X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fsg_netChannel.cxx;h=1561e8de464bbbc83413915f1b53d82ec2367727;hb=70c5d605641b628039f75cb8761ce783a17a5bdf;hp=d34a521bd465c4e6792ab56af0f097d84d33c092;hpb=878b504f8e044bc0e59903caa8641492421b76d8;p=simgear.git diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx index d34a521b..1561e8de 100644 --- a/simgear/io/sg_netChannel.cxx +++ b/simgear/io/sg_netChannel.cxx @@ -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 @@ -34,46 +34,29 @@ #include #include #include +#include #include -#include -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 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 writable()) { - assert(nwrites 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 writable()) { + assert(nwrites 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