1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 Steve Baker
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 For further information visit http://plib.sourceforge.net
20
21 $Id: netSocket.cxx 2054 2005-11-16 15:20:57Z bram $
22 */
23
24 #include "netSocket.h"
25
26 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
27
28 #if defined(UL_MAC_OSX)
29 # include <netinet/in.h>
30 #endif
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <time.h>
37 #include <sys/time.h> /* Need both for Mandrake 8.0!! */
38 #include <unistd.h>
39 #include <netdb.h>
40 #include <fcntl.h>
41 #include <stddef.h>
42
43 #else
44
45 #include <winsock.h>
46 #include <stdarg.h>
47
48 #endif
49
50 #if defined(UL_MSVC) && !defined(socklen_t)
51 #define socklen_t int
52 #endif
53
54 /* Paul Wiltsey says we need this for Solaris 2.8 */
55
56 #ifndef INADDR_NONE
57 #define INADDR_NONE ((unsigned long)-1)
58 #endif
59
netAddress(const char * host,int port)60 netAddress::netAddress ( const char* host, int port )
61 {
62 set ( host, port ) ;
63 }
64
65
set(const char * host,int port)66 void netAddress::set ( const char* host, int port )
67 {
68 int dummy[(sizeof(netAddress) == sizeof(sockaddr_in))*2-1]; // Compile time assert
69 memset(this, 0, sizeof(netAddress));
70
71 sin_len = sizeof(netAddress);
72 sin_family = AF_INET ;
73 sin_port = htons (port);
74
75 /* Convert a string specifying a host name or one of a few symbolic
76 ** names to a numeric IP address. This usually calls gethostbyname()
77 ** to do the work; the names "" and "<broadcast>" are special.
78 */
79
80 if (host[0] == '\0')
81 sin_addr = INADDR_ANY;
82 else
83 if (host[0] == '<' && strcmp(host, "<broadcast>") == 0)
84 sin_addr = INADDR_BROADCAST;
85 else
86 {
87 sin_addr = inet_addr ( host ) ;
88
89 if ( sin_addr == INADDR_NONE )
90 {
91 struct hostent *hp = gethostbyname ( host ) ;
92
93 if ( hp != NULL )
94 memcpy ( (char *) &sin_addr, hp->h_addr, hp->h_length ) ;
95 else
96 {
97 perror ( "netAddress::set" ) ;
98 sin_addr = INADDR_ANY ;
99 }
100 }
101 }
102 }
103
104
105 /* Create a string object representing an IP address.
106 This is always a string of the form 'dd.dd.dd.dd' (with variable
107 size numbers). */
108
getHost() const109 const char* netAddress::getHost () const
110 {
111 #if 0
112 const char* buf = inet_ntoa ( sin_addr ) ;
113 #else
114 static char buf [32];
115 long x = ntohl(sin_addr);
116 sprintf(buf, "%d.%d.%d.%d",
117 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
118 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff );
119 #endif
120 return buf;
121 }
122
getIP() const123 unsigned int netAddress::getIP () const
124 {
125 return sin_addr;
126 }
127
getPort() const128 unsigned int netAddress::getPort() const
129 {
130 return ntohs(sin_port);
131 }
132
getFamily() const133 unsigned int netAddress::getFamily () const
134 {
135 return sin_family;
136 }
137
getLocalHost()138 const char* netAddress::getLocalHost ()
139 {
140 //gethostbyname(gethostname())
141
142 char buf[256];
143 memset(buf, 0, sizeof(buf));
144 gethostname(buf, sizeof(buf)-1);
145 const hostent *hp = gethostbyname(buf);
146
147 if (hp && *hp->h_addr_list)
148 {
149 in_addr addr = *((in_addr*)*hp->h_addr_list);
150 const char* host = inet_ntoa(addr);
151
152 if ( host )
153 return host ;
154 }
155
156 return "127.0.0.1" ;
157 }
158
159
getBroadcast() const160 bool netAddress::getBroadcast () const
161 {
162 return sin_addr == INADDR_BROADCAST;
163 }
164
165
netSocket()166 netSocket::netSocket ()
167 {
168 handle = -1 ;
169 }
170
171
~netSocket()172 netSocket::~netSocket ()
173 {
174 close () ;
175 }
176
177
setHandle(int _handle)178 void netSocket::setHandle (int _handle)
179 {
180 close () ;
181 handle = _handle ;
182 }
183
184
open(bool stream)185 bool netSocket::open ( bool stream )
186 {
187 close () ;
188 handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ;
189 return (handle != -1);
190 }
191
192
setBlocking(bool blocking)193 void netSocket::setBlocking ( bool blocking )
194 {
195 assert ( handle != -1 ) ;
196
197 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
198
199 int delay_flag = ::fcntl (handle, F_GETFL, 0);
200
201 if (blocking)
202 delay_flag &= (~O_NDELAY);
203 else
204 delay_flag |= O_NDELAY;
205
206 ::fcntl (handle, F_SETFL, delay_flag);
207
208 #else
209
210 u_long nblocking = blocking? 0: 1;
211 ::ioctlsocket(handle, FIONBIO, &nblocking);
212
213 #endif
214 }
215
216
setBroadcast(bool broadcast)217 void netSocket::setBroadcast ( bool broadcast )
218 {
219 assert ( handle != -1 ) ;
220 int result;
221 if ( broadcast ) {
222 int one = 1;
223 #ifdef UL_WIN32
224 result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
225 #else
226 result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
227 #endif
228 } else {
229 result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
230 }
231 if ( result < 0 ) {
232 perror("set broadcast:");
233 }
234 assert ( result != -1 );
235 }
236
237
bind(const char * host,int port)238 int netSocket::bind ( const char* host, int port )
239 {
240 assert ( handle != -1 ) ;
241 netAddress addr ( host, port ) ;
242 return ::bind(handle,(const sockaddr*)&addr,sizeof(netAddress));
243 }
244
245
listen(int backlog)246 int netSocket::listen ( int backlog )
247 {
248 assert ( handle != -1 ) ;
249 return ::listen(handle,backlog);
250 }
251
252
accept(netAddress * addr)253 int netSocket::accept ( netAddress* addr )
254 {
255 assert ( handle != -1 ) ;
256
257 if ( addr == NULL )
258 {
259 return ::accept(handle,NULL,NULL);
260 }
261 else
262 {
263 socklen_t addr_len = (socklen_t) sizeof(netAddress) ;
264 return ::accept(handle,(sockaddr*)addr,&addr_len);
265 }
266 }
267
268
connect(const char * host,int port)269 int netSocket::connect ( const char* host, int port )
270 {
271 assert ( handle != -1 ) ;
272 netAddress addr ( host, port ) ;
273 if ( addr.getBroadcast() ) {
274 setBroadcast( true );
275 }
276 return ::connect(handle,(const sockaddr*)&addr,sizeof(netAddress));
277 }
278
279
send(const void * buffer,int size,int flags)280 int netSocket::send (const void * buffer, int size, int flags)
281 {
282 assert ( handle != -1 ) ;
283 return ::send (handle, (const char*)buffer, size, flags);
284 }
285
286
sendto(const void * buffer,int size,int flags,const netAddress * to)287 int netSocket::sendto ( const void * buffer, int size,
288 int flags, const netAddress* to )
289 {
290 assert ( handle != -1 ) ;
291 return ::sendto(handle,(const char*)buffer,size,flags,
292 (const sockaddr*)to,sizeof(netAddress));
293 }
294
295
recv(void * buffer,int size,int flags)296 int netSocket::recv (void * buffer, int size, int flags)
297 {
298 assert ( handle != -1 ) ;
299 return ::recv (handle, (char*)buffer, size, flags);
300 }
301
302
recvfrom(void * buffer,int size,int flags,netAddress * from)303 int netSocket::recvfrom ( void * buffer, int size,
304 int flags, netAddress* from )
305 {
306 assert ( handle != -1 ) ;
307 socklen_t fromlen = (socklen_t) sizeof(netAddress) ;
308 return ::recvfrom(handle,(char*)buffer,size,flags,(sockaddr*)from,&fromlen);
309 }
310
311
close(void)312 void netSocket::close (void)
313 {
314 if ( handle != -1 )
315 {
316 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
317 ::close( handle );
318 #else
319 ::closesocket( handle );
320 #endif
321 handle = -1 ;
322 }
323 }
324
325
isNonBlockingError()326 bool netSocket::isNonBlockingError ()
327 {
328 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
329 switch (errno) {
330 case EWOULDBLOCK: // always == NET_EAGAIN?
331 case EALREADY:
332 case EINPROGRESS:
333 return true;
334 }
335 return false;
336 #else
337 int wsa_errno = WSAGetLastError();
338 if ( wsa_errno != 0 )
339 {
340 WSASetLastError(0);
341 ulSetError(UL_WARNING,"WSAGetLastError() => %d",wsa_errno);
342 switch (wsa_errno) {
343 case WSAEWOULDBLOCK: // always == NET_EAGAIN?
344 case WSAEALREADY:
345 case WSAEINPROGRESS:
346 return true;
347 }
348 }
349 return false;
350 #endif
351 }
352
353
354 //////////////////////////////////////////////////////////////////////
355 //
356 // modified version by os
357 //
358 //////////////////////////////////////////////////////////////////////
select(netSocket ** reads,netSocket ** writes,int timeout)359 int netSocket::select ( netSocket** reads, netSocket** writes, int timeout )
360 {
361 fd_set r,w;
362 int retval;
363
364 FD_ZERO (&r);
365 FD_ZERO (&w);
366
367 int i, k ;
368 int num = 0 ;
369
370 if ( reads )
371 {
372 for ( i=0; reads[i]; i++ )
373 {
374 int fd = reads[i]->getHandle();
375 FD_SET (fd, &r);
376 num++;
377 }
378 }
379
380 if ( writes )
381 {
382 for ( i=0; writes[i]; i++ )
383 {
384 int fd = writes[i]->getHandle();
385 FD_SET (fd, &w);
386 num++;
387 }
388 }
389
390 if (!num)
391 return num ;
392
393 /* Set up the timeout */
394 struct timeval tv ;
395 tv.tv_sec = timeout/1000;
396 tv.tv_usec = (timeout%1000)*1000;
397
398 // It bothers me that select()'s first argument does not appear to
399 // work as advertised... [it hangs like this if called with
400 // anything less than FD_SETSIZE, which seems wasteful?]
401
402 // Note: we ignore the 'exception' fd_set - I have never had a
403 // need to use it. The name is somewhat misleading - the only
404 // thing I have ever seen it used for is to detect urgent data -
405 // which is an unportable feature anyway.
406
407 retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
408
409 //remove sockets that had no activity
410
411 num = 0 ;
412
413 if ( reads )
414 {
415 for ( k=i=0; reads[i]; i++ )
416 {
417 int fd = reads[i]->getHandle();
418 if ( FD_ISSET (fd, &r) )
419 {
420 reads[k++] = reads[i];
421 num++;
422 }
423 }
424 reads[k] = NULL ;
425 }
426
427 if ( writes )
428 {
429 for ( k=i=0; writes[i]; i++ )
430 {
431 int fd = writes[i]->getHandle();
432 if ( FD_ISSET (fd, &w) )
433 {
434 writes[k++] = writes[i];
435 num++;
436 }
437 }
438 writes[k] = NULL ;
439 }
440
441 if (retval == 0) // timeout
442 return (-2);
443 if (retval == -1)// error
444 return (-1);
445
446 return num ;
447 }
448
449
450 /* Init/Exit functions */
451
netExit(void)452 static void netExit ( void )
453 {
454 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
455 #else
456 /* Clean up windows networking */
457 if ( WSACleanup() == SOCKET_ERROR ) {
458 if ( WSAGetLastError() == WSAEINPROGRESS ) {
459 WSACancelBlockingCall();
460 WSACleanup();
461 }
462 }
463 #endif
464 }
465
466
netInit(int * argc,char ** argv)467 int netInit ( int* argc, char** argv )
468 {
469 /* Legacy */
470
471 return netInit () ;
472 }
473
474
netInit()475 int netInit ()
476 {
477 assert ( sizeof(sockaddr_in) == sizeof(netAddress) ) ;
478
479 #if defined(UL_CYGWIN) || !defined (UL_WIN32)
480 #else
481 /* Start up the windows networking */
482 WORD version_wanted = MAKEWORD(1,1);
483 WSADATA wsaData;
484
485 if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
486 ulSetError(UL_WARNING,"Couldn't initialize Winsock 1.1");
487 return(-1);
488 }
489 #endif
490
491 atexit( netExit ) ;
492 return(0);
493 }
494
495
netFormat(const char * format,...)496 const char* netFormat ( const char* format, ... )
497 {
498 static char buffer[ 256 ];
499 va_list argptr;
500 va_start(argptr, format);
501 vsprintf( buffer, format, argptr );
502 va_end(argptr);
503 return( buffer );
504 }
505
506
507