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