]> git.mxchange.org Git - simgear.git/blobdiff - simgear/io/sg_netChannel.cxx
Drop explicit SDK setting on Mac
[simgear.git] / simgear / io / sg_netChannel.cxx
index d34a521bd465c4e6792ab56af0f097d84d33c092..1561e8de464bbbc83413915f1b53d82ec2367727 100644 (file)
@@ -16,7 +16,7 @@
  
      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
+     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
  
      For further information visit http://plib.sourceforge.net
 
 #include <memory>
 #include <cassert>
 #include <cstring>
+#include <errno.h>
 
 #include <simgear/debug/logstream.hxx>
-#include <simgear/io/HostLookup.hxx>
 
-namespace simgear  {
 
-static NetChannel* channels = 0 ;
+namespace simgear  {
 
 NetChannel::NetChannel ()
 {
   closed = true ;
   connected = false ;
+  resolving_host  = false;
   accepting = false ;
   write_blocked = false ;
   should_delete = false ;
-
-  next_channel = channels ;
-  channels = this ;
+  poller = NULL;
 }
   
 NetChannel::~NetChannel ()
 {
   close();
-
-  NetChannel* prev = NULL ;
-
-  for ( NetChannel* ch = channels; ch != NULL;
-                    ch = ch -> next_channel )
-  {
-    if (ch == this)
-    {
-      ch = ch -> next_channel ;
-      if ( prev != NULL )
-        prev -> next_channel = ch ;
-      else
-        channels = ch ;
-      next_channel = 0 ;
-      break;
-    }
-    prev = ch ;
+  if (poller) {
+      poller->removeChannel(this);
   }
 }
   
@@ -83,7 +66,6 @@ NetChannel::setHandle (int handle, bool is_connected)
   close () ;
   Socket::setHandle ( handle ) ;
   connected = is_connected ;
-  //if ( connected ) this->handleConnect();
   closed = false ;
 }
 
@@ -107,11 +89,12 @@ NetChannel::listen ( int backlog )
 }
 
 int
-NetChannel::connect ( const char* host, int p )
+NetChannel::connect ( const char* h, int p )
 {
-  host_lookup = HostLookup::lookup(host);
+  host = h;
   port = p;
-  return 0;
+  resolving_host = true;
+  return handleResolve();
 }
 
 int
@@ -179,12 +162,10 @@ NetChannel::handleReadEvent (void)
   if (accepting) {
     if (!connected) {
       connected = true ;
-      //this->handleConnect();
     }
     this->handleAccept();
   } else if (!connected) {
     connected = true ;
-    //this->handleConnect();
     this->handleRead();
   } else {
     this->handleRead();
@@ -196,132 +177,176 @@ NetChannel::handleWriteEvent (void)
 {
   if (!connected) {
     connected = true ;
-    //this->handleConnect();
   }
   write_blocked = false ;
   this->handleWrite();
 }
 
-void
-NetChannel::doConnect()
-{    
-    IPAddress addr( host_lookup->address() );
+int
+NetChannel::handleResolve()
+{
+    IPAddress addr;
+    if (!IPAddress::lookupNonblocking(host.c_str(), addr)) {
+        return 0; // not looked up yet, wait longer
+    }
+    
+    if (!addr.isValid()) {
+        SG_LOG(SG_IO, SG_WARN, "Network: host lookup failed:" << host);
+        handleError (ENOENT);
+        close();
+        return -1;
+    }
+    
+    resolving_host = false;
     addr.setPort(port);
-    int result = Socket::connect ( addr ) ;
-    host_lookup = NULL;
-
+    int result = Socket::connect ( &addr ) ;
     if (result == 0) {
         connected = true ;
+        return 0;
     } else if (isNonBlockingError ()) {
-
+        return 0;
     } else {
-    // some other error condition
+        // some other error condition
         handleError (result);
         close();
+        return -1;
     }
 }
 
-bool
-NetChannel::poll (unsigned int timeout)
-{
-  if (!channels)
-    return false ;
-  
-  enum { MAX_SOCKETS = 256 } ;
-  Socket* reads [ MAX_SOCKETS+1 ] ;
-  Socket* writes [ MAX_SOCKETS+1 ] ;
-  Socket* deletes [ MAX_SOCKETS+1 ] ;
-  int nreads = 0 ;
-  int nwrites = 0 ;
-  int ndeletes = 0 ;
-  int nopen = 0 ;
-  NetChannel* ch;
-  for (  ch = channels; ch != NULL; ch = ch -> next_channel )
-  {
-    if ( ch -> should_delete )
-    {
-      assert(ndeletes<MAX_SOCKETS);
-      deletes[ndeletes++] = ch ;
-    }
-    else if ( ! ch -> closed )
-    {
-      nopen++ ;
-      if (ch->host_lookup) {
-          if (ch->host_lookup->resolved()) {
-              ch->doConnect();
-          } else if (ch->host_lookup->failed()) {
-              ch->handleError (-1);
-              ch->close();
-          }
-          continue;
-      }
-      
-      if (ch -> readable()) {
-        assert(nreads<MAX_SOCKETS);
-        reads[nreads++] = ch ;
-      }
-      if (ch -> writable()) {
-        assert(nwrites<MAX_SOCKETS);
-        writes[nwrites++] = ch ;
-      }
-    }
-  }
-  reads[nreads] = NULL ;
-  writes[nwrites] = NULL ;
-  deletes[ndeletes] = NULL ;
-
-  int i ;
-  for ( i=0; deletes[i]; i++ )
-  {
-    ch = (NetChannel*)deletes[i];
-    delete ch ;
-  }
-
-  if (!nopen)
-    return false ;
-  if (!nreads && !nwrites)
-    return true ; //hmmm- should we shutdown?
-
-  Socket::select (reads, writes, timeout) ;
+void NetChannel::handleRead (void) {
+  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
+}
 
-  for ( i=0; reads[i]; i++ )
-  {
-    ch = (NetChannel*)reads[i];
-    if ( ! ch -> closed )
-      ch -> handleReadEvent();
-  }
+void NetChannel::handleWrite (void) {
+  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
+}
 
-  for ( i=0; writes[i]; i++ )
-  {
-    ch = (NetChannel*)writes[i];
-    if ( ! ch -> closed )
-      ch -> handleWriteEvent();
-  }
+void NetChannel::handleAccept (void) {
+  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
+}
 
-  return true ;
+void NetChannel::handleError (int error)
+{
+    // warn about address lookup failures seperately, don't warn again.
+    // (and we (ab-)use ENOENT to mean 'name not found'.
+    if (error != ENOENT) {
+        SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
+    }
 }
 
 void
-NetChannel::loop (unsigned int timeout)
+NetChannelPoller::addChannel(NetChannel* channel)
 {
-  while ( poll (timeout) ) ;
+    assert(channel);
+    assert(channel->poller == NULL);
+        
+    channel->poller = this;
+    channels.push_back(channel);
 }
 
+void
+NetChannelPoller::removeChannel(NetChannel* channel)
+{
+    assert(channel);
+    assert(channel->poller == this);
+    channel->poller = NULL;
+    
+    // portability: MSVC throws assertion failure when empty
+    if (channels.empty()) {
+        return;
+    }
 
-void NetChannel::handleRead (void) {
-  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
+    ChannelList::iterator it = channels.begin();
+    for (; it != channels.end(); ++it) {
+        if (*it == channel) {
+            channels.erase(it);
+            return;
+        }
+    }
 }
 
-void NetChannel::handleWrite (void) {
-  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
-}
+bool
+NetChannelPoller::poll(unsigned int timeout)
+{
+    if (channels.empty()) {
+        return false;
+    }
+    
+    enum { MAX_SOCKETS = 256 } ;
+    Socket* reads [ MAX_SOCKETS+1 ] ;
+    Socket* writes [ MAX_SOCKETS+1 ] ;
+    int nreads = 0 ;
+    int nwrites = 0 ;
+    int nopen = 0 ;
+    
+    ChannelList::iterator it = channels.begin();
+    while( it != channels.end() )
+    {
+        NetChannel* ch = *it;
+        if ( ch -> should_delete )
+        {
+            // avoid the channel trying to remove itself from us, or we get
+            // bug http://code.google.com/p/flightgear-bugs/issues/detail?id=1144
+            ch->poller = NULL;
+            delete ch;
+            it = channels.erase(it);
+            continue;
+        }
+
+        ++it; // we've copied the pointer into ch
+        if ( ch->closed ) { 
+            continue;
+        }
+
+        if (ch -> resolving_host )
+        {
+            ch -> handleResolve();
+            continue;
+        }
+      
+        nopen++ ;
+        if (ch -> readable()) {
+          assert(nreads<MAX_SOCKETS);
+          reads[nreads++] = ch ;
+        }
+        if (ch -> writable()) {
+          assert(nwrites<MAX_SOCKETS);
+          writes[nwrites++] = ch ;
+        }
+    } // of array-filling pass
+    
+    reads[nreads] = NULL ;
+    writes[nwrites] = NULL ;
+
+    if (!nopen)
+      return false ;
+    if (!nreads && !nwrites)
+      return true ; //hmmm- should we shutdown?
+
+    Socket::select (reads, writes, timeout) ;
+
+    for ( int i=0; reads[i]; i++ )
+    {
+      NetChannel* ch = (NetChannel*)reads[i];
+      if ( ! ch -> closed )
+        ch -> handleReadEvent();
+    }
 
-void NetChannel::handleAccept (void) {
-  SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
+    for ( int i=0; writes[i]; i++ )
+    {
+      NetChannel* ch = (NetChannel*)writes[i];
+      if ( ! ch -> closed )
+        ch -> handleWriteEvent();
+    }
+
+    return true ;
 }
 
-void NetChannel::handleError (int error) {
-  SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
+void
+NetChannelPoller::loop (unsigned int timeout)
+{
+  while ( poll (timeout) ) ;
 }
 
+
 } // of namespace simgear