X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fraw_socket.cxx;h=bb08aae76a26b1e7f240a89cce4a903473e58827;hb=09b0dd2b2d7d934c1d4059cb2cbd3b4fcbb7872f;hp=b849bddc9b288d267a878e4fb6a8de95d87e1cb1;hpb=becea84955bf1d553f0bb6b721ace64b9880fa93;p=simgear.git diff --git a/simgear/io/raw_socket.cxx b/simgear/io/raw_socket.cxx index b849bddc..bb08aae7 100644 --- a/simgear/io/raw_socket.cxx +++ b/simgear/io/raw_socket.cxx @@ -1,20 +1,20 @@ /* simgear::Socket, adapted from PLIB Socket by James Turner Copyright (C) 2010 James Turner - + PLIB - A Suite of Portable Game Libraries Copyright (C) 1998,2002 Steve Baker - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -47,7 +47,7 @@ # include # include # include -# include +# include # include # include # include @@ -61,40 +61,43 @@ #include #include - -#include -#include -#include +#include namespace { -class Resolver : public OpenThreads::Thread +class Resolver : public SGThread { public: static Resolver* instance() { if (!static_instance) { - OpenThreads::Thread::Init(); - static_instance = new Resolver; atexit(&Resolver::cleanup); static_instance->start(); } - + return static_instance; } - + static void cleanup() { - static_instance->cancel(); + static_instance->shutdown(); + static_instance->join(); } - - Resolver() + + Resolver() : + _done(false) + { + } + + void shutdown() { - // take the lock initially, thread will wait upon it once running _lock.lock(); + _done = true; + _wait.signal(); + _lock.unlock(); } - + simgear::IPAddress* lookup(const string& host) { simgear::IPAddress* result = NULL; @@ -109,7 +112,7 @@ public: _lock.unlock(); return result; } - + simgear::IPAddress* lookupSync(const string& host) { simgear::IPAddress* result = NULL; @@ -140,31 +143,33 @@ protected: */ virtual void run() { - while (true) { - _wait.wait(&_lock); + _lock.lock(); + while (!_done) { AddressCache::iterator it; - + for (it = _cache.begin(); it != _cache.end(); ++it) { if (it->second == NULL) { string h = it->first; - + _lock.unlock(); simgear::IPAddress* addr = new simgear::IPAddress; // may take seconds or even minutes! lookupHost(h.c_str(), *addr); _lock.lock(); - + // cahce may have changed while we had the lock released - // so iterators may be invalid: restart the traversal it = _cache.begin(); _cache[h] = addr; } // of found un-resolved entry - } // of un-resolved address iteration + } // of un-resolved address iteration + _wait.wait(_lock); } // of thread run loop + _lock.unlock(); } private: static Resolver* static_instance; - + /** * The actual synchronous, blocking host lookup function * do *not* call this with any locks (mutexs) held, since depending @@ -177,7 +182,7 @@ private: memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; bool ok = false; - + struct addrinfo* result0 = NULL; int err = getaddrinfo(host, NULL, &hints, &result0); if (err) { @@ -205,21 +210,22 @@ private: freeaddrinfo(result0); return ok; } - - OpenThreads::Mutex _lock; - OpenThreads::Condition _wait; - + + SGMutex _lock; + SGWaitCondition _wait; + typedef std::map AddressCache; AddressCache _cache; + bool _done; }; Resolver* Resolver::static_instance = NULL; - + } // of anonymous namespace namespace simgear { - + IPAddress::IPAddress ( const char* host, int port ) { set ( host, port ) ; @@ -266,18 +272,18 @@ void IPAddress::set ( const char* host, int port ) addr->sin_addr.s_addr = INADDR_ANY; return; } - + if (strcmp(host, "") == 0) { addr->sin_addr.s_addr = INADDR_BROADCAST; return; } - + // check the cache IPAddress* cached = Resolver::instance()->lookupSync(host); if (cached) { memcpy(addr, cached->getAddr(), cached->getAddrLen()); } - + addr->sin_port = htons (port); // fix up port after getaddrinfo } @@ -289,12 +295,12 @@ IPAddress::~IPAddress() } bool IPAddress::lookupNonblocking(const char* host, IPAddress& addr) -{ +{ IPAddress* cached = Resolver::instance()->lookup(host); if (!cached) { return false; } - + addr = *cached; return true; } @@ -305,6 +311,10 @@ bool IPAddress::lookupNonblocking(const char* host, IPAddress& addr) const char* IPAddress::getHost () const { + if (!addr) { + return NULL; + } + static char buf [32]; long x = ntohl(addr->sin_addr.s_addr); sprintf(buf, "%d.%d.%d.%d", @@ -313,24 +323,40 @@ const char* IPAddress::getHost () const return buf; } -unsigned int IPAddress::getIP () const -{ - return addr->sin_addr.s_addr; +unsigned int IPAddress::getIP () const +{ + if (!addr) { + return 0; + } + + return addr->sin_addr.s_addr; } unsigned int IPAddress::getPort() const { + if (!addr) { + return 0; + } + return ntohs(addr->sin_port); } void IPAddress::setPort(int port) { + if (!addr) { + return; + } + addr->sin_port = htons(port); } -unsigned int IPAddress::getFamily () const -{ - return addr->sin_family; +unsigned int IPAddress::getFamily () const +{ + if (!addr) { + return 0; + } + + return addr->sin_family; } const char* IPAddress::getLocalHost () @@ -357,7 +383,11 @@ const char* IPAddress::getLocalHost () bool IPAddress::getBroadcast () const { - return (addr->sin_addr.s_addr == INADDR_BROADCAST); + if (!addr) { + return false; + } + + return (addr->sin_addr.s_addr == INADDR_BROADCAST); } unsigned int IPAddress::getAddrLen() const @@ -371,10 +401,15 @@ struct sockaddr* IPAddress::getAddr() const addr = (struct sockaddr_in*) malloc(sizeof(struct sockaddr_in)); memset(addr, 0, sizeof(struct sockaddr_in)); } - + return (struct sockaddr*) addr; } +bool IPAddress::isValid() const +{ + return (addr != NULL); +} + Socket::Socket () { handle = -1 ; @@ -456,7 +491,7 @@ void Socket::setBroadcast ( bool broadcast ) } else { result = ::setsockopt( handle, SOL_SOCKET, SO_BROADCAST, NULL, 0 ); } - + if ( result < 0 ) { throw sg_exception("Socket::setBroadcast failed"); } @@ -476,7 +511,7 @@ int Socket::bind ( const char* host, int port ) } #endif - // 224.0.0.0 - 239.255.255.255 are multicast + // 224.0.0.0 - 239.255.255.255 are multicast // Usage of 239.x.x.x is recommended for local scope // Reference: http://tools.ietf.org/html/rfc5771 if( ntohl(addr.getIP()) >= 0xe0000000 && ntohl(addr.getIP()) <= 0xefffffff ) { @@ -486,7 +521,7 @@ int Socket::bind ( const char* host, int port ) a.sin_addr.S_un.S_addr = INADDR_ANY; a.sin_family = AF_INET; a.sin_port = htons(port); - + if( (result = ::bind(handle,(const sockaddr*)&a,sizeof(a))) < 0 ) { SG_LOG(SG_IO, SG_ALERT, "bind(any:" << port << ") failed. Errno " << errno << " (" << strerror(errno) << ")"); return result; @@ -636,7 +671,7 @@ int Socket::select ( Socket** reads, Socket** writes, int timeout ) { fd_set r,w; int retval; - + FD_ZERO (&r); FD_ZERO (&w); @@ -674,7 +709,7 @@ int Socket::select ( Socket** reads, Socket** writes, int timeout ) // It bothers me that select()'s first argument does not appear to // work as advertised... [it hangs like this if called with // anything less than FD_SETSIZE, which seems wasteful?] - + // Note: we ignore the 'exception' fd_set - I have never had a // need to use it. The name is somewhat misleading - the only // thing I have ever seen it used for is to detect urgent data -