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 <simgear/debug/logstream.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);
}
}
close () ;
Socket::setHandle ( handle ) ;
connected = is_connected ;
- //if ( connected ) this->handleConnect();
closed = false ;
}
}
int
-NetChannel::connect ( const char* host, int port )
+NetChannel::connect ( const char* h, int p )
{
- int result = Socket::connect ( host, port ) ;
- if (result == 0) {
- connected = true ;
- //this->handleConnect();
- return 0;
- } else if (isNonBlockingError ()) {
- return 0;
- } else {
- // some other error condition
- this->handleError (result);
- close();
- return -1;
- }
+ host = h;
+ port = p;
+ resolving_host = true;
+ return handleResolve();
}
int
if (accepting) {
if (!connected) {
connected = true ;
- //this->handleConnect();
}
this->handleAccept();
} else if (!connected) {
connected = true ;
- //this->handleConnect();
this->handleRead();
} else {
this->handleRead();
{
if (!connected) {
connected = true ;
- //this->handleConnect();
}
write_blocked = false ;
this->handleWrite();
}
-bool
-NetChannel::poll (unsigned int timeout)
+int
+NetChannel::handleResolve()
{
- 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 ;
+ IPAddress addr;
+ if (!IPAddress::lookupNonblocking(host.c_str(), addr)) {
+ return 0; // not looked up yet, wait longer
}
- else if ( ! ch -> closed )
- {
- nopen++ ;
- if (ch -> readable()) {
- assert(nreads<MAX_SOCKETS);
- reads[nreads++] = ch ;
- }
- if (ch -> writable()) {
- assert(nwrites<MAX_SOCKETS);
- writes[nwrites++] = ch ;
- }
+
+ if (!addr.isValid()) {
+ SG_LOG(SG_IO, SG_WARN, "Network: host lookup failed:" << host);
+ handleError (ENOENT);
+ close();
+ return -1;
}
- }
- reads[nreads] = NULL ;
- writes[nwrites] = NULL ;
- deletes[ndeletes] = NULL ;
-
- int i ;
- for ( i=0; deletes[i]; i++ )
- {
- ch = (NetChannel*)deletes[i];
- delete ch ;
- }
+
+ resolving_host = false;
+ addr.setPort(port);
+ int result = Socket::connect ( &addr ) ;
+ if (result == 0) {
+ connected = true ;
+ return 0;
+ } else if (isNonBlockingError ()) {
+ return 0;
+ } else {
+ // some other error condition
+ handleError (result);
+ close();
+ return -1;
+ }
+}
- if (!nopen)
- return false ;
- if (!nreads && !nwrites)
- return true ; //hmmm- should we shutdown?
+void NetChannel::handleRead (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
+}
- Socket::select (reads, writes, timeout) ;
+void NetChannel::handleWrite (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
+}
- for ( i=0; reads[i]; i++ )
- {
- ch = (NetChannel*)reads[i];
- if ( ! ch -> closed )
- ch -> handleReadEvent();
- }
+void NetChannel::handleAccept (void) {
+ SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
+}
- for ( i=0; writes[i]; i++ )
- {
- ch = (NetChannel*)writes[i];
- if ( ! ch -> closed )
- ch -> handleWriteEvent();
- }
+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 << ")");
+ }
+}
- return true ;
+void
+NetChannelPoller::addChannel(NetChannel* channel)
+{
+ assert(channel);
+ assert(channel->poller == NULL);
+
+ channel->poller = this;
+ channels.push_back(channel);
}
void
-NetChannel::loop (unsigned int timeout)
+NetChannelPoller::removeChannel(NetChannel* channel)
{
- while ( poll (timeout) ) ;
+ assert(channel);
+ assert(channel->poller == this);
+ channel->poller = NULL;
+
+ ChannelList::iterator it = channels.begin();
+ for (; it != channels.end(); ++it) {
+ if (*it == channel) {
+ channels.erase(it);
+ return;
+ }
+ }
}
+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::handleRead (void) {
- SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
-}
+ for ( int i=0; writes[i]; i++ )
+ {
+ NetChannel* ch = (NetChannel*)writes[i];
+ if ( ! ch -> closed )
+ ch -> handleWriteEvent();
+ }
-void NetChannel::handleWrite (void) {
- SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
+ return true ;
}
-void NetChannel::handleAccept (void) {
- SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
+void
+NetChannelPoller::loop (unsigned int timeout)
+{
+ while ( poll (timeout) ) ;
}
-void NetChannel::handleError (int error) {
- SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
-}
} // of namespace simgear