From 87d76df1720e29e4195cf4a8845c07450fb3b2f2 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 1 Aug 2023 11:38:26 -0700 Subject: Fixed issues around disconnected sockets. We were bailing out when sockets closed, that was silly. --- src/stable/server.cpp | 97 ++++++++++++++++++++++++++++++++++---------------- src/stable/server.h | 2 +- src/stable/sockettcp.h | 7 ++++ 3 files changed, 75 insertions(+), 31 deletions(-) (limited to 'src/stable') diff --git a/src/stable/server.cpp b/src/stable/server.cpp index 3aa8a34..6ee7d6e 100644 --- a/src/stable/server.cpp +++ b/src/stable/server.cpp @@ -247,6 +247,8 @@ void Bu::Server::addClient( const Bu::ServerSocket *pSrv, Bu::Socket *pSocket ) Bu::Client *Bu::Server::getClient( fd iId ) { Bu::MutexLocker l( mClients ); + if( !hClients.has( iId ) ) + return NULL; return hClients.get( iId ); } @@ -520,30 +522,38 @@ void Bu::Server::IoWorker::handleRead( Client *pClient, Socket *pSocket ) Bu::size iTotal=0; BU_PROFILE_START("client.read"); - for(;;) + try { - try + for(;;) { - iRead = pSocket->read( buf, RBS ); - - if( iRead == 0 ) + try { - break; + iRead = pSocket->read( buf, RBS ); + + if( iRead == 0 ) + { + break; + } + else + { + iTotal += iRead; + pClient->cbBuffer.server().write( buf, iRead ); + if( !pSocket->canRead() ) + break; + } } - else + catch( Bu::ExceptionBase &e ) { - iTotal += iRead; - pClient->cbBuffer.server().write( buf, iRead ); - if( !pSocket->canRead() ) - break; + pClient->disconnect(); + //close( pSocket ); + return; } } - catch( Bu::ExceptionBase &e ) - { - pClient->disconnect(); - //close( pSocket ); - return; - } + } + catch( std::exception &e ) + { + // Probably the socket is dead. We should maybe disconnect, but we'll + // also notice soon enough anyway? } BU_PROFILE_END("client.read"); @@ -565,12 +575,28 @@ void Bu::Server::IoWorker::handleRead( Client *pClient, Socket *pSocket ) void Bu::Server::IoWorker::handleWrite( Client *pClient, Socket *pSocket ) { char buf[RBS]; - while( pClient->hasOutput() > 0 ) + try + { + while( pClient->hasOutput() ) + { + int iAmnt = RBS; + iAmnt = pClient->cbBuffer.server().peek( buf, iAmnt ); + int iReal = pSocket->write( buf, iAmnt ); + pClient->cbBuffer.server().seek( iReal ); + if( iReal < iAmnt ) + { + // We wrote less than expected, the kernel buffer must be full, + // we should queue ourselves again. + rSrv.clientWriteReady( pClient->getId() ); + break; + } + } + } + catch( std::exception &e ) { - int iAmnt = RBS; - iAmnt = pClient->cbBuffer.server().peek( buf, iAmnt ); - int iReal = pSocket->write( buf, iAmnt ); - pClient->cbBuffer.server().seek( iReal ); + // Error working with socket, it's probably closed. + if( pClient->hasOutput() ) + rSrv.clientWriteReady( pClient->getId() ); } } @@ -596,17 +622,28 @@ void Bu::Server::ClientWorker::run() if( pEv == NULL ) continue; - Client *pClient = rSrv.getClient( pEv->getId() ); - if( pClient == NULL ) + try { - delete pEv; - continue; + Client *pClient = rSrv.getClient( pEv->getId() ); + if( pClient == NULL ) + { + delete pEv; + continue; + } + + pClient->processInput(); + if( pClient->getOutputSize() > 0 ) + { + rSrv.clientWriteReady( pClient->getId() ); + } } - - pClient->processInput(); - if( pClient->getOutputSize() > 0 ) + catch( std::exception &e ) + { + // Probably we're fine, the client just closed between queuing and + // working. + } + catch(...) { - rSrv.clientWriteReady( pClient->getId() ); } delete pEv; } diff --git a/src/stable/server.h b/src/stable/server.h index 9fb8282..a9680cf 100644 --- a/src/stable/server.h +++ b/src/stable/server.h @@ -23,7 +23,7 @@ #include "bu/config.h" #ifndef PROFILE_BU_SERVER - #define PROFILE_BU_SERVER 1 +// #define PROFILE_BU_SERVER 1 #endif #ifdef PROFILE_BU_SERVER diff --git a/src/stable/sockettcp.h b/src/stable/sockettcp.h index 3fc14ef..8539b52 100644 --- a/src/stable/sockettcp.h +++ b/src/stable/sockettcp.h @@ -48,7 +48,14 @@ namespace Bu ... ... ... + // sigset is deprecated sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::SocketTcp + + // this is the modern Linux alternative + struct sigaction saIgnore; + memset( &saIgnore, 0, sizeof(struct sigaction) ); + saIgnore.sa_handler = SIG_IGN; + sigaction( SIGPIPE, &saIgnore, NULL ); @endcode * When this is done, Bu::SocketTcp will simply throw a broken pipe * exception just like every other error condition, allowing your program -- cgit v1.2.3