#include <string.h>
#include <errno.h> // system call error numbers
#include <unistd.h> // for select call
#include <stdlib.h> // for calloc()
#include <errno.h>
#include <sys/time.h> // for struct timeval
#include "DSCThread.h" // for GetCurThreadRunState()
#include "DSTCPEndpoint.h"
#ifdef DSSERVERTCP
#include "CLog.h"
#endif
#include "SharedConsts.h" // for sComData
#pragma mark **** Class Methods ****
#pragma mark **** Instance Methods ****
void DSTCPEndpoint::InitBuffers ( void )
{
::memset(&mMySockAddr, 0, sizeof(mMySockAddr));
mRemoteHostIPString[0] = '\0';
::memset(&mRemoteSockAddr, 0, sizeof(mRemoteSockAddr));
try {
mErrorBuffer = new char [kTCPErrorBufferLen];
if ( mErrorBuffer == nil ) throw((sInt32)eMemoryAllocError);
}
catch( sInt32 err )
{
throw(err);
}
}
DSTCPEndpoint::DSTCPEndpoint ( const uInt32 inSessionID,
const uInt32 inOpenTimeout,
const uInt32 inRWTimeout ) :
mLogMsgSessionID(inSessionID),
mMyIPAddr (DSNetworkUtilities::GetOurIPAddress(0)),
mRemoteHostIPAddr (0),
mListenFD (0),
mConnectFD (0),
mErrorBuffer (NULL),
mAborting (false),
mWeHaveClosed (false),
mOpenTimeout (inOpenTimeout),
mRWTimeout (inRWTimeout),
mDefaultTimeout(inRWTimeout)
{
this->InitBuffers ();
}
DSTCPEndpoint::DSTCPEndpoint ( const DSTCPEndpoint *inEndpoint,
const uInt32 inSessionID) :
mLogMsgSessionID(inSessionID),
mMyIPAddr (inEndpoint->mMyIPAddr),
mRemoteHostIPAddr (inEndpoint->mRemoteHostIPAddr),
mListenFD (inEndpoint->mListenFD),
mConnectFD (inEndpoint->mConnectFD),
mErrorBuffer (NULL),
mAborting (false),
mWeHaveClosed (false),
mOpenTimeout (inEndpoint->mOpenTimeout),
mRWTimeout (inEndpoint->mRWTimeout),
mDefaultTimeout(inEndpoint->mDefaultTimeout)
{
this->InitBuffers ();
::memcpy(&mMySockAddr, &inEndpoint->mMySockAddr, sizeof (mMySockAddr));
::memcpy(mRemoteHostIPString, &inEndpoint->mRemoteHostIPString, sizeof (mRemoteHostIPString));
::memcpy(&mRemoteSockAddr, &inEndpoint->mRemoteSockAddr, sizeof (mRemoteSockAddr));
}
DSTCPEndpoint::~DSTCPEndpoint ( void )
{
try
{
if ( mWeHaveClosed == false )
{
DoTCPCloseSocket( mConnectFD );
}
}
catch( sInt32 err )
{
}
if ( mErrorBuffer != NULL )
{
delete [] mErrorBuffer;
mErrorBuffer = NULL;
}
}
sInt32 DSTCPEndpoint::ConnectTo ( const uInt32 inIPAddress, const uInt16 inPort )
{
int err = eDSNoErr;
int result = 0;
int sockfd;
int len = sizeof(struct sockaddr_in);
time_t timesUp;
struct sockaddr_in serverAddr;
int rc = eDSNoErr;
bool releaseZeroFD = false;
do {
sockfd = DoTCPOpenSocket();
if ( sockfd < 0 )
{
return( eDSTCPSendError );
}
mConnectFD = sockfd;
::memset( &serverAddr, 0, len );
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons( inPort ); serverAddr.sin_addr.s_addr = htonl( inIPAddress );
timesUp = ::time(NULL) + mOpenTimeout;
while ( ::time(NULL) < timesUp )
{
result = ::connect( mConnectFD, (struct sockaddr *)&serverAddr, len );
if ( mAborting == true )
{
return( kAbortedWarning );
}
if ( result == -1 )
{
err = errno;
switch ( err )
{
case ETIMEDOUT:
continue; break;
case ECONNREFUSED:
::memset(mErrorBuffer, 0, kTCPErrorBufferLen);
::strncpy(mErrorBuffer, ::strerror(err), kTCPErrorBufferLen);
LOG2( kStdErr, "TCP connect error (%d) %s.", err, mErrorBuffer );
LOG2( kStdErr, "ConnectTo: connect() error: %d, %s", err, mErrorBuffer );
return( eDSIPUnreachable );
break;
default: ::memset(mErrorBuffer, 0, kTCPErrorBufferLen);
::strncpy(mErrorBuffer, ::strerror(err), kTCPErrorBufferLen);
LOG2( kStdErr, "TCP connect error (%d) %s.", err, mErrorBuffer );
LOG2( kStdErr, "ConnectTo: connect() error: %d, %s", err, mErrorBuffer );
return( eDSTCPSendError );
break;
} }
else
{ if ( (sockfd != 0) && (releaseZeroFD) ) {
int rcSock = 0;
rcSock = ::close( 0 );
if ( rcSock == -1 )
{
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy( mErrorBuffer, ::strerror( err ), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPCloseSocket: close() on unused socket 0 failed with error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DoTCPCloseSocket: close() on unused socket 0 failed with error %d: %s", err, mErrorBuffer );
#endif
}
else
{
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "DoTCPCloseSocket: close() on unused socket 0" );
#else
LOG( kStdErr, "DoTCPCloseSocket: close() on unused socket 0" );
#endif
}
}
break;
}
}
if (sockfd == 0)
{
releaseZeroFD = true;
}
} while (sockfd == 0);
if ( result == 0 )
{
::memcpy(&mRemoteSockAddr, &serverAddr, len);
rc = this->SetSocketOption( mConnectFD, SO_NOSIGPIPE );
if ( rc != 0 )
{
return( eDSTCPSendError );
}
LOG2( kStdErr, "Established TCP connection to %d on port %d.", inIPAddress, inPort );
return(eDSNoErr);
}
else
{
LOG2( kStdErr, "Unable to connect to %d on port %d.", inIPAddress, inPort );
return(eDSServerTimeout);
}
}
void DSTCPEndpoint::ListenToPort ( const uInt16 inPort )
{
this->ListenToPortOnAddress( inPort, INADDR_ANY );
}
void DSTCPEndpoint::ListenToPortOnAddress ( const uInt16 inPort, const uInt32 inWhichAddress )
{
int rc = 0;
int sockfd;
::memset( &mMySockAddr, '\0', sizeof( mMySockAddr ) );
::memset( &mRemoteSockAddr, '\0', sizeof( mRemoteSockAddr ) );
mMySockAddr.sin_family = AF_INET;
mMySockAddr.sin_addr.s_addr = htonl( inWhichAddress );
mMySockAddr.sin_port = htons( inPort );
sockfd = this->DoTCPOpenSocket();
if ( sockfd < 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
mListenFD = sockfd;
rc = this->SetSocketOption( mListenFD, SO_REUSEADDR );
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
rc = this->SetSocketOption( mListenFD, SO_REUSEPORT );
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
rc = this->DoTCPBind();
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
rc = this->DoTCPListen();
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
}
Boolean DSTCPEndpoint::AcceptConnection ()
{
mConnectFD = 0;
return( (this->DoTCPAccept() == 0) );
}
void DSTCPEndpoint::SetTimeout ( const int inWhichTimeout, const int inSeconds )
{
switch (inWhichTimeout)
{
case kOpenTimeoutType:
mOpenTimeout = inSeconds;
break;
case kRWTimeoutType:
mRWTimeout = inSeconds;
break;
case kDefaultTimeoutType:
mDefaultTimeout = inSeconds;
break;
default:
break;
}
}
void DSTCPEndpoint::GetReverseAddressString ( char *ioBuffer,
const int inBufferLen) const
{
if ( ioBuffer != NULL )
{
::strncpy (ioBuffer, mRemoteHostIPString, inBufferLen);
}
}
Boolean DSTCPEndpoint::Connected ( void ) const
{
int bytesReadable = 0;
char temp[1];
if ( mAborting == true )
{
return false;
}
bytesReadable = ::recvfrom( mConnectFD, temp, sizeof (temp), (MSG_DONTWAIT | MSG_PEEK), NULL, NULL );
if ( bytesReadable == -1 )
{
switch ( errno )
{
case EAGAIN:
return true;
break;
default:
return false;
break;
}
}
if ( bytesReadable == 0 )
{
return( false );
}
return( true );
}
void DSTCPEndpoint::EncryptData ( void *inData, const uInt32 inBuffSize, void *&outData, uInt32 &outBuffSize )
{
outBuffSize = 0;
return;
}
void DSTCPEndpoint::DecryptData ( void *inData, const uInt32 inBuffSize, void *&outData, uInt32 &outBuffSize )
{
outBuffSize = 0;
return;
}
uInt32 DSTCPEndpoint::WriteData ( const void *inData, const uInt32 inSize )
{
struct timeval tvTimeout = { mRWTimeout, 0 };
const char *aPtr = (const char *) inData;
int err = eDSNoErr;
int rc = 0;
uInt32 dataSize = inSize;
uInt32 bytesWrote = 0;
fd_set aWriteSet;
while ( dataSize > 0 && aPtr != NULL )
{
struct timeval tvTimeoutTime;
::gettimeofday( &tvTimeoutTime, NULL );
tvTimeoutTime.tv_sec += mRWTimeout;
tvTimeout.tv_sec = mRWTimeout;
do {
FD_ZERO( &aWriteSet );
FD_SET( mConnectFD, &aWriteSet );
rc = ::select( mConnectFD+1, NULL, &aWriteSet, NULL, &tvTimeout );
if ( !mAborting && (rc == -1) && (EINTR == errno) )
{
struct timeval tvNow;
::gettimeofday( &tvNow, NULL );
timersub( &tvTimeoutTime, &tvNow, &tvTimeout );
if ( tvTimeout.tv_sec < 0 )
{
break;
}
}
} while ( !mAborting && (rc == -1) && (EINTR == errno) );
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
if ( rc == 0 )
{
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "WriteData(): select() timed out on %s", mRemoteHostIPString );
#else
LOG1( kStdErr, "WriteData(): select() timed out on %s", mRemoteHostIPString );
#endif
throw( (sInt32)kTimeoutError );
}
else if ( rc == -1 )
{
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "WriteData: select() error %d: %s on %A.\n", errno, ::strerror( errno ), mRemoteHostIPAddr );
#else
LOG3( kStdErr, "WriteData: select() error %d: %s on %A.\n", errno, ::strerror( errno ), mRemoteHostIPAddr );
#endif
throw( (sInt32)eDSTCPSendError);
}
else if ( FD_ISSET(mConnectFD, &aWriteSet) )
{
do
{
rc = ::sendto(mConnectFD, aPtr, dataSize, NULL, NULL, NULL);
if (mAborting == true)
{
throw((sInt32)kAbortedWarning);
}
} while ( (rc == -1) && (errno == EAGAIN) );
if ( rc == -1 )
{
err = errno;
::memset(mErrorBuffer, 0, kTCPErrorBufferLen);
::strncpy(mErrorBuffer, ::strerror(err), kTCPErrorBufferLen);
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "WriteData: select() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "WriteData: select() error %d: %s", err, mErrorBuffer );
#endif
throw( (sInt32)eDSTCPSendError);
}
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "WriteData(): sent %d bytes with endpoint %d and connectFD %d", rc, (uInt32)this, mConnectFD );
#else
LOG3( kStdErr, "WriteData(): sent %d bytes with endpoint %d and connectFD %d", rc, (uInt32)this, mConnectFD );
#endif
dataSize -= rc;
aPtr += rc;
bytesWrote += rc;
}
}
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "WriteData(): sent %d total bytes with endpoint %d and connectFD %d", bytesWrote, (uInt32)this, mConnectFD );
#else
LOG3( kStdErr, "WriteData(): sent %d total bytes with endpoint %d and connectFD %d", bytesWrote, (uInt32)this, mConnectFD );
#endif
return bytesWrote;
}
void DSTCPEndpoint::CloseConnection ( void )
{
if ( mConnectFD > 0 )
{
int err = this->DoTCPCloseSocket( mConnectFD );
if ( err == eDSNoErr )
{
mConnectFD = 0;
mWeHaveClosed = true;
}
}
}
int DSTCPEndpoint::CloseListener ( void )
{
int rc = 0;
if ( mListenFD > 0 )
{
rc = this->DoTCPCloseSocket( mListenFD );
if ( rc == eDSNoErr )
{
mListenFD = 0;
}
}
return rc;
}
inline void DSTCPEndpoint::Abort ( void )
{
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "Aborting a TCPEndpoint..." );
#else
LOG( kStdErr, "Aborting a TCPEndpoint..." );
#endif
mAborting = true;
this->CloseConnection();
}
int DSTCPEndpoint::DoTCPOpenSocket (void)
{
int err;
int sockfd;
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "Open socket." );
#else
LOG( kStdErr, "Open socket." );
#endif
sockfd = ::socket( AF_INET, SOCK_STREAM, 0 );
if ( sockfd == -1 )
{
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy( mErrorBuffer, ::strerror(err), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
ERRORLOG2( kLogTCPEndpoint, "Unable to open a socket. error %d: %s", err, mErrorBuffer );
DBGLOG2( kLogTCPEndpoint, "DoTCPOpenSocket: socket() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DoTCPOpenSocket: Unable to open a socket with error %d: %s", err, mErrorBuffer );
#endif
}
err = errno;
if (err != 0)
{
::strncpy( mErrorBuffer, ::strerror(err), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "DoTCPOpenSocket: socket error %d: %s with sockfd %d", err, mErrorBuffer, sockfd );
#else
LOG3( kStdErr, "DoTCPOpenSocket: socket error %d: %s with sockfd %d", err, mErrorBuffer, sockfd );
#endif
}
return( sockfd );
}
int DSTCPEndpoint::SetSocketOption ( const int inSocket, const int inSocketOption )
{
int rc = 0;
int err = 0;
int val = 1;
int len = sizeof(val);
if ( inSocket != 0 )
{
if ( (inSocket != mListenFD) && (inSocket != mConnectFD) )
{
#ifdef DSSERVERTCP
ERRORLOG1( kLogTCPEndpoint, "SetSocketOption: invalid socket: %d", inSocket );
#else
LOG1( kStdErr, "SetSocketOption: invalid socket: %d", inSocket );
#endif
return( -1 );
}
rc = ::setsockopt( inSocket, SOL_SOCKET, inSocketOption, &val, len );
if ( rc != 0 )
{
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy( mErrorBuffer, ::strerror( errno ), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
ERRORLOG2( kLogTCPEndpoint, "Unable to set socket option: Message: \"%s\", Error: %d", mErrorBuffer, err );
DBGLOG2( kLogTCPEndpoint, "Unable to set socket option: Message: \"%s\", Error: %d", mErrorBuffer, err );
#else
LOG2( kStdErr, "Unable to set socket option: Message: \"%s\", Error: %d", mErrorBuffer, err );
#endif
}
}
return( 0 );
}
int DSTCPEndpoint::DoTCPBind ( void )
{
int err = eDSNoErr;
volatile int rc = 0;
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
rc = ::bind( mListenFD, (struct sockaddr *)&mMySockAddr, sizeof(mMySockAddr) );
if ( rc != 0 )
{
err = errno;
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
::strncpy( mErrorBuffer, ::strerror( err ), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DSTCPEndpoint: bind() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DSTCPEndpoint: bind() error %d: %s", err, mErrorBuffer );
#endif
}
return( err );
}
int DSTCPEndpoint::DoTCPListen ( void )
{
int err = eDSNoErr;
int rc;
rc = ::listen( mListenFD, kTCPMaxListenBackLog );
if ( rc == -1 )
{
if ( mAborting == true )
{
return( rc );
}
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy(mErrorBuffer, ::strerror(err), kTCPErrorBufferLen);
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPListen: listen() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DoTCPListen: listen() error %d: %s", err, mErrorBuffer );
#endif
}
return (err);
}
int DSTCPEndpoint::DoTCPAccept ( void )
{
int err = eDSNoErr;
int aLen = sizeof( mRemoteSockAddr );
int rc = eDSNoErr;
fd_set readSet;
do {
FD_ZERO( &readSet );
FD_SET( mListenFD, &readSet );
rc = ::select( mListenFD + 1, &readSet, NULL, NULL, NULL );
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
if ( rc == -1 )
{
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPAccept: select() returned error %d: %s\n", errno, ::strerror( errno ) );
#else
LOG2( kStdErr, "DoTCPAccept: select() returned error %d: %s\n", errno, ::strerror( errno ) );
#endif
if ( errno != EINTR )
{
throw( (sInt32)eDSTCPReceiveError );
}
FD_CLR( mListenFD, &readSet );
}
} while ( !FD_ISSET( mListenFD, &readSet ) );
mConnectFD = ::accept( mListenFD, (struct sockaddr *)&mRemoteSockAddr, &aLen );
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
if ( mConnectFD == -1 )
{
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPAccept: select error %d: %s", errno, ::strerror( err ) );
#else
LOG2( kStdErr, "DoTCPAccept: select error %d: %s", errno, ::strerror( err ) );
#endif
throw( (sInt32)eDSTCPReceiveError );
}
rc = this->SetSocketOption( mListenFD, SO_KEEPALIVE );
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
rc = this->SetSocketOption( mListenFD, SO_NOSIGPIPE );
if ( rc != 0 )
{
throw( (sInt32)eDSTCPReceiveError );
}
if ( err == eDSNoErr )
{
mRemoteHostIPAddr = ntohl( mRemoteSockAddr.sin_addr.s_addr );
DSNetworkUtilities::IPAddrToString( mRemoteHostIPAddr, mRemoteHostIPString, MAXIPADDRSTRLEN );
}
return( err );
}
int DSTCPEndpoint::DoTCPCloseSocket ( const int inSockFD )
{
int err = eDSNoErr;
int rc = 0;
if ( inSockFD <= 0 )
{
return( eDSNoErr );
}
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "Close socket." );
#endif
rc = ::close( inSockFD );
if ( rc == -1 )
{
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy( mErrorBuffer, ::strerror( err ), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "DoTCPCloseSocket: close() on socket %d failed with error %d: %s", inSockFD, err, mErrorBuffer );
#else
LOG3( kStdErr, "DoTCPCloseSocket: close() on socket %d failed with error %d: %s", inSockFD, err, mErrorBuffer );
#endif
}
return( err );
}
uInt32 DSTCPEndpoint::DoTCPRecvFrom ( void *ioBuffer, const uInt32 inBufferSize )
{
int rc;
int err;
int bytesRead = 0;
fd_set readSet;
struct timeval tvTimeout = { mRWTimeout, 0 };
struct timeval tvTimeoutTime = { mRWTimeout, 0 };
time_t timeoutTime;
timeoutTime = ::time( NULL ) + mRWTimeout;
::gettimeofday (&tvTimeoutTime, NULL);
tvTimeoutTime.tv_sec += mRWTimeout;
do {
FD_ZERO( &readSet );
FD_SET( mConnectFD, &readSet );
rc = ::select( mConnectFD+1, &readSet, NULL, NULL, &tvTimeout );
if ( !mAborting && (rc == -1) && (EINTR == errno) )
{
struct timeval tvNow;
::gettimeofday( &tvNow, NULL );
timersub( &tvTimeoutTime, &tvNow, &tvTimeout );
if ( tvTimeout.tv_sec < 0 )
{
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "DoTCPRecvFrom: connection timeout?" );
#else
LOG( kStdErr, "DoTCPRecvFrom: connection timeout?" );
#endif
throw( (sInt32)eDSTCPReceiveError );
}
}
} while ( !mAborting && (rc == -1) && (EINTR == errno) );
if ( mAborting == true )
{
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "DSTCPEndpoint::DoTCPRecvFrom(): We have been aborted." );
#else
LOG( kStdErr, "DSTCPEndpoint::DoTCPRecvFrom(): We have been aborted." );
#endif
throw( (sInt32)kAbortedWarning );
}
if ( rc == 0 )
{
#ifdef DSSERVERTCP
DBGLOG( kLogTCPEndpoint, "DoTCPRecvFrom: timed out waiting for response." );
#else
LOG( kStdErr, "DoTCPRecvFrom: timed out waiting for response." );
#endif
throw( (sInt32)kTimeoutError );
}
else if ( rc == -1 )
{
err = errno;
::memset(mErrorBuffer, 0, kTCPErrorBufferLen);
::strncpy(mErrorBuffer, ::strerror(err), kTCPErrorBufferLen);
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPRecvFrom: select() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DoTCPRecvFrom: select() error %d: %s", err, mErrorBuffer );
#endif
throw((sInt32)eDSTCPReceiveError);
}
else if ( FD_ISSET(mConnectFD, &readSet) )
{
do
{
bytesRead = ::recvfrom( mConnectFD, ioBuffer, inBufferSize, MSG_WAITALL, NULL, NULL );
if ( mAborting == true )
{
throw( (sInt32)kAbortedWarning );
}
} while ( (bytesRead == -1) && (errno == EAGAIN) );
if ( bytesRead == 0 )
{
err = errno;
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "DoTCPRecvFrom: connection closed by peer - error is %d", err );
#else
LOG1( kStdErr, "DoTCPRecvFrom: connection closed by peer - error is %d", err );
#endif
throw( (sInt32)eDSTCPReceiveError );
}
else if ( bytesRead == -1 )
{
::memset( mErrorBuffer, 0, kTCPErrorBufferLen );
err = errno;
::strncpy( mErrorBuffer, ::strerror(err), kTCPErrorBufferLen );
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "DoTCPRecvFrom: recvfrom error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "DoTCPRecvFrom: recvfrom error %d: %s", err, mErrorBuffer );
#endif
throw( (sInt32)eDSTCPReceiveError );
}
else
{
#ifdef DSSERVERTCP
DBGLOG3( kLogTCPEndpoint, "DoTCPRecvFrom(): received %d bytes with endpoint %d and connectFD %d", bytesRead, (uInt32)this, mConnectFD );
#else
LOG3( kStdErr, "DoTCPRecvFrom(): received %d bytes with endpoint %d and connectFD %d", bytesRead, (uInt32)this, mConnectFD );
#endif
}
}
return( (uInt32)bytesRead );
}
void * DSTCPEndpoint::GetClientMessage ( void )
{
sComData *pOutMsg = nil;
void *tmpOutMsg = nil;
uInt32 buffLen = 0;
uInt32 readBytes = 0;
sInt32 siResult = eDSNoErr;
void *inBuffer = nil;
uInt32 inLength = 0;
siResult = SyncToMessageBody(true, &inLength);
if ( (siResult == eDSNoErr) && (inLength != 0) )
{
inBuffer = (void *) calloc(1, inLength);
if (inBuffer != nil)
{
try
{
readBytes = DoTCPRecvFrom(inBuffer, inLength);
if (readBytes != inLength)
{
#ifdef DSSERVERTCP
ERRORLOG( kLogTCPEndpoint, "GetClientMessage: Couldn't read entire message block" );
#endif
free(inBuffer);
inBuffer = nil;
}
else
{
DecryptData(inBuffer, inLength, tmpOutMsg, buffLen);
pOutMsg = (sComData *) tmpOutMsg;
if (buffLen == 0)
{
pOutMsg = (sComData *)inBuffer;
inBuffer = nil;
buffLen = inLength;
}
if (pOutMsg != nil)
{
if (pOutMsg->fDataSize > buffLen - sizeof(sComData))
{
free(pOutMsg);
pOutMsg = nil;
}
}
}
}
catch( sInt32 err )
{
if (pOutMsg != nil)
{
free(pOutMsg);
pOutMsg = nil;
}
siResult = eDSTCPReceiveError; }
free(inBuffer);
inBuffer = nil;
} }
return( pOutMsg );
}
sInt32 DSTCPEndpoint::SyncToMessageBody(const Boolean inStripLeadZeroes, uInt32 *outBuffLen)
{
uInt32 index = 0;
uInt32 readBytes = 0;
uInt32 newLen = 0;
uInt32 curIndex = kDSTCPEndpointMessageTagSize;
char *ourBuffer;
uInt32 buffLen = 0;
sInt32 result = eDSNoErr;
ourBuffer = (char *) calloc(kDSTCPEndpointMaxMessageSize, 1);
try
{
readBytes = DoTCPRecvFrom(ourBuffer, kDSTCPEndpointMessageTagSize);
if (readBytes != kDSTCPEndpointMessageTagSize)
{
free(ourBuffer);
*outBuffLen = 0;
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "SyncToMessageBody: attempted read of %d bytes failed with %d bytes read", kDSTCPEndpointMessageTagSize, readBytes );
#else
LOG2( kStdErr, "SyncToMessageBody: attempted read of %d bytes failed with %d bytes read", kDSTCPEndpointMessageTagSize, readBytes );
#endif
return eDSTCPReceiveError;
}
}
catch( sInt32 err )
{
if (ourBuffer != nil)
{
free(ourBuffer);
}
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "SyncToMessageBody: attempted read of %d bytes failed in DoTCPRecvFrom with error %d", kDSTCPEndpointMessageTagSize, err );
#else
LOG2( kStdErr, "SyncToMessageBody: attempted read of %d bytes failed in DoTCPRecvFrom with error %d", kDSTCPEndpointMessageTagSize, err );
#endif
return eDSTCPReceiveError;
}
if (inStripLeadZeroes)
{
for ( index=0; (index < kDSTCPEndpointMessageTagSize) && (ourBuffer[index] == 0x00); index++ )
{
readBytes--;
}
try
{
while ( (readBytes < kDSTCPEndpointMessageTagSize) && (curIndex < kDSTCPEndpointMaxMessageSize) )
{
newLen = DoTCPRecvFrom(ourBuffer+curIndex, 1);
if (newLen != 1)
{
free(ourBuffer);
*outBuffLen = 0;
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "SyncToMessageBody: align frame by skipping leading zeroes - attempted read of one byte failed with %d bytes read", newLen );
#else
LOG1( kStdErr, "SyncToMessageBody: align frame by skipping leading zeroes - attempted read of one byte failed with %d bytes read", newLen );
#endif
return eDSTCPReceiveError;
}
if (ourBuffer[curIndex] != 0x00)
{
readBytes++;
}
curIndex++;
}
}
catch( sInt32 err )
{
if (ourBuffer != nil)
{
free(ourBuffer);
}
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "SyncToMessageBody: align frame by skipping leading zeroes - failed in DoTCPRecvFrom with error %l", err );
#else
LOG1( kStdErr, "SyncToMessageBody: align frame by skipping leading zeroes - failed in DoTCPRecvFrom with error %l", err );
#endif
return eDSTCPReceiveError;
}
}
if ( (readBytes == kDSTCPEndpointMessageTagSize) && (strncmp(ourBuffer+curIndex-kDSTCPEndpointMessageTagSize,"DSPX",kDSTCPEndpointMessageTagSize) == 0) )
{
try
{
newLen = DoTCPRecvFrom(&buffLen , 4);
if (newLen != 4) {
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "SyncToMessageBody: get the buffer length - attempted read of four bytes failed with %d bytes read", newLen );
#else
LOG1( kStdErr, "SyncToMessageBody: get the buffer length - attempted read of four bytes failed with %d bytes read", newLen );
#endif
*outBuffLen = 0;
}
else
{
*outBuffLen = buffLen;
}
}
catch( sInt32 err )
{
if (ourBuffer != nil)
{
free(ourBuffer);
}
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "SyncToMessageBody: get the buffer length - failed in DoTCPRecvFrom with error %l", err );
#else
LOG1( kStdErr, "SyncToMessageBody: get the buffer length - failed in DoTCPRecvFrom with error %l", err );
#endif
return eDSTCPReceiveError;
}
}
free(ourBuffer);
return result;
}
sInt32 DSTCPEndpoint::SendClientReply ( void *inMsg )
{
return SendBuffer(inMsg, sizeof(sComData) + ((sComData *)inMsg)->fDataSize);
}
sInt32 DSTCPEndpoint::SendServerMessage ( void *inMsg )
{
return SendBuffer(inMsg, sizeof(sComData) + ((sComData *)inMsg)->fDataSize);
}
sInt32 DSTCPEndpoint::SendBuffer ( void *inBuffer, uInt32 inLength )
{
sInt32 result = eDSNoErr;
char *sendBuffer = nil;
uInt32 dataBuffLen = 0;
uInt32 sendBuffLen = 0;
uInt32 sentBytes = 0;
void *outBuffer = nil;
uInt32 outLength = 0;
bool bFreeOutBuff= true;
EncryptData(inBuffer, inLength, outBuffer, outLength);
if (outLength == 0)
{
outBuffer = inBuffer;
outLength = inLength;
bFreeOutBuff = false;
}
dataBuffLen = outLength;
sendBuffLen = kDSTCPEndpointMessageTagSize + 4 + dataBuffLen;
sendBuffer = (char *)calloc(sendBuffLen, 1);
strcpy(sendBuffer,"DSPX");
memcpy(sendBuffer+kDSTCPEndpointMessageTagSize, &dataBuffLen, 4);
memcpy(sendBuffer+kDSTCPEndpointMessageTagSize+4, outBuffer, outLength);
try
{
sentBytes = WriteData(sendBuffer, sendBuffLen);
if (sentBytes != sendBuffLen)
{
#ifdef DSSERVERTCP
DBGLOG2( kLogTCPEndpoint, "SendBuffer(): attempted send of %d bytes only sent %d bytes", sendBuffLen, sentBytes );
#else
LOG2( kStdErr, "SendBuffer(): attempted send of %d bytes only sent %d bytes", sendBuffLen, sentBytes );
#endif
result = eDSTCPSendError;
}
}
catch( sInt32 err )
{
#ifdef DSSERVERTCP
DBGLOG1( kLogTCPEndpoint, "SendBuffer(): failed send of %d bytes", sendBuffLen );
#else
LOG1( kStdErr, "SendBuffer(): failed send of %d bytes", sendBuffLen );
#endif
result = eDSTCPSendError;
}
if (sendBuffer != NULL)
{
free(sendBuffer);
sendBuffer = NULL;
}
if (bFreeOutBuff)
{
if (outBuffer != NULL)
{
free(outBuffer);
outBuffer = NULL;
}
}
return( result );
}
sInt32 DSTCPEndpoint::GetServerReply ( sComData **outMsg )
{
sInt32 siResult = eDSNoErr;
uInt32 buffLen = 0;
uInt32 readBytes = 0;
void *inBuffer = nil;
uInt32 inLength = 0;
siResult = SyncToMessageBody(true, &inLength);
if ( (siResult == eDSNoErr) && (inLength != 0) )
{
try
{
inBuffer = (void *)calloc(1,inLength);
readBytes = DoTCPRecvFrom(inBuffer, inLength);
if (readBytes != inLength)
{
LOG( kStdErr, "GetServerReply: Couldn't read entire message block" );
siResult = eDSTCPReceiveError;
}
else
{
void *tmpOutMsg = nil;
DecryptData(inBuffer, inLength, tmpOutMsg, buffLen);
*outMsg = (sComData *)tmpOutMsg;
if (buffLen == 0)
{
free(*outMsg);
*outMsg = (sComData *)inBuffer;
inBuffer = nil;
buffLen = inLength;
}
}
}
catch( sInt32 err )
{
siResult = eDSTCPReceiveError;
}
}
if (inBuffer != nil)
{
free(inBuffer);
inBuffer = nil;
}
return( siResult );
}
uInt32 DSTCPEndpoint::GetRemoteHostIPAddress ( void )
{
return mRemoteHostIPAddr;
}
uInt16 DSTCPEndpoint::GetRemoteHostPort ( void )
{
return ( ntohs( mRemoteSockAddr.sin_port ) );
}