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