]> git.mxchange.org Git - simgear.git/blob - simgear/io/raw_socket.cxx
Fix VS2010 lack of fminf
[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 #ifdef SO_NOSIGPIPE
458   // Do not generate SIGPIPE signal (which immediately terminates the program),
459   // instead ::send() will return -1 and errno will be set to EPIPE.
460   // SO_NOSIGPIPE should be available on Mac/BSD systems, but is not available
461   // within Posix/Linux.
462   // This only works for calls to ::send() but not for ::write():
463   // http://freebsd.1045724.n5.nabble.com/is-setsockopt-SO-NOSIGPIPE-work-tp4011054p4011055.html
464   int set = 1;
465   setsockopt(handle, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(set));
466 #endif
467
468 #ifndef MSG_NOSIGNAL
469 # define MSG_NOSIGNAL 0
470 #endif
471   // TODO supress SIGPIPE if neither SO_NOSIGPIPE nor MSG_NOSIGNAL is available
472   // http://krokisplace.blogspot.co.at/2010/02/suppressing-sigpipe-in-library.html
473
474   return (handle != -1);
475 }
476
477
478 void Socket::setBlocking ( bool blocking )
479 {
480   assert ( handle != -1 ) ;
481
482 #if defined(WINSOCK)
483     u_long nblocking = blocking? 0: 1;
484   ::ioctlsocket(handle, FIONBIO, &nblocking);
485 #else
486
487   int delay_flag = ::fcntl (handle, F_GETFL, 0);
488
489   if (blocking)
490     delay_flag &= (~O_NDELAY);
491   else
492     delay_flag |= O_NDELAY;
493
494   ::fcntl (handle, F_SETFL, delay_flag);
495 #endif
496 }
497
498
499 void Socket::setBroadcast ( bool broadcast )
500 {
501   assert ( handle != -1 ) ;
502   int result;
503   if ( broadcast ) {
504       int one = 1;
505 #if defined(_WIN32) || defined(__CYGWIN__)
506       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char*)&one, sizeof(one) );
507 #else
508       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) );
509 #endif
510   } else {
511       result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 );
512   }
513
514   if ( result < 0 ) {
515       throw sg_exception("Socket::setBroadcast failed");
516   }
517 }
518
519
520 int Socket::bind ( const char* host, int port )
521 {
522   int result;
523   assert ( handle != -1 ) ;
524   IPAddress addr ( host, port ) ;
525
526 #if !defined(WINSOCK)
527   if( (result = ::bind(handle, addr.getAddr(), addr.getAddrLen() ) ) < 0 ) {
528     SG_LOG(SG_IO, SG_ALERT, "bind(" << addr.getHost() << ":" << addr.getPort() << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
529     return result;
530   }
531 #endif
532
533   // 224.0.0.0 - 239.255.255.255 are multicast
534   // Usage of 239.x.x.x is recommended for local scope
535   // Reference: http://tools.ietf.org/html/rfc5771
536   if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) {
537
538 #if defined(WINSOCK)
539     struct sockaddr_in a;
540     a.sin_addr.S_un.S_addr = INADDR_ANY;
541     a.sin_family = AF_INET;
542     a.sin_port = htons(port);
543
544     if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) {
545       SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
546       return result;
547     }
548 #endif
549
550     struct ip_mreq mreq;
551     mreq.imr_multiaddr.s_addr = addr.getIP();
552     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
553     if( (result=::setsockopt(getHandle(), IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq))) != 0 ) {
554       SG_LOG(SG_IO, SG_ALERT, "setsockopt(IP_ADD_MEMBERSHIP) failed. Errno " << errno << " (" << strerror(errno) << ")");
555       return result;
556     }
557   }
558 #if defined(WINSOCK)
559   else if( (result = ::bind(handle,addr.getAddr(), addr.getAddrLen())) < 0 ) {
560     SG_LOG(SG_IO, SG_ALERT, "bind(" << host << ":" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")");
561     return result;
562   }
563 #endif
564
565   return 0;
566 }
567
568
569 int Socket::listen ( int backlog )
570 {
571   assert ( handle != -1 ) ;
572   return ::listen(handle,backlog);
573 }
574
575
576 int Socket::accept ( IPAddress* addr )
577 {
578   assert ( handle != -1 ) ;
579
580   if ( addr == NULL )
581   {
582     return ::accept(handle,NULL,NULL);
583   }
584   else
585   {
586     socklen_t addr_len = addr->getAddrLen(); ;
587     return ::accept(handle, addr->getAddr(), &addr_len);
588   }
589 }
590
591
592 int Socket::connect ( const char* host, int port )
593 {
594   IPAddress addr ( host, port ) ;
595   return connect ( &addr );
596 }
597
598
599 int Socket::connect ( IPAddress* addr )
600 {
601   assert ( handle != -1 ) ;
602   if ( addr->getBroadcast() ) {
603       setBroadcast( true );
604   }
605   return ::connect(handle, addr->getAddr(), addr->getAddrLen() );
606 }
607
608
609 int Socket::send (const void * buffer, int size, int flags)
610 {
611   assert ( handle != -1 ) ;
612   return ::send (handle, (const char*)buffer, size, flags | MSG_NOSIGNAL);
613 }
614
615
616 int Socket::sendto ( const void * buffer, int size,
617                         int flags, const IPAddress* to )
618 {
619   assert ( handle != -1 ) ;
620   return ::sendto( handle,
621                    (const char*)buffer,
622                    size,
623                    flags | MSG_NOSIGNAL,
624                    (const sockaddr*)to->getAddr(),
625                    to->getAddrLen() );
626 }
627
628
629 int Socket::recv (void * buffer, int size, int flags)
630 {
631   assert ( handle != -1 ) ;
632   return ::recv (handle, (char*)buffer, size, flags);
633 }
634
635
636 int Socket::recvfrom ( void * buffer, int size,
637                           int flags, IPAddress* from )
638 {
639   assert ( handle != -1 ) ;
640   socklen_t fromlen = (socklen_t) from->getAddrLen() ;
641   return ::recvfrom(handle,(char*)buffer,size,flags, from->getAddr(),&fromlen);
642 }
643
644
645 void Socket::close (void)
646 {
647   if ( handle != -1 )
648   {
649 #if defined(WINSOCK)
650     ::closesocket( handle );
651 #else
652     ::close( handle );
653 #endif
654     handle = -1 ;
655   }
656 }
657
658
659 bool Socket::isNonBlockingError ()
660 {
661 #if defined(WINSOCK)
662   int wsa_errno = WSAGetLastError();
663   if ( wsa_errno != 0 )
664   {
665     WSASetLastError(0);
666         SG_LOG(SG_IO, SG_WARN, "isNonBlockingError: WSAGetLastError():" << wsa_errno);
667     switch (wsa_errno) {
668     case WSAEWOULDBLOCK: // always == NET_EAGAIN?
669     case WSAEALREADY:
670     case WSAEINPROGRESS:
671       return true;
672     }
673   }
674   return false;
675 #else
676   switch (errno) {
677   case EWOULDBLOCK: // always == NET_EAGAIN?
678   case EALREADY:
679   case EINPROGRESS:
680     return true;
681   }
682   return false;
683
684 #endif
685 }
686
687
688 //////////////////////////////////////////////////////////////////////
689 //
690 //      modified version by os
691 //
692 //////////////////////////////////////////////////////////////////////
693 int Socket::select ( Socket** reads, Socket** writes, int timeout )
694 {
695   fd_set r,w;
696   int   retval;
697
698   FD_ZERO (&r);
699   FD_ZERO (&w);
700
701   int i, k ;
702   int num = 0 ;
703
704   if ( reads )
705   {
706     for ( i=0; reads[i]; i++ )
707     {
708       int fd = reads[i]->getHandle();
709       FD_SET (fd, &r);
710       num++;
711     }
712   }
713
714   if ( writes )
715   {
716     for ( i=0; writes[i]; i++ )
717     {
718       int fd = writes[i]->getHandle();
719       FD_SET (fd, &w);
720       num++;
721     }
722   }
723
724   if (!num)
725     return num ;
726
727   /* Set up the timeout */
728   struct timeval tv ;
729   tv.tv_sec = timeout/1000;
730   tv.tv_usec = (timeout%1000)*1000;
731
732   // It bothers me that select()'s first argument does not appear to
733   // work as advertised... [it hangs like this if called with
734   // anything less than FD_SETSIZE, which seems wasteful?]
735
736   // Note: we ignore the 'exception' fd_set - I have never had a
737   // need to use it.  The name is somewhat misleading - the only
738   // thing I have ever seen it used for is to detect urgent data -
739   // which is an unportable feature anyway.
740
741   retval = ::select (FD_SETSIZE, &r, &w, 0, &tv);
742
743   //remove sockets that had no activity
744
745   num = 0 ;
746
747   if ( reads )
748   {
749     for ( k=i=0; reads[i]; i++ )
750     {
751       int fd = reads[i]->getHandle();
752       if ( FD_ISSET (fd, &r) )
753       {
754         reads[k++] = reads[i];
755         num++;
756       }
757     }
758     reads[k] = NULL ;
759   }
760
761   if ( writes )
762   {
763     for ( k=i=0; writes[i]; i++ )
764     {
765       int fd = writes[i]->getHandle();
766       if ( FD_ISSET (fd, &w) )
767       {
768         writes[k++] = writes[i];
769         num++;
770       }
771     }
772     writes[k] = NULL ;
773   }
774
775   if (retval == 0) // timeout
776     return (-2);
777   if (retval == -1)// error
778     return (-1);
779
780   return num ;
781 }
782
783
784 /* Init/Exit functions */
785
786 static void netExit ( void )
787 {
788 #if defined(WINSOCK)
789         /* Clean up windows networking */
790         if ( WSACleanup() == SOCKET_ERROR ) {
791                 if ( WSAGetLastError() == WSAEINPROGRESS ) {
792                         WSACancelBlockingCall();
793                         WSACleanup();
794                 }
795         }
796 #endif
797 }
798
799 int Socket::initSockets()
800 {
801 #if defined(WINSOCK)
802         /* Start up the windows networking */
803         WORD version_wanted = MAKEWORD(1,1);
804         WSADATA wsaData;
805
806         if ( WSAStartup(version_wanted, &wsaData) != 0 ) {
807                 throw sg_exception("WinSock initialization failed");
808         }
809 #endif
810
811   atexit( netExit ) ;
812         return(0);
813 }
814
815
816 } // of namespace simgear
817