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