-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket_listener.cpp
executable file
·249 lines (196 loc) · 5.49 KB
/
socket_listener.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// OS-dependent header files for socket I/O.
#ifdef unix
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>
#include <netdb.h>
#else
#include <io.h>
#include <winsock2.h>
#endif
#include "globals.h"
#include "socket_listener.h"
#include "socket_connection.h"
#include "utility.h"
// STL includes
#include <iostream>
#include <sstream>
#include <string>
#include "connection.h"
using namespace std;
/*
_____ __ __ ____
/ ___/___ ___ ___ / /_ ____ __ __ ____ / /_ ___ ____ / __/___
/ /__ / _ \ / _ \ (_-</ __// __// // // __// __// _ \ / __/ > _/_ _/
\___/ \___//_//_//___/\__//_/ \_,_/ \__/ \__/ \___//_/ |_____/
___ __ __
/ _ \ ___ ___ / /_ ____ __ __ ____ / /_ ___ ____
/ // // -_)(_-</ __// __// // // __// __// _ \ / __/
/____/ \__//___/\__//_/ \_,_/ \__/ \__/ \___//_/
*/
SocketListener::SocketListener( SocketManager * manager )
{
Error = esleNone;
Ready = false;
Port = 0;
FileDescriptor = 0;
Manager = manager;
}
SocketListener::~SocketListener()
{
Disconnect();
printf("Deleting listener socket.\n");
}
/*
___ __ _
/ _ \ ___ / / __ __ ___ _ ___ _ (_)___ ___ _
/ // // -_)/ _ \/ // // _ `// _ `// // _ \/ _ `/
/____/ \__//_.__/\_,_/ \_, / \_, //_//_//_/\_, /
/___/ /___/ /___/
*/
eSocketListenerErrors SocketListener::GetLastError()
{
return Error;
}
bool SocketListener::InInSet()
{
if (!Ready)
{
Error = esleNotReady;
return false;
}
char buf[MAX_STRING_LENGTH];
struct sockaddr_in sock;
struct hostent * from;
int desc;
#ifdef unix
socklen_t size;
#else
int size;
#endif
size = sizeof(sock);
if ( ( desc = accept( FileDescriptor, (struct sockaddr *) &sock, &size) ) < 0 )
{
/* According to the Linux manpage for accept:
* ERROR HANDLING
* Linux accept passes already-pending network errors on the new socket as
* an error code from accept. This behaviour differs from other BSD
* socket implementations. For reliable operation the application should
* detect the network errors defined for the protocol after accept and
* treat them like EAGAIN by retrying. In case of TCP/IP these are ENET-
* DOWN, EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP,
* and ENETUNREACH.
*****************************
* So, it seems wise to me to do like what SMAUG did and just say "whatever",
* and if there's an error just ignore it.
*/
return true;
/* Old error handling code...
// Error...
Error = esleCouldntAccept;
return false;
*/
}
SocketConnection * newConnection = new NEW_SOCKET_CONNECTION_TYPE(desc);
newConnection->SetPort(ntohs(sock.sin_port));
strcpy( buf, inet_ntoa( sock.sin_addr ) );
//printf("Incoming connection from %s.\n\n", buf);
newConnection->SetAddress(buf);
from = gethostbyaddr( (char *) &sock.sin_addr, sizeof(sock.sin_addr), AF_INET );
newConnection->SetHost( (from ? from->h_name : buf) );
newConnection->SetInputReceiver(Manager);
Manager->toAdd.push_back( newConnection->GetId() );
return true;
}
bool SocketListener::StartListening(int port)
{
Port = port;
char hostname[64];
struct sockaddr_in sa;
struct hostent * hp;
struct servent * sp;
gethostname(hostname, sizeof(hostname));
if ( ( FileDescriptor = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
Error = esleCreateSocket;
return false;
}
int value = 1;
if ( setsockopt( FileDescriptor, SOL_SOCKET, SO_REUSEADDR,
(char *) &value, sizeof(value) ) < 0 )
{
Error = esleSocketOptions;
close( FileDescriptor );
return false;
}
#if defined(SO_DONTLINGER) && !defined(SYSV)
{
struct linger ld;
ld.l_onoff = 1;
ld.l_linger = 1000;
if ( setsockopt( FileDescriptor, SOL_SOCKET, SO_DONTLINGER,
(char *) &ld, sizeof(ld) ) < 0 )
{
perror( "Init_socket: SO_DONTLINGER" );
close( FileDescriptor );
exit( 1 );
}
}
#endif
hp = gethostbyname( hostname );
sp = getservbyname( "service", "mud" );
memset(&sa, '\0', sizeof(sa));
sa.sin_family = AF_INET; /* hp->h_addrtype; */
sa.sin_port = htons( port );
/* sa.sin_addr.s_addr = inet_addr("205.243.76.36"); */
if ( bind( FileDescriptor, (struct sockaddr *) &sa, sizeof(sa) ) == -1 )
{
Error = esleCouldntBind;
close( FileDescriptor );
return false;
}
if ( listen( FileDescriptor, 50 ) < 0 )
{
Error = esleCouldntListen;
close( FileDescriptor );
FileDescriptor = -1;
return false;
}
Ready = true;
return true;
}
////////////////////////
// Code object interface
////////////////////////
const string SocketListener::codeGetClassName() const
{
return "SocketListener";
}
const string SocketListener::codeGetBasicInfo() const
{
// for copying results into
ostringstream os;
os << "Desc #" << this->GetDescriptor() << ", port #" << this->GetPort() << ".";
return os.str();
}
const string SocketListener::codeGetFullInfo() const
{
// for copying results into
ostringstream os;
os << "Listener socket:" << endl;
if (!Ready)
{
os << "Socket not yet ready." << endl;
return os.str();
}
os << "Listening on port " << this->GetPort() <<
", descriptor #" << this->GetDescriptor() << "." << endl;
return os.str();
}