From 469bbcf0701e1eb8a6670c23145b0da87357e178 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 25 Mar 2012 20:00:08 +0000 Subject: Code is all reorganized. We're about ready to release. I should write up a little explenation of the arrangement. --- src/stable/server.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 src/stable/server.cpp (limited to 'src/stable/server.cpp') diff --git a/src/stable/server.cpp b/src/stable/server.cpp new file mode 100644 index 0000000..1972a3f --- /dev/null +++ b/src/stable/server.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/server.h" +#include +#include +#include "bu/tcpserversocket.h" +#include "bu/client.h" +#include "bu/tcpsocket.h" +#include "bu/config.h" + +Bu::Server::Server() : + nTimeoutSec( 0 ), + nTimeoutUSec( 0 ), + bAutoTick( false ) +{ + FD_ZERO( &fdActive ); +} + +Bu::Server::~Server() +{ + shutdown(); +} + +void Bu::Server::addPort( int nPort, int nPoolSize ) +{ + TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); + int nSocket = s->getSocket(); + FD_SET( nSocket, &fdActive ); + hServers.insert( nSocket, s ); +} + +void Bu::Server::addPort( const String &sAddr, int nPort, int nPoolSize ) +{ + TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); + int nSocket = s->getSocket(); + FD_SET( nSocket, &fdActive ); + hServers.insert( nSocket, s ); +} + +void Bu::Server::setTimeout( int nTimeoutSec, int nTimeoutUSec ) +{ + this->nTimeoutSec = nTimeoutSec; + this->nTimeoutUSec = nTimeoutUSec; +} + +void Bu::Server::scan() +{ + struct timeval xTimeout = { nTimeoutSec, nTimeoutUSec }; + + fd_set fdRead = fdActive; + fd_set fdWrite /* = fdActive*/; + fd_set fdException = fdActive; + + FD_ZERO( &fdWrite ); + for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) + { + if( (*i)->hasOutput() ) + FD_SET( i.getKey(), &fdWrite ); + } + + if( TEMP_FAILURE_RETRY( select( FD_SETSIZE, + &fdRead, &fdWrite, &fdException, &xTimeout ) ) < 0 ) + { + throw ExceptionBase("Error attempting to scan open connections."); + } + + for( int j = 0; j < FD_SETSIZE; j++ ) + { + if( FD_ISSET( j, &fdRead ) ) + { + if( hServers.has( j ) ) + { + TcpServerSocket *pSrv = hServers.get( j ); + addClient( pSrv->accept(), pSrv->getPort() ); + } + else + { + Client *pClient = hClients.get( j ); + pClient->processInput(); + if( !pClient->isOpen() ) + { + closeClient( j ); + } + } + } + if( FD_ISSET( j, &fdWrite ) ) + { + try + { + Client *pClient = hClients.get( j ); + try + { + pClient->processOutput(); + } + catch( Bu::TcpSocketException &e ) + { + closeClient( j ); + } + } + catch( Bu::HashException &e ) + { + // Do nothing, I guess, the client is already dead... + // TODO: Someday, we may want to handle this more graceully. + } + } + } + + Bu::List lDelete; + // Now we just try to write all the pending data on all the sockets. + // this could be done better eventually, if we care about the socket + // wanting to accept writes (using a select). + for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) + { + if( (*i)->wantsDisconnect() && !(*i)->hasOutput() ) + { + lDelete.append( i.getKey() ); + } + } + + for( Bu::List::iterator i = lDelete.begin(); i != lDelete.end(); i++ ) + { + closeClient( *i ); + } + + if( bAutoTick ) + tick(); +} + +void Bu::Server::addClient( int nSocket, int nPort ) +{ + FD_SET( nSocket, &fdActive ); + + Client *c = new Client( + new Bu::TcpSocket( nSocket ), + new SrvClientLinkFactory() + ); + hClients.insert( nSocket, c ); + + onNewConnection( c, nPort ); +} + +Bu::Server::SrvClientLink::SrvClientLink( Bu::Client *pClient ) : + pClient( pClient ) +{ +} + +Bu::Server::SrvClientLink::~SrvClientLink() +{ +} + +void Bu::Server::SrvClientLink::sendMessage( const Bu::String &sMsg ) +{ + pClient->onMessage( sMsg ); +} + +Bu::Server::SrvClientLinkFactory::SrvClientLinkFactory() +{ +} + +Bu::Server::SrvClientLinkFactory::~SrvClientLinkFactory() +{ +} + +Bu::ClientLink *Bu::Server::SrvClientLinkFactory::createLink( + Bu::Client *pClient ) +{ + return new SrvClientLink( pClient ); +} + +void Bu::Server::setAutoTick( bool bEnable ) +{ + bAutoTick = bEnable; +} + +void Bu::Server::tick() +{ + for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) + { + (*i)->tick(); + } +} + +void Bu::Server::shutdown() +{ + for( SrvHash::iterator i = hServers.begin(); i != hServers.end(); i++ ) + { + delete *i; + } + + hServers.clear(); + + for( ClientHash::iterator i = hClients.begin(); i != hClients.end(); i++ ) + { + closeClient( i.getKey() ); + } + + hClients.clear(); +} + +void Bu::Server::closeClient( int iSocket ) +{ + Bu::Client *pClient = hClients.get( iSocket ); + onClosedConnection( pClient ); + pClient->close(); + hClients.erase( iSocket ); + FD_CLR( iSocket, &fdActive ); + delete pClient; +} + -- cgit v1.2.3