]> git.mxchange.org Git - simgear.git/blob - simgear/io/raw_socket.cxx
Ick, further fixes for Linux/MSVC
[simgear.git] / simgear / io / raw_socket.cxx
1 /*
2      simgear::Socket, adapted from PLIB Socket by James Turner
3      Copyright (C) 2010  James Turner
4      
5      PLIB - A Suite of Portable Game Libraries
6      Copyright (C) 1998,2002  Steve Baker
7  
8      This library is free software; you can redistribute it and/or
9      modify it under the terms of the GNU Library General Public
10      License as published by the Free Software Foundation; either
11      version 2 of the License, or (at your option) any later version.
12  
13      This library is distributed in the hope that it will be useful,
14      but WITHOUT ANY WARRANTY; without even the implied warranty of
15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16      Library General Public License for more details.
17  
18      You should have received a copy of the GNU Library General Public
19      License along with this library; if not, write to the Free Software
20      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include <simgear/compiler.h>
28
29 #include "sg_socket.hxx"
30
31 #if defined(_WIN32) && !defined(__CYGWIN__)
32 # define WINSOCK // use winsock convetions, otherwise standard POSIX
33 #endif
34
35 #include <cstdlib>
36 #include <ctime>
37 #include <cstring>
38 #include <cassert>
39 #include <cstdio> // for snprintf
40 #include <iostream>
41
42 #if defined(WINSOCK)
43 #  include <winsock.h>
44 #  include <stdarg.h>
45 #else
46 #  include <sys/types.h>
47 #  include <sys/socket.h>
48 #  include <netinet/in.h>
49 #  include <arpa/inet.h>
50 #  include <sys/time.h>  
51 #  include <unistd.h>
52 #  include <netdb.h>
53 #  include <fcntl.h>
54 #endif
55
56 #if defined(_MSC_VER) && !defined(socklen_t)
57 #define socklen_t int
58 #endif
59
60 #include <simgear/debug/logstream.hxx>
61 #include <simgear/structure/exception.hxx>
62
63 namespace simgear
64 {
65                                                                                        
66 IPAddress::IPAddress ( const char* host, int port )
67 {
68   set ( host, port ) ;
69 }
70
71 IPAddress::IPAddress ( struct sockaddr* addr, size_t len )
72 {
73     memset(&_raw, 0, sizeof(struct sockaddr_in));
74     if ((addr->sa_family != AF_INET) ||
75         (len != sizeof(struct sockaddr_in))) 
76     {
77         std::cout << "address size mismatch" << std::endl;
78         return;
79     }
80     
81     memcpy(&_raw, addr, len);
82 }
83
84 void IPAddress::setPort(unsigned int port)
85 {
86     _raw.sin_port = htons(port);
87 }
88
89 void IPAddress::set ( const char* host, int port )
90 {
91   memset(&_raw, 0, sizeof(struct sockaddr_in));
92
93   _raw.sin_family = AF_INET ;
94   _raw.sin_port = htons (port);
95
96   /* Convert a string specifying a host name or one of a few symbolic
97   ** names to a numeric IP address.  This usually calls gethostbyname()
98   ** to do the work; the names "" and "<broadcast>" are special.
99   */
100
101   if (!host || host[0] == '\0') {
102     _raw.sin_addr.s_addr = INADDR_ANY;
103     return;
104   }
105   
106   if (strcmp(host, "<broadcast>") == 0) {
107     _raw.sin_addr.s_addr = INADDR_BROADCAST;
108     return;
109   }
110   
111   _raw.sin_addr.s_addr = inet_addr ( host ) ;
112   if (_raw.sin_addr.s_addr != INADDR_NONE) {
113     return;
114   }
115 // finally, try gethostbyname
116     struct hostent *hp = gethostbyname ( host ) ;
117     if (!hp) {
118       SG_LOG(SG_IO, SG_WARN, "gethostbyname failed for " << host);
119       _raw.sin_addr.s_addr = INADDR_ANY ;
120       return;
121     }
122     
123     memcpy ( (char *) &_raw.sin_addr, hp->h_addr, hp->h_length ) ;
124 }
125
126
127 /* Create a string object representing an IP address.
128    This is always a string of the form 'dd.dd.dd.dd' (with variable
129    size numbers). */
130
131 const char* IPAddress::getHost () const
132 {
133 #if 0
134   const char* buf = inet_ntoa ( sin_addr ) ;
135 #else
136   static char buf [32];
137         long x = ntohl(_raw.sin_addr.s_addr);
138         sprintf(buf, "%d.%d.%d.%d",
139                 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
140                 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff );
141 #endif
142   return buf;
143 }
144
145 unsigned int IPAddress::getIP () const 
146
147         return _raw.sin_addr.s_addr; 
148 }
149
150 unsigned int IPAddress::getPort() const
151 {
152   return ntohs(_raw.sin_port);
153 }
154
155 unsigned int IPAddress::getFamily () const 
156
157         return _raw.sin_family; 
158 }
159
160 const char* IPAddress::getLocalHost ()
161 {
162   //gethostbyname(gethostname())
163
164   char buf[256];
165   memset(buf, 0, sizeof(buf));
166   gethostname(buf, sizeof(buf)-1);
167   const hostent *hp = gethostbyname(buf);
168
169   if (hp && *hp->h_addr_list)
170   {
171     in_addr     addr = *((in_addr*)*hp->h_addr_list);
172     const char* host = inet_ntoa(addr);
173
174     if ( host )
175       return host ;
176   }
177
178   return "127.0.0.1" ;
179 }
180
181
182 bool IPAddress::getBroadcast () const
183 {
184   return (_raw.sin_addr.s_addr == INADDR_BROADCAST);
185 }
186
187
188 Socket::Socket ()
189 {
190   handle = -1 ;
191 }
192
193
194 Socket::~Socket ()
195 {
196   close () ;
197 }
198
199
200 void Socket::setHandle (int _handle)
201 {
202   close () ;
203   handle = _handle ;
204 }
205
206
207 bool Socket::open ( bool stream )
208 {
209   close () ;
210   handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ;
211
212   // Jan 26, 2010: Patch to avoid the problem of the socket resource not
213   // yet being available if the program is restarted quickly after being
214   // killed.
215   //
216   // Reference: http://www.unixguide.net/network/socketfaq/4.5.shtml
217   // --
218   // Also required for joining multicast domains
219   if ( stream ) {
220     int opt_boolean = 1;
221 #if defined(_WIN32) || defined(__CYGWIN__)
222     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, (char *)&opt_boolean,
223                 sizeof(opt_boolean) );
224 #else
225     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, &opt_boolean,
226                 sizeof(opt_boolean) );
227 #endif
228   }
229
230   return (handle != -1);
231 }
232
233
234 void Socket::setBlocking ( bool blocking )
235 {
236   assert ( handle != -1 ) ;
237
238 #if defined(WINSOCK)
239     u_long nblocking = blocking? 0: 1;
240   ::ioctlsocket(handle, FIONBIO, &nblocking);
241 #else
242
243   int delay_flag = ::fcntl (handle, F_GETFL, 0);
244
245   if (blocking)
246     delay_flag &= (~O_NDELAY);
247   else
248     delay_flag |= O_NDELAY;
249
250   ::fcntl (handle, F_SETFL, delay_flag);
251 #endif
252 }
253
254
255 void Socket::setBroadcast ( bool broadcast )
256 {
257   assert ( handle != -1 ) ;
258   int result;
259   if ( broadcast ) {
260       int one = 1;
261 #if defined(_WIN32) || defined(__CYGWIN__)
262       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
263 #else
264       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
265 #endif
266   } else {
267       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
268   }
269   
270   if ( result < 0 ) {
271       throw sg_exception("Socket::setBroadcast failed");
272   }
273 }
274
275
276 int Socket::bind ( const char* host, int port )
277 {
278   int result;
279   assert ( handle != -1 ) ;
280   IPAddress addr ( host, port ) ;
281
282 #if !defined(WINSOCK)
283   if( (result = ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress))) < 0 ) {
284     SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
285     return result;
286   }
287 #endif
288
289   // 224.0.0.0 - 239.255.255.255 are multicast   
290   // Usage of 239.x.x.x is recommended for local scope
291   // Reference: http://tools.ietf.org/html/rfc5771
292   if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) {
293
294 #if defined(WINSOCK)
295     struct sockaddr_in a;
296     a.sin_addr.S_un.S_addr = INADDR_ANY;
297     a.sin_family = AF_INET;
298     a.sin_port = htons(port);
299       
300     if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) {
301       SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
302       return result;
303     }
304 #endif
305
306     struct ip_mreq mreq;
307     mreq.imr_multiaddr.s_addr = addr.getIP();
308     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
309     if( (result=::setsockopt(getHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq))) != 0 ) {
310       SG_LOG(SG_IO, SG_ALERT, "setsockopt(IP_ADD_MEMBERSHIP) failed. Errno " << errno << " (" << strerror(errno) << ")");
311       return result;
312     }
313   }
314 #if defined(WINSOCK)
315   else if( (result = ::bind(handle,(const sockaddr*)&addr,sizeof(IPAddress))) < 0 ) {
316     SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
317     return result;
318   }
319 #endif
320
321   return 0;
322 }
323
324
325 int Socket::listen ( int backlog )
326 {
327   assert ( handle != -1 ) ;
328   return ::listen(handle,backlog);
329 }
330
331
332 int Socket::accept ( IPAddress* addr )
333 {
334   assert ( handle != -1 ) ;
335
336   if ( addr == NULL )
337   {
338     return ::accept(handle,NULL,NULL);
339   }
340   else
341   {
342     socklen_t addr_len = addr->getAddressSize();
343     return ::accept(handle,(sockaddr*)addr->getAddress(),&addr_len);
344   }
345 }
346
347
348 int Socket::connect ( const char* host, int port )
349 {
350   assert ( handle != -1 ) ;
351   IPAddress addr ( host, port ) ;
352   if ( addr.getBroadcast() ) {
353       setBroadcast( true );
354   }
355   return ::connect(handle,(const sockaddr*) addr.getAddress(), addr.getAddressSize());
356 }
357
358 int Socket::connect ( const IPAddress& addr )
359 {
360   assert ( handle != -1 ) ;
361   if ( addr.getBroadcast() ) {
362       setBroadcast( true );
363   }
364   
365   return ::connect(handle,(const sockaddr*) addr.getAddress(), addr.getAddressSize());
366 }
367
368 int Socket::send (const void * buffer, int size, int flags)
369 {
370   assert ( handle != -1 ) ;
371   return ::send (handle, (const char*)buffer, size, flags);
372 }
373
374
375 int Socket::sendto ( const void * buffer, int size,
376                         int flags, const IPAddress* to )
377 {
378   assert ( handle != -1 ) ;
379   return ::sendto(handle,(const char*)buffer,size,flags,
380                          (const sockaddr*)to,sizeof(IPAddress));
381 }
382
383
384 int Socket::recv (void * buffer, int size, int flags)
385 {
386   assert ( handle != -1 ) ;
387   return ::recv (handle, (char*)buffer, size, flags);
388 }
389
390
391 int Socket::recvfrom ( void * buffer, int size,
392                           int flags, IPAddress* from )
393 {
394   assert ( handle != -1 ) ;
395   socklen_t fromlen = (socklen_t) sizeof(IPAddress) ;
396   return ::recvfrom(handle,(char*)buffer,size,flags,(sockaddr*)from,&fromlen);
397 }
398
399
400 void Socket::close (void)
401 {
402   if ( handle != -1 )
403   {
404 #if defined(WINSOCK)
405     ::closesocket( handle );
406 #else
407     ::close( handle );
408 #endif
409     handle = -1 ;
410   }
411 }
412
413
414 bool Socket::isNonBlockingError ()
415 {
416 #if defined(WINSOCK)
417   int wsa_errno = WSAGetLastError();
418   if ( wsa_errno != 0 )
419   {
420     WSASetLastError(0);
421         SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno);
422     switch (wsa_errno) {
423     case WSAEWOULDBLOCK: // always == NET_EAGAIN?
424     case WSAEALREADY:
425     case WSAEINPROGRESS:
426       return true;
427     }
428   }
429   return false;
430 #else
431   switch (errno) {
432   case EWOULDBLOCK: // always == NET_EAGAIN?
433   case EALREADY:
434   case EINPROGRESS:
435     return true;
436   }
437   return false;
438
439 #endif
440 }
441
442
443 //////////////////////////////////////////////////////////////////////
444 //
445 //      modified version by os
446 //
447 //////////////////////////////////////////////////////////////////////
448 int Socket::select ( Socket** reads, Socket** writes, int timeout )
449 {
450   fd_set r,w;
451   int   retval;
452   
453   FD_ZERO (&r);
454   FD_ZERO (&w);
455
456   int i, k ;
457   int num = 0 ;
458
459   if ( reads )
460   {
461     for ( i=0; reads[i]; i++ )
462     {
463       int fd = reads[i]->getHandle();
464       FD_SET (fd, &r);
465       num++;
466     }
467   }
468
469   if ( writes )
470   {
471     for ( i=0; writes[i]; i++ )
472     {
473       int fd = writes[i]->getHandle();
474       FD_SET (fd, &w);
475       num++;
476     }
477   }
478
479   if (!num)
480     return num ;
481
482   /* Set up the timeout */
483   struct timeval tv ;
484   tv.tv_sec = timeout/1000;
485   tv.tv_usec = (timeout%1000)*1000;
486
487   // It bothers me that select()'s first argument does not appear to
488   // work as advertised... [it hangs like this if called with
489   // anything less than FD_SETSIZE, which seems wasteful?]
490   
491   // Note: we ignore the 'exception' fd_set - I have never had a
492   // need to use it.  The name is somewhat misleading - the only
493   // thing I have ever seen it used for is to detect urgent data -
494   // which is an unportable feature anyway.
495
496   retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
497
498   //remove sockets that had no activity
499
500   num = 0 ;
501
502   if ( reads )
503   {
504     for ( k=i=0; reads[i]; i++ )
505     {
506       int fd = reads[i]->getHandle();
507       if ( FD_ISSET (fd, &r) )
508       {
509         reads[k++] = reads[i];
510         num++;
511       }
512     }
513     reads[k] = NULL ;
514   }
515
516   if ( writes )
517   {
518     for ( k=i=0; writes[i]; i++ )
519     {
520       int fd = writes[i]->getHandle();
521       if ( FD_ISSET (fd, &w) )
522       {
523         writes[k++] = writes[i];
524         num++;
525       }
526     }
527     writes[k] = NULL ;
528   }
529
530   if (retval == 0) // timeout
531     return (-2);
532   if (retval == -1)// error
533     return (-1);
534
535   return num ;
536 }
537
538
539 /* Init/Exit functions */
540
541 static void netExit ( void )
542 {
543 #if defined(WINSOCK)
544         /* Clean up windows networking */
545         if ( WSACleanup() == SOCKET_ERROR ) {
546                 if ( WSAGetLastError() == WSAEINPROGRESS ) {
547                         WSACancelBlockingCall();
548                         WSACleanup();
549                 }
550         }
551 #endif
552 }
553
554 int Socket::initSockets()
555 {
556   assert ( sizeof(sockaddr_in) == sizeof(IPAddress) ) ;
557
558 #if defined(WINSOCK)
559         /* Start up the windows networking */
560         WORD version_wanted = MAKEWORD(1,1);
561         WSADATA wsaData;
562
563         if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
564                 throw sg_exception("WinSock initialization failed");
565         }
566 #endif
567
568   atexit( netExit ) ;
569         return(0);
570 }
571
572
573 } // of namespace simgear
574