From 9d099f181674ae075aa8ccaeb56acc7b732638af Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 19 Jan 2009 21:46:48 +0000 Subject: This should fix the problem of never knowing if your sockets are closed. Now Bu::Socket::read will throw an exception if the socket has been closed. Also, you'll get an exception at object creation if the socket could connect to a computer, but not the given port. --- src/formula.h | 3 ++- src/linux_compatibility.h | 2 ++ src/socket.cpp | 49 ++++++++++++++++++++++++++++++----------------- src/tests/socketbreak.cpp | 27 ++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 src/tests/socketbreak.cpp diff --git a/src/formula.h b/src/formula.h index c57c4bb..c88e409 100644 --- a/src/formula.h +++ b/src/formula.h @@ -44,8 +44,9 @@ namespace Bu { } - prec run( const char *sFormula ) + prec run( const Bu::FString &sFormulaSrc ) { + const char *sFormula = sFormulaSrc.getStr(); for(;;) { uint8_t tNum = nextToken( &sFormula ); diff --git a/src/linux_compatibility.h b/src/linux_compatibility.h index 67016a7..6d3d85e 100644 --- a/src/linux_compatibility.h +++ b/src/linux_compatibility.h @@ -15,6 +15,8 @@ #define bu_bind bind #define bu_listen listen #define bu_accept accept +#define bu_send send +#define bu_recv recv #define bu_gai_strerror gai_strerror diff --git a/src/socket.cpp b/src/socket.cpp index dd19d39..3e4f3c7 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -115,6 +115,7 @@ Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) close(); throw ExceptionBase("Connection timeout.\n"); } + read( NULL, 0 ); // See if we can get any errors out of the way early. } } @@ -129,6 +130,7 @@ void Bu::Socket::close() #ifndef WIN32 fsync( nSocket ); #endif + shutdown( nSocket, SHUT_RDWR ); ::close( nSocket ); } bActive = false; @@ -136,25 +138,36 @@ void Bu::Socket::close() size_t Bu::Socket::read( void *pBuf, size_t nBytes ) { -#ifdef WIN32 - int nRead = TEMP_FAILURE_RETRY( - bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); -#else - int nRead = TEMP_FAILURE_RETRY( ::read( nSocket, pBuf, nBytes ) ); -#endif - if( nRead < 0 ) + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nSocket, &rfds); + struct timeval tv = {0, 0}; + if( bu_select( nSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) + throw SocketException( SocketException::cRead, strerror(errno) ); + if( FD_ISSET( nSocket, &rfds ) ) { + int nRead = TEMP_FAILURE_RETRY( + bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); + if( nRead == 0 ) + { + bActive = false; + throw SocketException( SocketException::cClosed, "Socket closed."); + } + if( nRead < 0 ) + { #ifdef WIN32 - int iWSAError = bu_WSAGetLastError(); - if( iWSAError == WSAEWOULDBLOCK ) - return 0; + int iWSAError = bu_WSAGetLastError(); + if( iWSAError == WSAEWOULDBLOCK ) + return 0; #else - if( errno == EAGAIN ) - return 0; - throw SocketException( SocketException::cRead, strerror(errno) ); + if( errno == EAGAIN ) + return 0; + throw SocketException( SocketException::cRead, strerror(errno) ); #endif + } + return nRead; } - return nRead; + return 0; } size_t Bu::Socket::read( void *pBuf, size_t nBytes, @@ -203,12 +216,12 @@ size_t Bu::Socket::read( void *pBuf, size_t nBytes, size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) { -#ifdef WIN32 +//#ifdef WIN32 int nWrote = TEMP_FAILURE_RETRY( bu_send( nSocket, (const char *) pBuf, nBytes, 0 ) ); -#else - int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); -#endif +//#else +// int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); +//#endif if( nWrote < 0 ) { #ifdef WIN32 diff --git a/src/tests/socketbreak.cpp b/src/tests/socketbreak.cpp new file mode 100644 index 0000000..82069de --- /dev/null +++ b/src/tests/socketbreak.cpp @@ -0,0 +1,27 @@ +#include "bu/serversocket.h" +#include "bu/socket.h" + +int main() +{ + Bu::ServerSocket sSrv( 9987 ); + + Bu::Socket sSend("localhost", 9987 ); + + Bu::Socket sRecv( sSrv.accept() ); + + printf("Connected sockets.\n"); + + sleep( 1 ); + printf("Closing sRecv.\n"); + sRecv.close(); + sleep( 1 ); + + char buf[3]; + printf("About to write.\n"); + printf("write: %d\n", sSend.write("hi", 2 ) ); + printf("About to read.\n"); + printf("read: %d\n", sSend.read( buf, 2 ) ); + + return 0; +} + -- cgit v1.2.3