X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2Fsg_netChannel.cxx;h=3fe0decfa85ca0aaa1acc1183a5e739835cc7e11;hb=84e5142195f5d3b2bf40b11119991457d7f8558b;hp=a189f6816af6de09e6b8a1af07315fc0b4a2f947;hpb=08cb2039c53cff49e93e621621a9796b1c43f574;p=simgear.git diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx index a189f681..3fe0decf 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 @@ -41,8 +41,6 @@ namespace simgear { -static NetChannel* channels = 0 ; - NetChannel::NetChannel () { closed = true ; @@ -51,31 +49,14 @@ NetChannel::NetChannel () 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); } } @@ -133,7 +114,7 @@ NetChannel::send (const void * buffer, int size, int flags) write_blocked = true ; return 0; } else { - this->handleError (result); + this->handleError (errorNumber()); close(); return -1; } @@ -153,7 +134,7 @@ NetChannel::recv (void * buffer, int size, int flags) } else if (isNonBlockingError ()) { return 0; } else { - this->handleError (result); + this->handleError (errorNumber()); close(); return -1; } @@ -211,7 +192,7 @@ NetChannel::handleResolve() if (!addr.isValid()) { SG_LOG(SG_IO, SG_WARN, "Network: host lookup failed:" << host); - handleError (0); + handleError (ENOENT); close(); return -1; } @@ -226,109 +207,153 @@ NetChannel::handleResolve() return 0; } else { // some other error condition - handleError (result); + handleError (errorNumber()); 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 ) - { - 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 ( i=0; writes[i]; i++ ) - { - ch = (NetChannel*)writes[i]; - if ( ! ch -> closed ) - ch -> handleWriteEvent(); - } +void NetChannel::handleError (int error) +{ + if (error == EINPROGRESS) { + // this shoudl never happen, because we should use isNonBlocking to check + // such error codes. + SG_LOG(SG_IO, SG_WARN, "Got EINPROGRESS at NetChannel::handleError: suggests broken logic somewhere else"); + return; // not an actual error, don't warn + } - return true ; + // 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(); + } + + 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