#include <string.h>
#include <errno.h> // system call error numbers
#include <unistd.h> // for select call
#include <stdlib.h> // for calloc()
#include <poll.h>
#include <sys/time.h> // for struct timeval
#include <machine/byte_order.h>
#include "DSCThread.h" // for GetCurThreadRunState()
#include "DSTCPEndpoint.h"
#ifdef DSSERVERTCP
#include "CLog.h"
#endif
#include "SharedConsts.h" // for sComData
#include "DirServicesConst.h"
#include "DSTCPEndian.h"
#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
DbgLog( 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
{
struct pollfd fdToPoll;
int result;
if ( mAborting == true )
{
return false;
}
if ( mConnectFD == -1 )
return false;
fdToPoll.fd = mConnectFD;
fdToPoll.events = POLLSTANDARD;
fdToPoll.revents = 0;
result = poll( &fdToPoll, 1, 0 );
if ( result == -1 )
return false;
return ( (fdToPoll.revents & POLLHUP) == 0 );
}
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
DbgLog( 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
DbgLog( 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, 0, NULL, 0);
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
DbgLog( kLogTCPEndpoint, "WriteData: select() error %d: %s", err, mErrorBuffer );
#else
LOG2( kStdErr, "WriteData: select() error %d: %s", err, mErrorBuffer );
#endif
throw( (SInt32)eDSTCPSendError);
}
#ifdef DSSERVERTCP
DbgLog( 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
DbgLog( 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
ErrLog( kLogTCPEndpoint, "Unable to open a socket. error %d: %s", err, mErrorBuffer );
DbgLog( 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
DbgLog( 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
ErrLog( 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
ErrLog( kLogTCPEndpoint, "Unable to set socket option: Message: \"%s\", Error: %d", mErrorBuffer, err );
DbgLog( 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
DbgLog( 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
DbgLog( 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;
socklen_t 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
DbgLog( 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, (socklen_t*)&aLen );
if ( mAborting == true )
{
throw( (SInt32)kAbortedWarning );
}
if ( mConnectFD == -1 )
{
#ifdef DSSERVERTCP
DbgLog( 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
DbgLog( 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
DbgLog( 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
DbgLog( 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
DbgLog( 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
DbgLog( 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;
sComProxyData *pOutProxyMsg = 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
ErrLog( kLogTCPEndpoint, "GetClientMessage: Couldn't read entire message block" );
#endif
free(inBuffer);
inBuffer = nil;
}
else
{
DecryptData(inBuffer, inLength, tmpOutMsg, buffLen);
pOutProxyMsg = (sComProxyData *) tmpOutMsg;
if (buffLen == 0)
{
pOutProxyMsg= (sComProxyData *)inBuffer;
inBuffer = nil;
buffLen = inLength;
}
if (pOutProxyMsg != nil)
{
if (NXSwapBigIntToHost(pOutProxyMsg->fDataSize) > buffLen - sizeof(sComProxyData))
{
free(pOutProxyMsg);
pOutProxyMsg = nil;
}
}
}
}
catch( SInt32 err )
{
if (pOutProxyMsg != nil)
{
free(pOutProxyMsg);
pOutProxyMsg = nil;
}
siResult = eDSTCPReceiveError; }
free(inBuffer);
inBuffer = nil;
} }
#ifndef __BIG_ENDIAN__
DSTCPEndian swapper(pOutProxyMsg, kDSSwapToHost);
swapper.AddIPAndPort( mRemoteHostIPAddr, ntohs( mRemoteSockAddr.sin_port ));
swapper.SwapMessage();
#endif
pOutMsg = AllocFromProxyStruct( pOutProxyMsg );
if (pOutProxyMsg != nil)
{
free(pOutProxyMsg);
pOutProxyMsg = 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
DbgLog( 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
DbgLog( 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
DbgLog( 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
DbgLog( 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
DbgLog( 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 = NXSwapBigIntToHost(buffLen);
}
}
catch( SInt32 err )
{
if (ourBuffer != nil)
{
free(ourBuffer);
}
#ifdef DSSERVERTCP
DbgLog( 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 )
{
UInt32 messageSize = 0;
sComProxyData *inProxyMsg = nil;
SInt32 sendResult = eDSNoErr;
inProxyMsg = AllocToProxyStruct( (sComData *)inMsg );
inProxyMsg->fDataSize = inProxyMsg->fDataLength;
messageSize = sizeof(sComProxyData) + inProxyMsg->fDataLength;
#ifndef __BIG_ENDIAN__
DSTCPEndian swapper(inProxyMsg, kDSSwapToBig);
swapper.AddIPAndPort( mRemoteHostIPAddr, ntohs( mRemoteSockAddr.sin_port ));
swapper.SwapMessage();
#endif
sendResult = SendBuffer(inProxyMsg, messageSize);
free(inProxyMsg);
inProxyMsg = nil;
return(sendResult);
}
SInt32 DSTCPEndpoint::SendServerMessage ( void *inMsg )
{
UInt32 messageSize = 0;
sComProxyData *inProxyMsg = nil;
SInt32 sendResult = eDSNoErr;
inProxyMsg = AllocToProxyStruct( (sComData *)inMsg );
inProxyMsg->fDataSize = inProxyMsg->fDataLength;
messageSize = sizeof(sComProxyData) + inProxyMsg->fDataLength;
#ifndef __BIG_ENDIAN__
DSTCPEndian swapper(inProxyMsg, kDSSwapToBig);
swapper.SwapMessage();
#endif
sendResult = SendBuffer(inProxyMsg, messageSize);
free(inProxyMsg);
inProxyMsg = nil;
return(sendResult);
}
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");
*(SInt32*)(sendBuffer+kDSTCPEndpointMessageTagSize) = NXSwapHostIntToBig(dataBuffLen);
memcpy(sendBuffer+kDSTCPEndpointMessageTagSize+4, outBuffer, outLength);
try
{
sentBytes = WriteData(sendBuffer, sendBuffLen);
if (sentBytes != sendBuffLen)
{
#ifdef DSSERVERTCP
DbgLog( 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
DbgLog( 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;
sComProxyData *outProxyMsg = nil;
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);
outProxyMsg = (sComProxyData *)tmpOutMsg;
if (buffLen == 0)
{
free(outProxyMsg);
outProxyMsg = (sComProxyData *)inBuffer;
inBuffer = nil;
buffLen = inLength;
}
}
}
catch( SInt32 err )
{
siResult = eDSTCPReceiveError;
}
}
if (inBuffer != nil)
{
free(inBuffer);
inBuffer = nil;
}
if (outProxyMsg != nil)
{
#ifndef __BIG_ENDIAN__
DSTCPEndian swapper(outProxyMsg, kDSSwapToHost);
swapper.SwapMessage();
#endif
*outMsg = AllocFromProxyStruct( outProxyMsg );
free(outProxyMsg);
outProxyMsg = nil;
}
return( siResult );
}
UInt32 DSTCPEndpoint::GetRemoteHostIPAddress ( void )
{
return mRemoteHostIPAddr;
}
UInt16 DSTCPEndpoint::GetRemoteHostPort ( void )
{
return ( ntohs( mRemoteSockAddr.sin_port ) );
}
sComProxyData* DSTCPEndpoint::AllocToProxyStruct ( sComData *inDataMsg )
{
sComProxyData *outProxyDataMsg = nil;
int objIndex;
if (inDataMsg != nil)
{
outProxyDataMsg = (sComProxyData *)calloc( 1, sizeof(sComProxyData) + inDataMsg->fDataSize );
bcopy( inDataMsg, outProxyDataMsg, (char *)(outProxyDataMsg->obj) - (char *)outProxyDataMsg );
bcopy( inDataMsg->obj, outProxyDataMsg->obj, kObjSize + inDataMsg->fDataSize );
for ( objIndex = 0; objIndex < 10; objIndex++ )
{
if ( outProxyDataMsg->obj[ objIndex ].offset != 0 )
{
outProxyDataMsg->obj[ objIndex ].offset -= sizeof(sComData) - sizeof(sComProxyData);
}
}
}
return ( outProxyDataMsg );
}
sComData* DSTCPEndpoint::AllocFromProxyStruct ( sComProxyData *inProxyDataMsg )
{
sComData *outDataMsg = nil;
int objIndex;
if (inProxyDataMsg != nil)
{
outDataMsg = (sComData *)calloc( 1, sizeof(sComData) + inProxyDataMsg->fDataSize );
bcopy( inProxyDataMsg, outDataMsg, (char *)(inProxyDataMsg->obj) - (char *)inProxyDataMsg );
bcopy( inProxyDataMsg->obj, outDataMsg->obj, kObjSize + inProxyDataMsg->fDataSize );
for ( objIndex = 0; objIndex < 10; objIndex++ )
{
if ( outDataMsg->obj[ objIndex ].offset != 0 )
{
outDataMsg->obj[ objIndex ].offset += sizeof(sComData) - sizeof(sComProxyData);
}
}
outDataMsg->fUID = outDataMsg->fEffectiveUID = (uid_t) -2;
}
return ( outDataMsg );
}