summaryrefslogtreecommitdiff
path: root/lib/server/SocketStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/server/SocketStream.cpp')
-rw-r--r--lib/server/SocketStream.cpp152
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();
+ }
+}