/*
* Copyright 2007 Stephen Liu
* For license terms, see the file COPYING along with this library.
*/
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "sptunnelimpl.hpp"
#include "sprequest.hpp"
#include "spresponse.hpp"
#include "spbuffer.hpp"
#include "spmsgblock.hpp"
#include "spdispatcher.hpp"
class SP_MutexGuard {
public:
SP_MutexGuard( pthread_mutex_t * mutex ) {
mMutex = mutex;
pthread_mutex_lock( mMutex );
}
~SP_MutexGuard() { pthread_mutex_unlock( mMutex ); }
private:
pthread_mutex_t * mMutex;
};
SP_TunnelArg * SP_TunnelArg :: create()
{
return new SP_TunnelArg();
}
SP_TunnelArg :: SP_TunnelArg()
{
pthread_mutex_init( &mMutex, NULL );
mRefCount = 1;
mTunnelStatus = mBackendStatus = eCreate;
memset( &mTunnelSid, 0, sizeof( SP_Sid_t ) );
memset( &mBackendSid, 0, sizeof( SP_Sid_t ) );
}
SP_TunnelArg :: ~SP_TunnelArg()
{
pthread_mutex_destroy( &mMutex );
}
void SP_TunnelArg :: setTunnelStatus( int status )
{
SP_MutexGuard gurad( &mMutex );
mTunnelStatus = status;
}
int SP_TunnelArg :: getTunnelStatus()
{
SP_MutexGuard gurad( &mMutex );
return mTunnelStatus;
}
void SP_TunnelArg :: setTunnelSid( SP_Sid_t sid )
{
SP_MutexGuard gurad( &mMutex );
mTunnelSid = sid;
}
SP_Sid_t SP_TunnelArg :: getTunnelSid()
{
SP_MutexGuard gurad( &mMutex );
return mTunnelSid;
}
void SP_TunnelArg :: setBackendStatus( int status )
{
SP_MutexGuard gurad( &mMutex );
mBackendStatus = status;
}
int SP_TunnelArg :: getBackendStatus()
{
SP_MutexGuard gurad( &mMutex );
return mBackendStatus;
}
void SP_TunnelArg :: setBackendSid( SP_Sid_t sid )
{
SP_MutexGuard gurad( &mMutex );
mBackendSid = sid;
}
SP_Sid_t SP_TunnelArg :: getBackendSid()
{
SP_MutexGuard gurad( &mMutex );
return mBackendSid;
}
void SP_TunnelArg :: addRef()
{
SP_MutexGuard gurad( &mMutex );
mRefCount++;
}
void SP_TunnelArg :: release()
{
int refCount = 1;
pthread_mutex_lock( &mMutex );
mRefCount--;
refCount = mRefCount;
pthread_mutex_unlock( &mMutex );
if( refCount <= 0 ) delete this;
}
//---------------------------------------------------------
SP_TunnelDecoder :: SP_TunnelDecoder()
{
mBuffer = NULL;
}
SP_TunnelDecoder :: ~SP_TunnelDecoder()
{
if( NULL != mBuffer ) delete mBuffer;
mBuffer = NULL;
}
int SP_TunnelDecoder :: decode( SP_Buffer * inBuffer )
{
if( inBuffer->getSize() > 0 ) {
if( NULL != mBuffer ) {
mBuffer->append( inBuffer );
inBuffer->reset();
} else {
mBuffer = inBuffer->take();
}
}
int ret = SP_MsgDecoder::eMoreData;
if( NULL != mBuffer && mBuffer->getSize() > 0 ) ret = SP_MsgDecoder::eOK;
return ret;
}
SP_Buffer * SP_TunnelDecoder :: getBuffer()
{
return mBuffer;
}
SP_Buffer * SP_TunnelDecoder :: takeBuffer()
{
SP_Buffer * buffer = mBuffer;
mBuffer = NULL;
return buffer;
}
//---------------------------------------------------------
SP_BackendHandler :: SP_BackendHandler( SP_TunnelArg * tunnelArg )
{
mArg = tunnelArg;
}
SP_BackendHandler :: ~SP_BackendHandler()
{
mArg->release();
}
int SP_BackendHandler :: start( SP_Request * request, SP_Response * response )
{
mArg->setBackendSid( response->getFromSid() );
mArg->setBackendStatus( SP_TunnelArg::eNormal );
request->setMsgDecoder( new SP_TunnelDecoder() );
return 0;
}
int SP_BackendHandler :: handle( SP_Request * request, SP_Response * response )
{
SP_TunnelDecoder * decoder = (SP_TunnelDecoder*)request->getMsgDecoder();
SP_Buffer * buffer = decoder->takeBuffer();
SP_Message * msg = new SP_Message();
msg->getToList()->add( mArg->getTunnelSid() );
msg->getFollowBlockList()->append( new SP_BufferMsgBlock( buffer, 1 ) );
response->addMessage( msg );
return SP_TunnelArg::eNormal == mArg->getTunnelStatus() ? 0 : -1;
}
void SP_BackendHandler :: error( SP_Response * response )
{
mArg->setBackendStatus( SP_TunnelArg::eDestroy );
}
void SP_BackendHandler :: timeout( SP_Response * response )
{
mArg->setBackendStatus( SP_TunnelArg::eDestroy );
}
void SP_BackendHandler :: close()
{
mArg->setBackendStatus( SP_TunnelArg::eDestroy );
}
//---------------------------------------------------------
SP_TunnelHandler :: SP_TunnelHandler( SP_Dispatcher * dispatcher,
const char * dstHost, int dstPort )
{
mDispatcher = dispatcher;
mArg = SP_TunnelArg::create();
mMsgBlockList = new SP_MsgBlockList();
snprintf( mHost, sizeof( mHost ), "%s", dstHost );
mPort = dstPort;
}
SP_TunnelHandler :: ~SP_TunnelHandler()
{
mArg->release();
mArg = NULL;
delete mMsgBlockList;
mMsgBlockList = NULL;
}
int SP_TunnelHandler :: start( SP_Request * request, SP_Response * response )
{
mArg->setTunnelSid( response->getFromSid() );
mArg->setTunnelStatus( SP_TunnelArg::eNormal );
request->setMsgDecoder( new SP_TunnelDecoder() );
int ret = 0;
int socketFd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );
if( socketFd >= 0 ) {
struct sockaddr_in inAddr;
inAddr.sin_family = AF_INET;
inAddr.sin_addr.s_addr = inet_addr( mHost );
inAddr.sin_port = htons( mPort );
ret = connect( socketFd, (struct sockaddr*)&inAddr, sizeof( inAddr ) );
if( 0 == ret ) {
mArg->addRef();
mDispatcher->push( socketFd, new SP_BackendHandler( mArg ) );
} else {
syslog( LOG_WARNING, "Cannot connect to %s:%d", mHost, mPort );
::close( socketFd );
}
} else {
ret = -1;
syslog( LOG_WARNING, "Cannot open socket, errno %d, %s",
errno, strerror( errno ) );
}
return ret;
}
int SP_TunnelHandler :: handle( SP_Request * request, SP_Response * response )
{
SP_TunnelDecoder * decoder = (SP_TunnelDecoder*)request->getMsgDecoder();
SP_Buffer * buffer = decoder->takeBuffer();
if( SP_TunnelArg::eCreate == mArg->getBackendStatus() ) {
mMsgBlockList->append( new SP_BufferMsgBlock( buffer, 1 ) );
} else {
SP_Message * msg = new SP_Message();
msg->getToList()->add( mArg->getBackendSid() );
for( ; mMsgBlockList->getCount() > 0; ) {
msg->getFollowBlockList()->append( mMsgBlockList->takeItem( 0 ) );
}
msg->getFollowBlockList()->append( new SP_BufferMsgBlock( buffer, 1 ) );
response->addMessage( msg );
}
return SP_TunnelArg::eDestroy != mArg->getBackendStatus() ? 0 : -1;
}
void SP_TunnelHandler :: error( SP_Response * response )
{
mArg->setTunnelStatus( SP_TunnelArg::eDestroy );
}
void SP_TunnelHandler :: timeout( SP_Response * response )
{
mArg->setTunnelStatus( SP_TunnelArg::eDestroy );
}
void SP_TunnelHandler :: close()
{
mArg->setTunnelStatus( SP_TunnelArg::eDestroy );
}
syntax highlighted by Code2HTML, v. 0.9.1