diff options
Diffstat (limited to 'lib/server/SocketStream.cpp')
-rw-r--r-- | lib/server/SocketStream.cpp | 152 |
1 files changed, 106 insertions, 46 deletions
diff --git a/lib/server/SocketStream.cpp b/lib/server/SocketStream.cpp index 6ef4b8d1..edb5e5b8 100644 --- a/lib/server/SocketStream.cpp +++ b/lib/server/SocketStream.cpp @@ -25,10 +25,24 @@ #include <ucred.h> #endif +#ifdef HAVE_BSD_UNISTD_H + #include <bsd/unistd.h> +#endif + +#ifdef HAVE_SYS_PARAM_H + #include <sys/param.h> +#endif + +#ifdef HAVE_SYS_UCRED_H + #include <sys/ucred.h> +#endif + +#include "autogen_ConnectionException.h" +#include "autogen_ServerException.h" #include "SocketStream.h" -#include "ServerException.h" #include "CommonException.h" #include "Socket.h" +#include "Utils.h" #include "MemLeakFindOn.h" @@ -162,25 +176,31 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port) 0 /* let OS choose protocol */); if(mSocketHandle == INVALID_SOCKET_VALUE) { - BOX_LOG_SOCKET_ERROR(Type, rName, Port, - "Failed to create a network socket"); - THROW_EXCEPTION(ServerException, SocketOpenError) + THROW_EXCEPTION_MESSAGE(ServerException, SocketOpenError, + BOX_SOCKET_ERROR_MESSAGE(Type, rName, Port, + "Failed to create a network socket")); } // Connect it if(::connect(mSocketHandle, &addr.sa_generic, addrLen) == -1) { // Dispose of the socket - BOX_LOG_SOCKET_ERROR(Type, rName, Port, - "Failed to connect to socket"); + try + { + THROW_EXCEPTION_MESSAGE(ServerException, SocketOpenError, + BOX_SOCKET_ERROR_MESSAGE(Type, rName, Port, + "Failed to connect to socket")); + } + catch(ServerException &e) + { #ifdef WIN32 - ::closesocket(mSocketHandle); + ::closesocket(mSocketHandle); #else // !WIN32 - ::close(mSocketHandle); + ::close(mSocketHandle); #endif // WIN32 - - mSocketHandle = INVALID_SOCKET_VALUE; - THROW_EXCEPTION(ConnectionException, Conn_SocketConnectError) + mSocketHandle = INVALID_SOCKET_VALUE; + throw; + } } ResetCounters(); @@ -199,7 +219,9 @@ void SocketStream::Open(Socket::Type Type, const std::string& rName, int Port) // -------------------------------------------------------------------------- int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) { - if(mSocketHandle == INVALID_SOCKET_VALUE) + CheckForMissingTimeout(Timeout); + + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, BadSocketHandle) } @@ -210,7 +232,7 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) p.fd = mSocketHandle; p.events = POLLIN; p.revents = 0; - switch(::poll(&p, 1, (Timeout == IOStream::TimeOutInfinite)?INFTIM:Timeout)) + switch(::poll(&p, 1, PollTimeout(Timeout, 0))) { case -1: // error @@ -256,7 +278,7 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) // Other error BOX_LOG_SYS_ERROR("Failed to read from socket"); THROW_EXCEPTION(ConnectionException, - Conn_SocketReadError); + SocketReadError); } } @@ -270,6 +292,41 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) return r; } +bool SocketStream::Poll(short Events, int Timeout) +{ + // Wait for data to send. + struct pollfd p; + p.fd = GetSocketHandle(); + p.events = Events; + p.revents = 0; + + box_time_t start = GetCurrentBoxTime(); + int result; + + do + { + result = ::poll(&p, 1, PollTimeout(Timeout, start)); + } + while(result == -1 && errno == EINTR); + + switch(result) + { + case -1: + // error - Bad! + THROW_SYS_ERROR("Failed to poll socket", ServerException, + SocketPollError); + break; + + case 0: + // Condition not met, timed out + return false; + + default: + // good to go! + return true; + } +} + // -------------------------------------------------------------------------- // // Function @@ -278,20 +335,21 @@ int SocketStream::Read(void *pBuffer, int NBytes, int Timeout) // Created: 2003/07/31 // // -------------------------------------------------------------------------- -void SocketStream::Write(const void *pBuffer, int NBytes) +void SocketStream::Write(const void *pBuffer, int NBytes, int Timeout) { - if(mSocketHandle == INVALID_SOCKET_VALUE) + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, BadSocketHandle) } - + // Buffer in byte sized type. ASSERT(sizeof(char) == 1); const char *buffer = (char *)pBuffer; - + // Bytes left to send int bytesLeft = NBytes; - + box_time_t start = GetCurrentBoxTime(); + while(bytesLeft > 0) { // Try to send. @@ -304,41 +362,30 @@ void SocketStream::Write(const void *pBuffer, int NBytes) { // Error. mWriteClosed = true; // assume can't write again - BOX_LOG_SYS_ERROR("Failed to write to socket"); - THROW_EXCEPTION(ConnectionException, - Conn_SocketWriteError); + THROW_SYS_ERROR("Failed to write to socket", + ConnectionException, SocketWriteError); } - + // Knock off bytes sent bytesLeft -= sent; // Move buffer pointer buffer += sent; mBytesWritten += sent; - + // Need to wait until it can send again? if(bytesLeft > 0) { - BOX_TRACE("Waiting to send data on socket " << + BOX_TRACE("Waiting to send data on socket " << mSocketHandle << " (" << bytesLeft << " of " << NBytes << " bytes left)"); - - // Wait for data to send. - struct pollfd p; - p.fd = mSocketHandle; - p.events = POLLOUT; - p.revents = 0; - - if(::poll(&p, 1, 16000 /* 16 seconds */) == -1) + + if(!Poll(POLLOUT, PollTimeout(Timeout, start))) { - // Don't exception if it's just a signal - if(errno != EINTR) - { - BOX_LOG_SYS_ERROR("Failed to poll " - "socket"); - THROW_EXCEPTION(ServerException, - SocketPollError) - } + THROW_EXCEPTION_MESSAGE(ConnectionException, + Protocol_Timeout, "Timed out waiting " + "to send " << bytesLeft << " of " << + NBytes << " bytes"); } } } @@ -354,7 +401,7 @@ void SocketStream::Write(const void *pBuffer, int NBytes) // -------------------------------------------------------------------------- void SocketStream::Close() { - if(mSocketHandle == INVALID_SOCKET_VALUE) + if(mSocketHandle == INVALID_SOCKET_VALUE) { THROW_EXCEPTION(ServerException, BadSocketHandle) } @@ -385,19 +432,19 @@ void SocketStream::Shutdown(bool Read, bool Write) { THROW_EXCEPTION(ServerException, BadSocketHandle) } - + // Do anything? if(!Read && !Write) return; - + int how = SHUT_RDWR; if(Read && !Write) how = SHUT_RD; if(!Read && Write) how = SHUT_WR; - + // Shut it down! if(::shutdown(mSocketHandle, how) == -1) { BOX_LOG_SYS_ERROR("Failed to shutdown socket"); - THROW_EXCEPTION(ConnectionException, Conn_SocketShutdownError) + THROW_EXCEPTION(ConnectionException, SocketShutdownError) } } @@ -478,8 +525,13 @@ bool SocketStream::GetPeerCredentials(uid_t &rUidOut, gid_t &rGidOut) if(::getsockopt(mSocketHandle, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == 0) { +#ifdef HAVE_STRUCT_UCRED_UID rUidOut = cred.uid; rGidOut = cred.gid; +#else // HAVE_STRUCT_UCRED_CR_UID + rUidOut = cred.cr_uid; + rGidOut = cred.cr_gid; +#endif return true; } @@ -509,3 +561,11 @@ bool SocketStream::GetPeerCredentials(uid_t &rUidOut, gid_t &rGidOut) return false; } +void SocketStream::CheckForMissingTimeout(int Timeout) +{ + if (Timeout == IOStream::TimeOutInfinite) + { + BOX_WARNING("Network operation started with no timeout!"); + DumpStackBacktrace(); + } +} |