]> git.mxchange.org Git - simgear.git/blob - simgear/io/raw_socket.cxx
Ganael Laplanche: fix include dependencies for FreeBSD support
[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     if (!addr) {
315         return NULL;
316     }
317     
318   static char buf [32];
319         long x = ntohl(addr->sin_addr.s_addr);
320         sprintf(buf, "%d.%d.%d.%d",
321                 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
322                 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff );
323   return buf;
324 }
325
326 unsigned int IPAddress::getIP () const
327 {
328     if (!addr) {
329         return 0;
330     }
331     
332         return addr->sin_addr.s_addr;
333 }
334
335 unsigned int IPAddress::getPort() const
336 {
337     if (!addr) {
338         return 0;
339     }
340     
341   return ntohs(addr->sin_port);
342 }
343
344 void IPAddress::setPort(int port)
345 {
346     if (!addr) {
347         return;
348     }
349     
350     addr->sin_port = htons(port);
351 }
352
353 unsigned int IPAddress::getFamily () const
354 {
355     if (!addr) {
356         return 0;
357     }
358     
359         return addr->sin_family;
360 }
361
362 const char* IPAddress::getLocalHost ()
363 {
364   //gethostbyname(gethostname())
365
366   char buf[256];
367   memset(buf, 0, sizeof(buf));
368   gethostname(buf, sizeof(buf)-1);
369   const hostent *hp = gethostbyname(buf);
370
371   if (hp && *hp->h_addr_list)
372   {
373     in_addr     addr = *((in_addr*)*hp->h_addr_list);
374     const char* host = inet_ntoa(addr);
375
376     if ( host )
377       return host ;
378   }
379
380   return "127.0.0.1" ;
381 }
382
383
384 bool IPAddress::getBroadcast () const
385 {
386     if (!addr) {
387         return false;
388     }
389     
390     return (addr->sin_addr.s_addr == INADDR_BROADCAST);
391 }
392
393 unsigned int IPAddress::getAddrLen() const
394 {
395     return sizeof(struct sockaddr_in);
396 }
397
398 struct sockaddr* IPAddress::getAddr() const
399 {
400     if (addr == NULL) {
401         addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in));
402         memset(addr, 0, sizeof(struct sockaddr_in));
403     }
404
405     return (struct sockaddr*) addr;
406 }
407
408 bool IPAddress::isValid() const
409 {
410     return (addr != NULL);
411 }
412
413 Socket::Socket ()
414 {
415   handle = -1 ;
416 }
417
418
419 Socket::~Socket ()
420 {
421   close () ;
422 }
423
424
425 void Socket::setHandle (int _handle)
426 {
427   close () ;
428   handle = _handle ;
429 }
430
431
432 bool Socket::open ( bool stream )
433 {
434   close () ;
435   handle = ::socket ( AF_INET, (stream? SOCK_STREAM: SOCK_DGRAM), 0 ) ;
436
437   // Jan 26, 2010: Patch to avoid the problem of the socket resource not
438   // yet being available if the program is restarted quickly after being
439   // killed.
440   //
441   // Reference: http://www.unixguide.net/network/socketfaq/4.5.shtml
442   // --
443   // Also required for joining multicast domains
444   if ( stream ) {
445     int opt_boolean = 1;
446 #if defined(_WIN32) || defined(__CYGWIN__)
447     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, (char *)&opt_boolean,
448                 sizeof(opt_boolean) );
449 #else
450     setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, &opt_boolean,
451                 sizeof(opt_boolean) );
452 #endif
453   }
454
455   return (handle != -1);
456 }
457
458
459 void Socket::setBlocking ( bool blocking )
460 {
461   assert ( handle != -1 ) ;
462
463 #if defined(WINSOCK)
464     u_long nblocking = blocking? 0: 1;
465   ::ioctlsocket(handle, FIONBIO, &nblocking);
466 #else
467
468   int delay_flag = ::fcntl (handle, F_GETFL, 0);
469
470   if (blocking)
471     delay_flag &= (~O_NDELAY);
472   else
473     delay_flag |= O_NDELAY;
474
475   ::fcntl (handle, F_SETFL, delay_flag);
476 #endif
477 }
478
479
480 void Socket::setBroadcast ( bool broadcast )
481 {
482   assert ( handle != -1 ) ;
483   int result;
484   if ( broadcast ) {
485       int one = 1;
486 #if defined(_WIN32) || defined(__CYGWIN__)
487       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
488 #else
489       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
490 #endif
491   } else {
492       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
493   }
494
495   if ( result < 0 ) {
496       throw sg_exception("Socket::setBroadcast failed");
497   }
498 }
499
500
501 int Socket::bind ( const char* host, int port )
502 {
503   int result;
504   assert ( handle != -1 ) ;
505   IPAddress addr ( host, port ) ;
506
507 #if !defined(WINSOCK)
508   if( (result = ::bind(handle, addr.getAddr(), addr.getAddrLen() ) ) < 0 ) {
509     SG_LOG(SG_IO, SG_ALERT, "bind(" << addr.getHost() << ":" << addr.getPort() << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
510     return result;
511   }
512 #endif
513
514   // 224.0.0.0 - 239.255.255.255 are multicast
515   // Usage of 239.x.x.x is recommended for local scope
516   // Reference: http://tools.ietf.org/html/rfc5771
517   if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) {
518
519 #if defined(WINSOCK)
520     struct sockaddr_in a;
521     a.sin_addr.S_un.S_addr = INADDR_ANY;
522     a.sin_family = AF_INET;
523     a.sin_port = htons(port);
524
525     if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) {
526       SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
527       return result;
528     }
529 #endif
530
531     struct ip_mreq mreq;
532     mreq.imr_multiaddr.s_addr = addr.getIP();
533     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
534     if( (result=::setsockopt(getHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq))) != 0 ) {
535       SG_LOG(SG_IO, SG_ALERT, "setsockopt(IP_ADD_MEMBERSHIP) failed. Errno " << errno << " (" << strerror(errno) << ")");
536       return result;
537     }
538   }
539 #if defined(WINSOCK)
540   else if( (result = ::bind(handle,addr.getAddr(), addr.getAddrLen())) < 0 ) {
541     SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
542     return result;
543   }
544 #endif
545
546   return 0;
547 }
548
549
550 int Socket::listen ( int backlog )
551 {
552   assert ( handle != -1 ) ;
553   return ::listen(handle,backlog);
554 }
555
556
557 int Socket::accept ( IPAddress* addr )
558 {
559   assert ( handle != -1 ) ;
560
561   if ( addr == NULL )
562   {
563     return ::accept(handle,NULL,NULL);
564   }
565   else
566   {
567     socklen_t addr_len = addr->getAddrLen(); ;
568     return ::accept(handle, addr->getAddr(), &addr_len);
569   }
570 }
571
572
573 int Socket::connect ( const char* host, int port )
574 {
575   IPAddress addr ( host, port ) ;
576   return connect ( &addr );
577 }
578
579
580 int Socket::connect ( IPAddress* addr )
581 {
582   assert ( handle != -1 ) ;
583   if ( addr->getBroadcast() ) {
584       setBroadcast( true );
585   }
586   return ::connect(handle, addr->getAddr(), addr->getAddrLen() );
587 }
588
589
590 int Socket::send (const void * buffer, int size, int flags)
591 {
592   assert ( handle != -1 ) ;
593   return ::send (handle, (const char*)buffer, size, flags);
594 }
595
596
597 int Socket::sendto ( const void * buffer, int size,
598                         int flags, const IPAddress* to )
599 {
600   assert ( handle != -1 ) ;
601   return ::sendto(handle,(const char*)buffer,size,flags,
602                          (const sockaddr*) to->getAddr(), to->getAddrLen());
603 }
604
605
606 int Socket::recv (void * buffer, int size, int flags)
607 {
608   assert ( handle != -1 ) ;
609   return ::recv (handle, (char*)buffer, size, flags);
610 }
611
612
613 int Socket::recvfrom ( void * buffer, int size,
614                           int flags, IPAddress* from )
615 {
616   assert ( handle != -1 ) ;
617   socklen_t fromlen = (socklen_t) from->getAddrLen() ;
618   return ::recvfrom(handle,(char*)buffer,size,flags, from->getAddr(),&fromlen);
619 }
620
621
622 void Socket::close (void)
623 {
624   if ( handle != -1 )
625   {
626 #if defined(WINSOCK)
627     ::closesocket( handle );
628 #else
629     ::close( handle );
630 #endif
631     handle = -1 ;
632   }
633 }
634
635
636 bool Socket::isNonBlockingError ()
637 {
638 #if defined(WINSOCK)
639   int wsa_errno = WSAGetLastError();
640   if ( wsa_errno != 0 )
641   {
642     WSASetLastError(0);
643         SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno);
644     switch (wsa_errno) {
645     case WSAEWOULDBLOCK: // always == NET_EAGAIN?
646     case WSAEALREADY:
647     case WSAEINPROGRESS:
648       return true;
649     }
650   }
651   return false;
652 #else
653   switch (errno) {
654   case EWOULDBLOCK: // always == NET_EAGAIN?
655   case EALREADY:
656   case EINPROGRESS:
657     return true;
658   }
659   return false;
660
661 #endif
662 }
663
664
665 //////////////////////////////////////////////////////////////////////
666 //
667 //      modified version by os
668 //
669 //////////////////////////////////////////////////////////////////////
670 int Socket::select ( Socket** reads, Socket** writes, int timeout )
671 {
672   fd_set r,w;
673   int   retval;
674
675   FD_ZERO (&r);
676   FD_ZERO (&w);
677
678   int i, k ;
679   int num = 0 ;
680
681   if ( reads )
682   {
683     for ( i=0; reads[i]; i++ )
684     {
685       int fd = reads[i]->getHandle();
686       FD_SET (fd, &r);
687       num++;
688     }
689   }
690
691   if ( writes )
692   {
693     for ( i=0; writes[i]; i++ )
694     {
695       int fd = writes[i]->getHandle();
696       FD_SET (fd, &w);
697       num++;
698     }
699   }
700
701   if (!num)
702     return num ;
703
704   /* Set up the timeout */
705   struct timeval tv ;
706   tv.tv_sec = timeout/1000;
707   tv.tv_usec = (timeout%1000)*1000;
708
709   // It bothers me that select()'s first argument does not appear to
710   // work as advertised... [it hangs like this if called with
711   // anything less than FD_SETSIZE, which seems wasteful?]
712
713   // Note: we ignore the 'exception' fd_set - I have never had a
714   // need to use it.  The name is somewhat misleading - the only
715   // thing I have ever seen it used for is to detect urgent data -
716   // which is an unportable feature anyway.
717
718   retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
719
720   //remove sockets that had no activity
721
722   num = 0 ;
723
724   if ( reads )
725   {
726     for ( k=i=0; reads[i]; i++ )
727     {
728       int fd = reads[i]->getHandle();
729       if ( FD_ISSET (fd, &r) )
730       {
731         reads[k++] = reads[i];
732         num++;
733       }
734     }
735     reads[k] = NULL ;
736   }
737
738   if ( writes )
739   {
740     for ( k=i=0; writes[i]; i++ )
741     {
742       int fd = writes[i]->getHandle();
743       if ( FD_ISSET (fd, &w) )
744       {
745         writes[k++] = writes[i];
746         num++;
747       }
748     }
749     writes[k] = NULL ;
750   }
751
752   if (retval == 0) // timeout
753     return (-2);
754   if (retval == -1)// error
755     return (-1);
756
757   return num ;
758 }
759
760
761 /* Init/Exit functions */
762
763 static void netExit ( void )
764 {
765 #if defined(WINSOCK)
766         /* Clean up windows networking */
767         if ( WSACleanup() == SOCKET_ERROR ) {
768                 if ( WSAGetLastError() == WSAEINPROGRESS ) {
769                         WSACancelBlockingCall();
770                         WSACleanup();
771                 }
772         }
773 #endif
774 }
775
776 int Socket::initSockets()
777 {
778 #if defined(WINSOCK)
779         /* Start up the windows networking */
780         WORD version_wanted = MAKEWORD(1,1);
781         WSADATA wsaData;
782
783         if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
784                 throw sg_exception("WinSock initialization failed");
785         }
786 #endif
787
788   atexit( netExit ) ;
789         return(0);
790 }
791
792
793 } // of namespace simgear
794