256 lines
7.0 KiB
C++
256 lines
7.0 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) Intel Corporation, 2006 - 2007.
|
|
//
|
|
// File: TcpConsumer.cpp
|
|
//
|
|
// Contents: Handles outgoing TCP messages.
|
|
//
|
|
// Notes:
|
|
//----------------------------------------------------------------------------
|
|
|
|
//===================================================
|
|
// INCLUDES
|
|
//===================================================
|
|
// Include for ignoring SIGPIPE under linux
|
|
#if !defined (ACE_WIN32)
|
|
#include <ace/Signal.h>
|
|
#endif /* !(ACE_WIN32) */
|
|
#include <ace/Message_Block.h>
|
|
#include <ace/SOCK_Stream.h>
|
|
|
|
#include "TcpSvcHandler.h"
|
|
#include "TcpConsumer.h"
|
|
#include "global.h"
|
|
#include "OptionsUtils.h"
|
|
|
|
//===================================================
|
|
// SocksSupplier Implementation
|
|
//===================================================
|
|
Tcp_Consumer::~Tcp_Consumer()
|
|
{
|
|
ACE_DEBUG((MY_DEBUG "----->Tcp_Consumer dtor\n"));
|
|
ACE_DEBUG((MY_TRACE ACE_TEXT("Tcp_Consumer::dtor .message counter remain in queue= %d. (%x)\n"), _msg_counter, _svc_handler));
|
|
|
|
}
|
|
|
|
// Constructor (set the svc handler)
|
|
Tcp_Consumer::Tcp_Consumer(Tcp_Svc_Handler* handler): _msg_counter(0)
|
|
{
|
|
_svc_handler = handler;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Get reference to socket stream
|
|
//-----------------------------------------
|
|
ACE_SOCK_Stream& Tcp_Consumer::getPeer(void) const
|
|
{
|
|
return (ACE_SOCK_Stream &)_svc_handler->peer();
|
|
}
|
|
|
|
// Put message in this tunnel handler queue
|
|
STATUS Tcp_Consumer::putq(ACE_Message_Block *mb, ACE_Time_Value *tv)
|
|
{
|
|
ACE_TRACE(ACE_TEXT("Tcp_Consumer::putq"));
|
|
if (_svc_handler == NULL)
|
|
return STATUS_FATAL_ERROR;
|
|
|
|
ACE_DEBUG((MY_TRACE ACE_TEXT("Tcp_Consumer:putq (%x)\n"), _svc_handler));
|
|
{
|
|
// every time we enqueue message, a new notification is created in reactor.
|
|
// we count those notification so we will know when the reactor does'nt contain
|
|
// any notification dispacher for this handler (important for deletion)
|
|
ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex ,
|
|
lock2,
|
|
_svc_handler->_dispatch_output_counter_mutex,
|
|
STATUS_LOCK_FAILURE);
|
|
|
|
_svc_handler->_dispatch_output_counter++;
|
|
}
|
|
if (_svc_handler->msg_queue()->is_full())
|
|
{
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT("Tcp_Consumer: Queue is full\n")));
|
|
}
|
|
_msg_counter++;
|
|
|
|
if (_svc_handler->putq (mb, tv) == -1)
|
|
{
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT("TCP consumer failed to put message in queue\n")));
|
|
|
|
if (errno == EWOULDBLOCK)
|
|
return STATUS_QUEUE_TIMEOUT;
|
|
else
|
|
return STATUS_FAILURE;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Handle output message.
|
|
// goes over the message queue - and send all its content.
|
|
//-----------------------------------------
|
|
STATUS Tcp_Consumer::handle_output(ACE_HANDLE h)
|
|
{
|
|
ACE_TRACE(ACE_TEXT("Tcp_Supplier::handle_output"));
|
|
if (getPeer().get_handle() == ACE_INVALID_HANDLE)
|
|
{
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT ("socket handler is INVALID\n")));
|
|
return STATUS_NETWORK_ERROR;
|
|
}
|
|
|
|
ACE_Message_Block *mb = NULL;
|
|
int res = 0;
|
|
int err = 0;
|
|
int qcount = 0 ;
|
|
STATUS rep = STATUS_SUCCESS;
|
|
|
|
if (_svc_handler->msg_queue()->message_count() <= 0)
|
|
{
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT ("tcpConsumer:handle_output - message count <=0\n")));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
_msg_counter--;
|
|
|
|
qcount = _svc_handler->getq(mb);
|
|
|
|
if (mb != 0 && qcount != -1) // qcount > 0
|
|
{
|
|
//if close connection message
|
|
if ( mb->msg_type() == ACE_Message_Block::MB_HANGUP)
|
|
{
|
|
|
|
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT ("sending close message to mc\n")));
|
|
|
|
// if there are more output notifications for this handler in reactor, we dont want to return STATUS_CONNECTION_CLOSED
|
|
// because it can cause to delete this handler (while reactor still holding it)
|
|
// only the last dispacher return STATUS_CONNECTION_CLOSED;
|
|
ACE_GUARD_RETURN( ACE_Recursive_Thread_Mutex ,
|
|
dispatch_output_counter_lock,
|
|
_svc_handler->_dispatch_output_counter_mutex,
|
|
STATUS_LOCK_FAILURE);
|
|
|
|
ACE_READ_GUARD_RETURN(ACE_Recursive_Thread_Mutex ,
|
|
active_lock,
|
|
_svc_handler->_active_mutex,
|
|
STATUS_LOCK_FAILURE);
|
|
|
|
ACE_WRITE_GUARD_RETURN( ACE_RW_Thread_Mutex ,
|
|
state_lock,
|
|
_svc_handler->_state_mutex,
|
|
STATUS_LOCK_FAILURE);
|
|
|
|
_svc_handler->_tcp_state = Tcp_Svc_Handler::DISCONNECTED;
|
|
if ((_svc_handler->_dispatch_output_counter == 0) && (_svc_handler->_active_counter == 1))
|
|
{
|
|
ACE_DEBUG((MY_TRACE ACE_TEXT("Tcp_Consumer::handle_output - got hangup message, and it IS the last dispacher\n")));
|
|
rep = STATUS_CONNECTION_CLOSED;
|
|
}
|
|
else
|
|
{
|
|
ACE_DEBUG((MY_TRACE ACE_TEXT("Tcp_Consumer::handle_output - got hangup message, but its NOT the last dispacher, or some other thread is handling output for this service [%x]\n"), _svc_handler));
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
ACE_READ_GUARD_RETURN( ACE_RW_Thread_Mutex ,
|
|
lock,
|
|
_svc_handler->_state_mutex,
|
|
STATUS_LOCK_FAILURE);
|
|
if (_svc_handler->state() == Tcp_Svc_Handler::DISCONNECTING)
|
|
{
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT ("DISCONNECT state - ignoring data\n")));
|
|
|
|
rep = STATUS_SUCCESS;
|
|
}
|
|
|
|
else
|
|
{
|
|
lock.release();
|
|
// Handle SIGPIPE under linux
|
|
#if !defined (ACE_WIN32)
|
|
ACE_Sig_Action no_sigpipe((ACE_SignalHandler) SIG_IGN);
|
|
ACE_Sig_Action original_action;
|
|
no_sigpipe.register_action(SIGPIPE, &original_action);
|
|
#endif /* !(ACE_WIN32) */
|
|
|
|
res = this->getPeer().send_n(mb, &ACE_Time_Value(*getMaxTunnelTimeout()));
|
|
|
|
#if !defined (ACE_WIN32)
|
|
no_sigpipe.restore_action(SIGPIPE, original_action);
|
|
#endif /* !(ACE_WIN32) */
|
|
|
|
if ( (res < 0) || (res != mb->length()))
|
|
{
|
|
// Failed to send the entire message
|
|
ACE_DEBUG((MY_DEBUG
|
|
ACE_TEXT("TCPConsumer failed to send the entire message\n")));
|
|
rep = STATUS_NETWORK_ERROR;
|
|
}
|
|
}
|
|
}
|
|
ACE_Message_Block::release(mb);
|
|
|
|
}
|
|
return rep;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// add message block to message queue, and
|
|
// register to write handler.
|
|
//-----------------------------------------
|
|
STATUS Tcp_Consumer::sendData(ACE_Message_Block* mb)
|
|
{
|
|
ACE_TRACE(ACE_TEXT("Tcp_Consumer::sendData"));
|
|
|
|
STATUS rep;
|
|
|
|
rep = putq(mb);
|
|
|
|
if (rep != STATUS_SUCCESS) // failed to putq
|
|
{
|
|
ACE_Message_Block::release(mb);
|
|
ACE_ERROR_RETURN((MY_DEBUG
|
|
ACE_TEXT("Tcp_Consumer::sendData - failed to send message block to message queue\n")),
|
|
rep);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Close consummer
|
|
// This method is called in two cases:
|
|
// 1. By the Tunnel_Supplier (after a channel has been established) when
|
|
// (a) AMT closed the channel. (b) The tunnel is closing.
|
|
// 2. By the SOCKS_Supplier if the channel creation failed.
|
|
//-----------------------------------------
|
|
void Tcp_Consumer::connectionClose()
|
|
{
|
|
ACE_TRACE(ACE_TEXT("Tcp_Supplier::connectionClose"));
|
|
|
|
ACE_Message_Block *mb;
|
|
ACE_NEW(mb,ACE_Message_Block(0, ACE_Message_Block::MB_HANGUP));
|
|
|
|
if (sendData(mb) != STATUS_SUCCESS)
|
|
{
|
|
ACE_DEBUG ((MY_DEBUG
|
|
ACE_TEXT ("failed to send close message\n")));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// close consummer
|
|
//-----------------------------------------
|
|
void Tcp_Consumer::handle_close()
|
|
{
|
|
ACE_TRACE(ACE_TEXT("Tcp_Supplier::close"));
|
|
}
|