Files
simgear/simgear/io/sg_netChannel.cxx
T

309 lines
6.2 KiB
C++

/*
Copied from PLIB into SimGear
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
For further information visit http://plib.sourceforge.net
$Id: netChannel.cxx 1906 2004-03-22 19:44:50Z sjbaker $
*/
// TODO:
// have all socket-related functions assert that the socket has not
// been closed. [a read event may close it, and a write event may try
// to write or something...]
// Maybe assert valid handle, too?
#include "sg_netChannel.hxx"
#include <memory>
#include <cassert>
#include <cstring>
#include <errno.h>
#include <simgear/debug/logstream.hxx>
namespace simgear {
static NetChannel* channels = 0 ;
NetChannel::NetChannel ()
{
closed = true ;
connected = false ;
accepting = false ;
write_blocked = false ;
should_delete = false ;
next_channel = channels ;
channels = this ;
}
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 ;
}
}
void
NetChannel::setHandle (int handle, bool is_connected)
{
close () ;
Socket::setHandle ( handle ) ;
connected = is_connected ;
//if ( connected ) this->handleConnect();
closed = false ;
}
bool
NetChannel::open (void)
{
close();
if (Socket::open(true)) {
closed = false ;
setBlocking ( false ) ;
return true ;
}
return false ;
}
int
NetChannel::listen ( int backlog )
{
accepting = true ;
return Socket::listen ( backlog ) ;
}
int
NetChannel::connect ( const char* host, int port )
{
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;
}
}
int
NetChannel::send (const void * buffer, int size, int flags)
{
int result = Socket::send (buffer, size, flags);
if (result == (int)size) {
// everything was sent
write_blocked = false ;
return result;
} else if (result >= 0) {
// not all of it was sent, but no error
write_blocked = true ;
return result;
} else if (isNonBlockingError ()) {
write_blocked = true ;
return 0;
} else {
this->handleError (result);
close();
return -1;
}
}
int
NetChannel::recv (void * buffer, int size, int flags)
{
int result = Socket::recv (buffer, size, flags);
if (result > 0) {
return result;
} else if (result == 0) {
close();
return 0;
} else if (isNonBlockingError ()) {
return 0;
} else {
this->handleError (result);
close();
return -1;
}
}
void
NetChannel::close (void)
{
if ( !closed )
{
this->handleClose();
closed = true ;
connected = false ;
accepting = false ;
write_blocked = false ;
}
Socket::close () ;
}
void
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();
}
}
void
NetChannel::handleWriteEvent (void)
{
if (!connected) {
connected = true ;
//this->handleConnect();
}
write_blocked = false ;
this->handleWrite();
}
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 -> 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) ;
for ( i=0; reads[i]; i++ )
{
ch = (NetChannel*)reads[i];
if ( ! ch -> closed )
ch -> handleReadEvent();
}
for ( i=0; writes[i]; i++ )
{
ch = (NetChannel*)writes[i];
if ( ! ch -> closed )
ch -> handleWriteEvent();
}
return true ;
}
void
NetChannel::loop (unsigned int timeout)
{
while ( poll (timeout) ) ;
}
void NetChannel::handleRead (void) {
SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read");
}
void NetChannel::handleWrite (void) {
SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled write");
}
void NetChannel::handleAccept (void) {
SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled accept");
}
void NetChannel::handleError (int error) {
SG_LOG(SG_IO, SG_WARN,"Network:" << getHandle() << ": errno: " << strerror(errno) <<"(" << errno << ")");
}
} // of namespace simgear