]> git.mxchange.org Git - simgear.git/blob - simgear/io/raw_socket.cxx
Merge branch 'next' of gitorious.org:fg/simgear into next
[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 #include "raw_socket.hxx"
29
30 #if defined(_WIN32) && !defined(__CYGWIN__)
31 # define WINSOCK // use winsock convetions, otherwise standard POSIX
32 #endif
33
34 #include <cstdlib>
35 #include <ctime>
36 #include <cstring>
37 #include <cassert>
38 #include <cstdio> // for snprintf
39 #include <errno.h>
40
41 #if defined(WINSOCK)
42 #  include <winsock2.h>
43 #  include <ws2tcpip.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 <map>
61
62 #include <simgear/debug/logstream.hxx>
63 #include <simgear/structure/exception.hxx>
64 #include <simgear/threads/SGThread.hxx>
65
66 namespace {
67
68 class Resolver : public SGThread
69 {
70 public:
71     static Resolver* instance()
72     {
73         if (!static_instance) {
74             static_instance = new Resolver;
75             atexit(&Resolver::cleanup);
76             static_instance->start();
77         }
78
79         return static_instance;
80     }
81
82     static void cleanup()
83     {
84         static_instance->shutdown();
85         static_instance->join();
86     }
87
88     Resolver() :
89         _done(false)
90     {
91     }
92
93     void shutdown()
94     {
95         _lock.lock();
96         _done = true;
97         _wait.signal();
98         _lock.unlock();
99     }
100
101     simgear::IPAddress* lookup(const string& host)
102     {
103         simgear::IPAddress* result = NULL;
104         _lock.lock();
105         AddressCache::iterator it = _cache.find(host);
106         if (it == _cache.end()) {
107             _cache[host] = NULL; // mark as needing looked up
108             _wait.signal(); // if the thread was sleeping, poke it
109         } else {
110             result = it->second;
111         }
112         _lock.unlock();
113         return result;
114     }
115
116     simgear::IPAddress* lookupSync(const string& host)
117     {
118         simgear::IPAddress* result = NULL;
119         _lock.lock();
120         AddressCache::iterator it = _cache.find(host);
121         if (it == _cache.end()) {
122             _lock.unlock();
123             result = new simgear::IPAddress;
124             bool ok = lookupHost(host.c_str(), *result);
125             _lock.lock();
126             if (ok) {
127                 _cache[host] = result; // mark as needing looked up
128             } else {
129                 delete result;
130                 result = NULL;
131             }
132         } else { // found in cache, easy
133             result = it->second;
134         }
135         _lock.unlock();
136         return result;
137     }
138 protected:
139     /**
140      * run method waits on a condition (_wait), and when awoken,
141      * finds any unresolved entries in _cache, resolves them, and goes
142      * back to sleep.
143      */
144     virtual void run()
145     {
146         _lock.lock();
147         while (!_done) {
148             AddressCache::iterator it;
149
150             for (it = _cache.begin(); it != _cache.end(); ++it) {
151                 if (it->second == NULL) {
152                     string h = it->first;
153
154                     _lock.unlock();
155                     simgear::IPAddress* addr = new simgear::IPAddress;
156                 // may take seconds or even minutes!
157                     lookupHost(h.c_str(), *addr);
158                     _lock.lock();
159
160                 // cahce may have changed while we had the lock released -
161                 // so iterators may be invalid: restart the traversal
162                     it = _cache.begin();
163                     _cache[h] = addr;
164                 } // of found un-resolved entry
165             } // of un-resolved address iteration
166             _wait.wait(_lock);
167         } // of thread run loop
168         _lock.unlock();
169     }
170 private:
171     static Resolver* static_instance;
172
173     /**
174      * The actual synchronous, blocking host lookup function
175      * do *not* call this with any locks (mutexs) held, since depending
176      * on local system configuration / network availability, it
177      * may block for seconds or minutes.
178      */
179     bool lookupHost(const char* host, simgear::IPAddress& addr)
180     {
181       struct addrinfo hints;
182       memset(&hints, 0, sizeof(struct addrinfo));
183       hints.ai_family = AF_INET;
184       bool ok = false;
185
186       struct addrinfo* result0 = NULL;
187       int err = getaddrinfo(host, NULL, &hints, &result0);
188       if (err) {
189         SG_LOG(SG_IO, SG_WARN, "getaddrinfo failed for '" << host << "' : " << gai_strerror(err));
190         return false;
191       } else {
192           struct addrinfo* result;
193           for (result = result0; result != NULL; result = result->ai_next) {
194               if (result->ai_family != AF_INET) { // only accept IP4 for the moment
195                   continue;
196               }
197
198               if (result->ai_addrlen != addr.getAddrLen()) {
199                   SG_LOG(SG_IO, SG_ALERT, "mismatch in socket address sizes: got " <<
200                       result->ai_addrlen << ", expected " << addr.getAddrLen());
201                   continue;
202               }
203
204               memcpy(addr.getAddr(), result->ai_addr, result->ai_addrlen);
205               ok = true;
206               break;
207           } // of getaddrinfo results iteration
208       } // of getaddrinfo succeeded
209
210       freeaddrinfo(result0);
211       return ok;
212     }
213
214     SGMutex _lock;
215     SGWaitCondition _wait;
216
217     typedef std::map<string, simgear::IPAddress*> AddressCache;
218     AddressCache _cache;
219     bool _done;
220 };
221
222 Resolver* Resolver::static_instance = NULL;
223
224 } // of anonymous namespace
225
226 namespace simgear
227 {
228
229 IPAddress::IPAddress ( const char* host, int port )
230 {
231   set ( host, port ) ;
232 }
233
234 IPAddress::IPAddress( const IPAddress& other ) :
235   addr(NULL)
236 {
237   if (other.addr) {
238     addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
239     memcpy(addr, other.addr, sizeof(struct sockaddr_in));
240   }
241 }
242
243 const IPAddress& IPAddress::operator=(const IPAddress& other)
244 {
245   if (addr) {
246     free(addr);
247     addr = NULL;
248   }
249
250   if (other.addr) {
251     addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
252     memcpy(addr, other.addr, sizeof(struct sockaddr_in));
253   }
254
255   return *this;
256 }
257
258 void IPAddress::set ( const char* host, int port )
259 {
260   addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
261   memset(addr, 0, sizeof(struct sockaddr_in));
262
263   addr->sin_family = AF_INET ;
264   addr->sin_port = htons (port);
265
266   /* Convert a string specifying a host name or one of a few symbolic
267   ** names to a numeric IP address.  This usually calls getaddrinfo()
268   ** to do the work; the names "" and "<broadcast>" are special.
269   */
270
271   if (!host || host[0] == '\0') {
272     addr->sin_addr.s_addr = INADDR_ANY;
273     return;
274   }
275
276   if (strcmp(host, "<broadcast>") == 0) {
277     addr->sin_addr.s_addr = INADDR_BROADCAST;
278     return;
279   }
280
281 // check the cache
282   IPAddress* cached = Resolver::instance()->lookupSync(host);
283   if (cached) {
284       memcpy(addr, cached->getAddr(), cached->getAddrLen());
285   }
286
287   addr->sin_port = htons (port); // fix up port after getaddrinfo
288 }
289
290 IPAddress::~IPAddress()
291 {
292   if (addr) {
293     free (addr);
294   }
295 }
296
297 bool IPAddress::lookupNonblocking(const char* host, IPAddress& addr)
298 {
299     IPAddress* cached = Resolver::instance()->lookup(host);
300     if (!cached) {
301         return false;
302     }
303
304     addr = *cached;
305     return true;
306 }
307
308 /* Create a string object representing an IP address.
309    This is always a string of the form 'dd.dd.dd.dd' (with variable
310    size numbers). */
311
312 const char* IPAddress::getHost () const
313 {
314   static char buf [32];
315         long x = ntohl(addr->sin_addr.s_addr);
316         sprintf(buf, "%d.%d.%d.%d",
317                 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
318                 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff );
319   return buf;
320 }
321
322 unsigned int IPAddress::getIP () const
323 {
324         return addr->sin_addr.s_addr;
325 }
326
327 unsigned int IPAddress::getPort() const
328 {
329   return ntohs(addr->sin_port);
330 }
331
332 void IPAddress::setPort(int port)
333 {
334     addr->sin_port = htons(port);
335 }
336
337 unsigned int IPAddress::getFamily () const
338 {
339         return addr->sin_family;
340 }
341
342 const char* IPAddress::getLocalHost ()
343 {
344   //gethostbyname(gethostname())
345
346   char buf[256];
347   memset(buf, 0, sizeof(buf));
348   gethostname(buf, sizeof(buf)-1);
349   const hostent *hp = gethostbyname(buf);
350
351   if (hp && *hp->h_addr_list)
352   {
353     in_addr     addr = *((in_addr*)*hp->h_addr_list);
354     const char* host = inet_ntoa(addr);
355
356     if ( host )
357       return host ;
358   }
359
360   return "127.0.0.1" ;
361 }
362
363
364 bool IPAddress::getBroadcast () const
365 {
366   return (addr->sin_addr.s_addr == INADDR_BROADCAST);
367 }
368
369 unsigned int IPAddress::getAddrLen() const
370 {
371     return sizeof(struct sockaddr_in);
372 }
373
374 struct sockaddr* IPAddress::getAddr() const
375 {
376     if (addr == NULL) {
377         addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
378         memset(addr, 0, sizeof(struct sockaddr_in));
379     }
380
381     return (struct sockaddr*) addr;
382 }
383
384 Socket::Socket ()
385 {
386   handle = -1 ;
387 }
388
389
390 Socket::~Socket ()
391 {
392   close () ;
393 }
394
395
396 void Socket::setHandle (int _handle)
397 {
398   close () ;
399   handle = _handle ;
400 }
401
402
403 bool Socket::open ( bool stream )
404 {
405   close () ;
406   handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ;
407
408   // Jan 26, 2010: Patch to avoid the problem of the socket resource not
409   // yet being available if the program is restarted quickly after being
410   // killed.
411   //
412   // Reference: http://www.unixguide.net/network/socketfaq/4.5.shtml
413   // --
414   // Also required for joining multicast domains
415   if ( stream ) {
416     int opt_boolean = 1;
417 #if defined(_WIN32) || defined(__CYGWIN__)
418     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, (char *)&opt_boolean,
419                 sizeof(opt_boolean) );
420 #else
421     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, &opt_boolean,
422                 sizeof(opt_boolean) );
423 #endif
424   }
425
426   return (handle != -1);
427 }
428
429
430 void Socket::setBlocking ( bool blocking )
431 {
432   assert ( handle != -1 ) ;
433
434 #if defined(WINSOCK)
435     u_long nblocking = blocking? 0: 1;
436   ::ioctlsocket(handle, FIONBIO, &nblocking);
437 #else
438
439   int delay_flag = ::fcntl (handle, F_GETFL, 0);
440
441   if (blocking)
442     delay_flag &= (~O_NDELAY);
443   else
444     delay_flag |= O_NDELAY;
445
446   ::fcntl (handle, F_SETFL, delay_flag);
447 #endif
448 }
449
450
451 void Socket::setBroadcast ( bool broadcast )
452 {
453   assert ( handle != -1 ) ;
454   int result;
455   if ( broadcast ) {
456       int one = 1;
457 #if defined(_WIN32) || defined(__CYGWIN__)
458       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
459 #else
460       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
461 #endif
462   } else {
463       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
464   }
465
466   if ( result < 0 ) {
467       throw sg_exception("Socket::setBroadcast failed");
468   }
469 }
470
471
472 int Socket::bind ( const char* host, int port )
473 {
474   int result;
475   assert ( handle != -1 ) ;
476   IPAddress addr ( host, port ) ;
477
478 #if !defined(WINSOCK)
479   if( (result = ::bind(handle, addr.getAddr(), addr.getAddrLen() ) ) < 0 ) {
480     SG_LOG(SG_IO, SG_ALERT, "bind(" << addr.getHost() << ":" << addr.getPort() << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
481     return result;
482   }
483 #endif
484
485   // 224.0.0.0 - 239.255.255.255 are multicast
486   // Usage of 239.x.x.x is recommended for local scope
487   // Reference: http://tools.ietf.org/html/rfc5771
488   if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) {
489
490 #if defined(WINSOCK)
491     struct sockaddr_in a;
492     a.sin_addr.S_un.S_addr = INADDR_ANY;
493     a.sin_family = AF_INET;
494     a.sin_port = htons(port);
495
496     if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) {
497       SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
498       return result;
499     }
500 #endif
501
502     struct ip_mreq mreq;
503     mreq.imr_multiaddr.s_addr = addr.getIP();
504     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
505     if( (result=::setsockopt(getHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq))) != 0 ) {
506       SG_LOG(SG_IO, SG_ALERT, "setsockopt(IP_ADD_MEMBERSHIP) failed. Errno " << errno << " (" << strerror(errno) << ")");
507       return result;
508     }
509   }
510 #if defined(WINSOCK)
511   else if( (result = ::bind(handle,addr.getAddr(), addr.getAddrLen())) < 0 ) {
512     SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
513     return result;
514   }
515 #endif
516
517   return 0;
518 }
519
520
521 int Socket::listen ( int backlog )
522 {
523   assert ( handle != -1 ) ;
524   return ::listen(handle,backlog);
525 }
526
527
528 int Socket::accept ( IPAddress* addr )
529 {
530   assert ( handle != -1 ) ;
531
532   if ( addr == NULL )
533   {
534     return ::accept(handle,NULL,NULL);
535   }
536   else
537   {
538     socklen_t addr_len = addr->getAddrLen(); ;
539     return ::accept(handle, addr->getAddr(), &addr_len);
540   }
541 }
542
543
544 int Socket::connect ( const char* host, int port )
545 {
546   IPAddress addr ( host, port ) ;
547   return connect ( &addr );
548 }
549
550
551 int Socket::connect ( IPAddress* addr )
552 {
553   assert ( handle != -1 ) ;
554   if ( addr->getBroadcast() ) {
555       setBroadcast( true );
556   }
557   return ::connect(handle, addr->getAddr(), addr->getAddrLen() );
558 }
559
560
561 int Socket::send (const void * buffer, int size, int flags)
562 {
563   assert ( handle != -1 ) ;
564   return ::send (handle, (const char*)buffer, size, flags);
565 }
566
567
568 int Socket::sendto ( const void * buffer, int size,
569                         int flags, const IPAddress* to )
570 {
571   assert ( handle != -1 ) ;
572   return ::sendto(handle,(const char*)buffer,size,flags,
573                          (const sockaddr*) to->getAddr(), to->getAddrLen());
574 }
575
576
577 int Socket::recv (void * buffer, int size, int flags)
578 {
579   assert ( handle != -1 ) ;
580   return ::recv (handle, (char*)buffer, size, flags);
581 }
582
583
584 int Socket::recvfrom ( void * buffer, int size,
585                           int flags, IPAddress* from )
586 {
587   assert ( handle != -1 ) ;
588   socklen_t fromlen = (socklen_t) from->getAddrLen() ;
589   return ::recvfrom(handle,(char*)buffer,size,flags, from->getAddr(),&fromlen);
590 }
591
592
593 void Socket::close (void)
594 {
595   if ( handle != -1 )
596   {
597 #if defined(WINSOCK)
598     ::closesocket( handle );
599 #else
600     ::close( handle );
601 #endif
602     handle = -1 ;
603   }
604 }
605
606
607 bool Socket::isNonBlockingError ()
608 {
609 #if defined(WINSOCK)
610   int wsa_errno = WSAGetLastError();
611   if ( wsa_errno != 0 )
612   {
613     WSASetLastError(0);
614         SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno);
615     switch (wsa_errno) {
616     case WSAEWOULDBLOCK: // always == NET_EAGAIN?
617     case WSAEALREADY:
618     case WSAEINPROGRESS:
619       return true;
620     }
621   }
622   return false;
623 #else
624   switch (errno) {
625   case EWOULDBLOCK: // always == NET_EAGAIN?
626   case EALREADY:
627   case EINPROGRESS:
628     return true;
629   }
630   return false;
631
632 #endif
633 }
634
635
636 //////////////////////////////////////////////////////////////////////
637 //
638 //      modified version by os
639 //
640 //////////////////////////////////////////////////////////////////////
641 int Socket::select ( Socket** reads, Socket** writes, int timeout )
642 {
643   fd_set r,w;
644   int   retval;
645
646   FD_ZERO (&r);
647   FD_ZERO (&w);
648
649   int i, k ;
650   int num = 0 ;
651
652   if ( reads )
653   {
654     for ( i=0; reads[i]; i++ )
655     {
656       int fd = reads[i]->getHandle();
657       FD_SET (fd, &r);
658       num++;
659     }
660   }
661
662   if ( writes )
663   {
664     for ( i=0; writes[i]; i++ )
665     {
666       int fd = writes[i]->getHandle();
667       FD_SET (fd, &w);
668       num++;
669     }
670   }
671
672   if (!num)
673     return num ;
674
675   /* Set up the timeout */
676   struct timeval tv ;
677   tv.tv_sec = timeout/1000;
678   tv.tv_usec = (timeout%1000)*1000;
679
680   // It bothers me that select()'s first argument does not appear to
681   // work as advertised... [it hangs like this if called with
682   // anything less than FD_SETSIZE, which seems wasteful?]
683
684   // Note: we ignore the 'exception' fd_set - I have never had a
685   // need to use it.  The name is somewhat misleading - the only
686   // thing I have ever seen it used for is to detect urgent data -
687   // which is an unportable feature anyway.
688
689   retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
690
691   //remove sockets that had no activity
692
693   num = 0 ;
694
695   if ( reads )
696   {
697     for ( k=i=0; reads[i]; i++ )
698     {
699       int fd = reads[i]->getHandle();
700       if ( FD_ISSET (fd, &r) )
701       {
702         reads[k++] = reads[i];
703         num++;
704       }
705     }
706     reads[k] = NULL ;
707   }
708
709   if ( writes )
710   {
711     for ( k=i=0; writes[i]; i++ )
712     {
713       int fd = writes[i]->getHandle();
714       if ( FD_ISSET (fd, &w) )
715       {
716         writes[k++] = writes[i];
717         num++;
718       }
719     }
720     writes[k] = NULL ;
721   }
722
723   if (retval == 0) // timeout
724     return (-2);
725   if (retval == -1)// error
726     return (-1);
727
728   return num ;
729 }
730
731
732 /* Init/Exit functions */
733
734 static void netExit ( void )
735 {
736 #if defined(WINSOCK)
737         /* Clean up windows networking */
738         if ( WSACleanup() == SOCKET_ERROR ) {
739                 if ( WSAGetLastError() == WSAEINPROGRESS ) {
740                         WSACancelBlockingCall();
741                         WSACleanup();
742                 }
743         }
744 #endif
745 }
746
747 int Socket::initSockets()
748 {
749 #if defined(WINSOCK)
750         /* Start up the windows networking */
751         WORD version_wanted = MAKEWORD(1,1);
752         WSADATA wsaData;
753
754         if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
755                 throw sg_exception("WinSock initialization failed");
756         }
757 #endif
758
759   atexit( netExit ) ;
760         return(0);
761 }
762
763
764 } // of namespace simgear
765