i2pd/libi2pd_client/BOB.cpp

720 lines
20 KiB
C++
Raw Normal View History

2014-12-02 23:47:44 +03:00
#include <string.h>
2014-12-02 19:42:35 +03:00
#include "Log.h"
2014-12-03 05:45:01 +03:00
#include "ClientContext.h"
2016-11-04 04:31:21 +03:00
#include "util.h"
2014-12-02 18:34:02 +03:00
#include "BOB.h"
namespace i2p
{
namespace client
{
2015-02-24 23:40:50 +03:00
BOBI2PInboundTunnel::BOBI2PInboundTunnel (int port, std::shared_ptr<ClientDestination> localDestination):
BOBI2PTunnel (localDestination),
2015-03-20 22:53:53 +03:00
m_Acceptor (localDestination->GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port))
2014-12-03 22:48:41 +03:00
{
}
BOBI2PInboundTunnel::~BOBI2PInboundTunnel ()
{
2014-12-05 03:29:20 +03:00
Stop ();
2014-12-03 22:48:41 +03:00
}
void BOBI2PInboundTunnel::Start ()
{
m_Acceptor.listen ();
Accept ();
}
void BOBI2PInboundTunnel::Stop ()
{
m_Acceptor.close();
ClearHandlers ();
2014-12-03 22:48:41 +03:00
}
void BOBI2PInboundTunnel::Accept ()
{
2015-04-06 22:02:37 +03:00
auto receiver = std::make_shared<AddressReceiver> ();
receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
2014-12-07 17:48:03 +03:00
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
std::placeholders::_1, receiver));
2014-12-03 22:48:41 +03:00
}
2015-04-06 22:02:37 +03:00
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver)
2014-12-03 22:48:41 +03:00
{
if (!ecode)
{
Accept ();
2014-12-07 17:48:03 +03:00
ReceiveAddress (receiver);
2014-12-03 22:48:41 +03:00
}
}
2015-04-06 22:02:37 +03:00
void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
2014-12-03 22:48:41 +03:00
{
2014-12-07 17:48:03 +03:00
receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset,
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
2014-12-03 22:48:41 +03:00
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
2014-12-07 17:48:03 +03:00
std::placeholders::_1, std::placeholders::_2, receiver));
2014-12-03 22:48:41 +03:00
}
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
2015-04-06 22:02:37 +03:00
std::shared_ptr<AddressReceiver> receiver)
2014-12-03 22:48:41 +03:00
{
if (ecode)
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: inbound tunnel read error: ", ecode.message ());
2014-12-03 22:48:41 +03:00
else
{
2014-12-07 17:48:03 +03:00
receiver->bufferOffset += bytes_transferred;
receiver->buffer[receiver->bufferOffset] = 0;
char * eol = strchr (receiver->buffer, '\n');
2014-12-03 22:48:41 +03:00
if (eol)
{
*eol = 0;
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
2014-12-07 17:48:03 +03:00
receiver->data = (uint8_t *)eol + 1;
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
2014-12-03 22:48:41 +03:00
i2p::data::IdentHash ident;
2014-12-07 17:48:03 +03:00
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
return;
}
2014-12-03 22:48:41 +03:00
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
if (leaseSet)
2014-12-07 17:48:03 +03:00
CreateConnection (receiver, leaseSet);
2014-12-03 22:48:41 +03:00
else
2015-03-20 22:53:53 +03:00
GetLocalDestination ()->RequestDestination (ident,
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
this, std::placeholders::_1, receiver));
2014-12-03 22:48:41 +03:00
}
else
{
2014-12-07 17:48:03 +03:00
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
ReceiveAddress (receiver);
2014-12-06 23:31:39 +03:00
else
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: missing inbound address");
2014-12-03 22:48:41 +03:00
}
}
}
void BOBI2PInboundTunnel::HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver)
2014-12-03 22:48:41 +03:00
{
if (leaseSet)
CreateConnection (receiver, leaseSet);
else
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found");
2014-12-03 22:48:41 +03:00
}
2015-04-06 22:02:37 +03:00
void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
2014-12-03 22:48:41 +03:00
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogDebug, "BOB: New inbound connection");
2014-12-07 17:48:03 +03:00
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
AddHandler (connection);
2014-12-07 17:48:03 +03:00
connection->I2PConnect (receiver->data, receiver->dataLen);
2014-12-03 22:48:41 +03:00
}
BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port,
2015-02-24 23:40:50 +03:00
std::shared_ptr<ClientDestination> localDestination, bool quiet): BOBI2PTunnel (localDestination),
2014-12-05 22:13:16 +03:00
m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsQuiet (quiet)
{
}
void BOBI2POutboundTunnel::Start ()
{
Accept ();
}
void BOBI2POutboundTunnel::Stop ()
{
ClearHandlers ();
2014-12-05 22:13:16 +03:00
}
void BOBI2POutboundTunnel::Accept ()
{
auto localDestination = GetLocalDestination ();
if (localDestination)
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
else
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: Local destination not set for server tunnel");
2014-12-05 22:13:16 +03:00
}
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
AddHandler (conn);
2014-12-05 22:13:16 +03:00
conn->Connect ();
}
}
2015-02-24 23:40:50 +03:00
BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination):
m_LocalDestination (localDestination),
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr)
{
}
BOBDestination::~BOBDestination ()
{
delete m_OutboundTunnel;
delete m_InboundTunnel;
2015-02-24 23:40:50 +03:00
i2p::client::context.DeleteLocalDestination (m_LocalDestination);
}
void BOBDestination::Start ()
{
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
if (m_InboundTunnel) m_InboundTunnel->Start ();
}
void BOBDestination::Stop ()
{
2014-12-08 05:04:02 +03:00
StopTunnels ();
2015-02-24 23:40:50 +03:00
m_LocalDestination->Stop ();
}
2014-12-05 22:13:16 +03:00
2014-12-08 05:04:02 +03:00
void BOBDestination::StopTunnels ()
{
if (m_OutboundTunnel)
{
m_OutboundTunnel->Stop ();
delete m_OutboundTunnel;
m_OutboundTunnel = nullptr;
}
if (m_InboundTunnel)
{
m_InboundTunnel->Stop ();
delete m_InboundTunnel;
m_InboundTunnel = nullptr;
}
}
void BOBDestination::CreateInboundTunnel (int port)
{
2014-12-08 05:04:02 +03:00
if (!m_InboundTunnel)
2015-02-24 23:40:50 +03:00
m_InboundTunnel = new BOBI2PInboundTunnel (port, m_LocalDestination);
}
void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet)
{
2014-12-08 05:04:02 +03:00
if (!m_OutboundTunnel)
2015-02-24 23:40:50 +03:00
m_OutboundTunnel = new BOBI2POutboundTunnel (address, port, m_LocalDestination, quiet);
}
2014-12-02 23:47:44 +03:00
BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner):
2016-07-19 18:08:28 +03:00
m_Owner (owner), m_Socket (m_Owner.GetService ()),
2016-07-21 21:02:13 +03:00
m_ReceiveBufferOffset (0), m_IsOpen (true), m_IsQuiet (false), m_IsActive (false),
2016-07-11 21:35:59 +03:00
m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr)
2014-12-02 19:42:35 +03:00
{
}
2014-12-02 23:47:44 +03:00
BOBCommandSession::~BOBCommandSession ()
{
}
2014-12-03 00:45:51 +03:00
void BOBCommandSession::Terminate ()
{
m_Socket.close ();
m_IsOpen = false;
}
2014-12-02 23:47:44 +03:00
void BOBCommandSession::Receive ()
{
m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, BOB_COMMAND_BUFFER_SIZE - m_ReceiveBufferOffset),
std::bind(&BOBCommandSession::HandleReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void BOBCommandSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
2014-12-03 00:45:51 +03:00
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ());
2014-12-05 03:29:20 +03:00
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
2014-12-03 00:45:51 +03:00
}
2014-12-02 23:47:44 +03:00
else
{
size_t size = m_ReceiveBufferOffset + bytes_transferred;
m_ReceiveBuffer[size] = 0;
char * eol = strchr (m_ReceiveBuffer, '\n');
if (eol)
{
*eol = 0;
char * operand = strchr (m_ReceiveBuffer, ' ');
2014-12-03 05:45:01 +03:00
if (operand)
{
*operand = 0;
operand++;
}
else
operand = eol;
2014-12-02 23:47:44 +03:00
// process command
2014-12-03 05:45:01 +03:00
auto& handlers = m_Owner.GetCommandHandlers ();
2014-12-02 23:47:44 +03:00
auto it = handlers.find (m_ReceiveBuffer);
if (it != handlers.end ())
2014-12-03 05:45:01 +03:00
(this->*(it->second))(operand, eol - operand);
else
2014-12-05 18:59:37 +03:00
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer);
2014-12-05 18:59:37 +03:00
SendReplyError ("unknown command");
}
2014-12-02 23:47:44 +03:00
m_ReceiveBufferOffset = size - (eol - m_ReceiveBuffer) - 1;
memmove (m_ReceiveBuffer, eol + 1, m_ReceiveBufferOffset);
}
else
{
if (size < BOB_COMMAND_BUFFER_SIZE)
m_ReceiveBufferOffset = size;
else
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: Malformed input of the command channel");
2014-12-03 00:45:51 +03:00
Terminate ();
2014-12-02 23:47:44 +03:00
}
}
2014-12-03 00:45:51 +03:00
}
}
void BOBCommandSession::Send (size_t len)
{
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SendBuffer, len),
boost::asio::transfer_all (),
std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void BOBCommandSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: command channel send error: ", ecode.message ());
2014-12-05 03:29:20 +03:00
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
2014-12-03 00:45:51 +03:00
}
else
{
2014-12-02 23:47:44 +03:00
if (m_IsOpen)
Receive ();
2014-12-03 00:45:51 +03:00
else
Terminate ();
2014-12-02 23:47:44 +03:00
}
}
2014-12-03 00:45:51 +03:00
void BOBCommandSession::SendReplyOK (const char * msg)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#endif
Send (len);
}
void BOBCommandSession::SendReplyError (const char * msg)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#endif
Send (len);
}
2014-12-06 06:25:31 +03:00
2014-12-06 00:03:43 +03:00
void BOBCommandSession::SendVersion ()
{
size_t len = strlen (BOB_VERSION);
memcpy (m_SendBuffer, BOB_VERSION, len);
Send (len);
}
2014-12-06 06:25:31 +03:00
void BOBCommandSession::SendData (const char * nickname)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#endif
Send (len);
}
2014-12-02 23:47:44 +03:00
void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: zap");
2014-12-03 00:45:51 +03:00
Terminate ();
}
void BOBCommandSession::QuitCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quit");
2014-12-02 23:47:44 +03:00
m_IsOpen = false;
2014-12-03 00:45:51 +03:00
SendReplyOK ("Bye!");
2014-12-02 23:47:44 +03:00
}
2014-12-03 05:45:01 +03:00
void BOBCommandSession::StartCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: start ", m_Nickname);
2016-07-21 21:02:13 +03:00
if (m_IsActive)
{
SendReplyError ("tunnel is active");
return;
}
2014-12-08 05:04:02 +03:00
if (!m_CurrentDestination)
{
2015-02-24 23:40:50 +03:00
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options));
2014-12-08 05:04:02 +03:00
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
}
if (m_InPort)
2014-12-08 05:04:02 +03:00
m_CurrentDestination->CreateInboundTunnel (m_InPort);
if (m_OutPort && !m_Address.empty ())
2014-12-08 05:04:02 +03:00
m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet);
m_CurrentDestination->Start ();
2016-07-21 21:02:13 +03:00
SendReplyOK ("Tunnel starting");
m_IsActive = true;
2014-12-03 05:45:01 +03:00
}
2016-07-11 21:35:59 +03:00
2014-12-03 23:24:30 +03:00
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
{
2016-07-21 21:02:13 +03:00
LogPrint (eLogDebug, "BOB: stop ", m_Nickname);
if (!m_IsActive)
{
SendReplyError ("tunnel is inactive");
return;
}
auto dest = m_Owner.FindDestination (m_Nickname);
if (dest)
2014-12-03 23:24:30 +03:00
{
2014-12-08 05:04:02 +03:00
dest->StopTunnels ();
2016-07-21 21:02:13 +03:00
SendReplyOK ("Tunnel stopping");
2014-12-03 23:24:30 +03:00
}
else
SendReplyError ("tunnel not found");
2016-07-21 21:02:13 +03:00
m_IsActive = false;
2014-12-03 23:24:30 +03:00
}
2014-12-03 05:45:01 +03:00
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setnick ", operand);
2014-12-03 05:45:01 +03:00
m_Nickname = operand;
2014-12-05 03:29:20 +03:00
std::string msg ("Nickname set to ");
2016-07-21 21:02:13 +03:00
msg += m_Nickname;
2014-12-03 05:45:01 +03:00
SendReplyOK (msg.c_str ());
}
2014-12-03 23:24:30 +03:00
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getnick ", operand);
2014-12-08 05:04:02 +03:00
m_CurrentDestination = m_Owner.FindDestination (operand);
if (m_CurrentDestination)
2014-12-03 23:24:30 +03:00
{
2014-12-08 05:04:02 +03:00
m_Keys = m_CurrentDestination->GetKeys ();
2014-12-03 23:24:30 +03:00
m_Nickname = operand;
}
if (m_Nickname == operand)
{
2014-12-05 03:29:20 +03:00
std::string msg ("Nickname set to ");
2016-07-21 21:02:13 +03:00
msg += m_Nickname;
2014-12-03 23:24:30 +03:00
SendReplyOK (msg.c_str ());
}
2014-12-03 23:24:30 +03:00
else
2016-07-21 21:02:13 +03:00
SendReplyError ("no nickname has been set");
2014-12-03 23:24:30 +03:00
}
2014-12-03 05:45:01 +03:00
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: newkeys");
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys ();
2015-11-03 17:15:49 +03:00
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
2014-12-03 05:45:01 +03:00
}
2014-12-04 05:01:40 +03:00
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setkeys ", operand);
2017-03-25 23:53:20 +03:00
if (m_Keys.FromBase64 (operand))
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
else
SendReplyError ("invalid keys");
2014-12-04 05:01:40 +03:00
}
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getkeys");
2016-10-11 17:18:42 +03:00
if (m_Keys.GetPublic ()) // keys are set ?
SendReplyOK (m_Keys.ToBase64 ().c_str ());
else
SendReplyError ("keys are not set");
}
2014-12-04 05:01:40 +03:00
void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getdest");
2015-11-03 17:15:49 +03:00
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
2014-12-04 05:01:40 +03:00
}
2014-12-03 05:45:01 +03:00
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outhost ", operand);
2014-12-03 05:45:01 +03:00
m_Address = operand;
SendReplyOK ("outhost set");
}
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outport ", operand);
m_OutPort = std::stoi(operand);
2016-07-21 21:02:13 +03:00
if (m_OutPort >= 0)
SendReplyOK ("outbound port set");
else
SendReplyError ("port out of range");
2014-12-03 05:45:01 +03:00
}
2014-12-03 23:02:19 +03:00
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inhost ", operand);
2014-12-03 23:02:19 +03:00
m_Address = operand;
SendReplyOK ("inhost set");
}
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inport ", operand);
m_InPort = std::stoi(operand);
2016-07-21 21:02:13 +03:00
if (m_InPort >= 0)
SendReplyOK ("inbound port set");
else
SendReplyError ("port out of range");
2014-12-03 23:02:19 +03:00
}
2014-12-05 22:13:16 +03:00
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quiet");
2016-07-21 21:02:13 +03:00
if (m_Nickname.length () > 0)
{
if (!m_IsActive)
{
m_IsQuiet = true;
SendReplyOK ("Quiet set");
}
else
SendReplyError ("tunnel is active");
}
else
SendReplyError ("no nickname has been set");
2014-12-05 22:13:16 +03:00
}
2014-12-06 00:03:43 +03:00
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: lookup ", operand);
i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetIdentHash (operand, ident))
2014-12-06 00:03:43 +03:00
{
SendReplyError ("Address Not found");
return;
}
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
auto leaseSet = localDestination->FindLeaseSet (ident);
if (leaseSet)
2015-11-03 17:15:49 +03:00
SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ());
else
{
auto s = shared_from_this ();
2015-04-10 16:58:08 +03:00
localDestination->RequestDestination (ident,
[s](std::shared_ptr<i2p::data::LeaseSet> ls)
{
if (ls)
2015-11-03 17:15:49 +03:00
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
else
s->SendReplyError ("LeaseSet Not found");
}
);
}
2014-12-06 00:03:43 +03:00
}
2014-12-06 03:16:54 +03:00
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: clear");
2014-12-08 05:04:02 +03:00
m_Owner.DeleteDestination (m_Nickname);
2016-07-21 21:02:13 +03:00
m_Nickname = "";
2014-12-06 03:16:54 +03:00
SendReplyOK ("cleared");
}
2014-12-06 00:03:43 +03:00
2014-12-06 06:25:31 +03:00
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: list");
2016-08-05 21:23:54 +03:00
const auto& destinations = m_Owner.GetDestinations ();
for (const auto& it: destinations)
2014-12-06 06:25:31 +03:00
SendData (it.first.c_str ());
SendReplyOK ("Listing done");
}
void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: option ", operand);
2014-12-06 23:31:39 +03:00
const char * value = strchr (operand, '=');
if (value)
{
2016-07-21 21:02:13 +03:00
std::string msg ("option ");
2014-12-06 23:31:39 +03:00
*(const_cast<char *>(value)) = 0;
m_Options[operand] = value + 1;
2016-07-21 21:02:13 +03:00
msg += operand;
2014-12-06 23:31:39 +03:00
*(const_cast<char *>(value)) = '=';
2016-07-21 21:02:13 +03:00
msg += " set to ";
msg += value;
SendReplyOK (msg.c_str ());
2014-12-06 23:31:39 +03:00
}
else
SendReplyError ("malformed");
2014-12-06 06:25:31 +03:00
}
2016-07-16 16:31:33 +03:00
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: status ", operand);
2016-07-21 21:02:13 +03:00
if (m_Nickname == operand)
2016-07-19 18:08:28 +03:00
{
std::stringstream s;
2016-07-24 16:24:20 +03:00
s << "DATA"; s << " NICKNAME: "; s << m_Nickname;
if (m_CurrentDestination)
{
if (m_CurrentDestination->GetLocalDestination ()->IsReady ())
s << " STARTING: false RUNNING: true STOPPING: false";
else
s << " STARTING: true RUNNING: false STOPPING: false";
}
2016-07-19 18:08:28 +03:00
else
s << " STARTING: false RUNNING: false STOPPING: false";
2016-07-24 16:24:20 +03:00
s << " KEYS: true"; s << " QUIET: "; s << (m_IsQuiet ? "true":"false");
2016-07-19 18:08:28 +03:00
if (m_InPort)
{
2016-07-24 16:24:20 +03:00
s << " INPORT: " << m_InPort;
s << " INHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
2016-07-19 18:08:28 +03:00
}
if (m_OutPort)
{
2016-07-24 16:24:20 +03:00
s << " OUTPORT: " << m_OutPort;
s << " OUTHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
2016-07-19 18:08:28 +03:00
}
SendReplyOK (s.str().c_str());
}
2016-07-16 16:31:33 +03:00
else
SendReplyError ("no nickname has been set");
}
2014-12-06 06:25:31 +03:00
2015-11-30 17:44:32 +03:00
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
2014-12-02 19:42:35 +03:00
m_IsRunning (false), m_Thread (nullptr),
2015-11-30 17:44:32 +03:00
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
2014-12-02 18:34:02 +03:00
{
2014-12-03 05:45:01 +03:00
// command -> handler
2014-12-02 23:47:44 +03:00
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
2014-12-03 00:45:51 +03:00
m_CommandHandlers[BOB_COMMAND_QUIT] = &BOBCommandSession::QuitCommandHandler;
2014-12-03 05:45:01 +03:00
m_CommandHandlers[BOB_COMMAND_START] = &BOBCommandSession::StartCommandHandler;
2014-12-03 23:24:30 +03:00
m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler;
2014-12-03 05:45:01 +03:00
m_CommandHandlers[BOB_COMMAND_SETNICK] = &BOBCommandSession::SetNickCommandHandler;
2014-12-03 23:24:30 +03:00
m_CommandHandlers[BOB_COMMAND_GETNICK] = &BOBCommandSession::GetNickCommandHandler;
2014-12-03 05:45:01 +03:00
m_CommandHandlers[BOB_COMMAND_NEWKEYS] = &BOBCommandSession::NewkeysCommandHandler;
2014-12-04 05:01:40 +03:00
m_CommandHandlers[BOB_COMMAND_GETKEYS] = &BOBCommandSession::GetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_SETKEYS] = &BOBCommandSession::SetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_GETDEST] = &BOBCommandSession::GetdestCommandHandler;
2014-12-03 05:45:01 +03:00
m_CommandHandlers[BOB_COMMAND_OUTHOST] = &BOBCommandSession::OuthostCommandHandler;
m_CommandHandlers[BOB_COMMAND_OUTPORT] = &BOBCommandSession::OutportCommandHandler;
2014-12-03 23:02:19 +03:00
m_CommandHandlers[BOB_COMMAND_INHOST] = &BOBCommandSession::InhostCommandHandler;
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
2014-12-05 22:13:16 +03:00
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
2014-12-06 00:03:43 +03:00
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
2014-12-06 03:16:54 +03:00
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
2014-12-06 06:25:31 +03:00
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;
2016-07-16 16:31:33 +03:00
m_CommandHandlers[BOB_COMMAND_STATUS] = &BOBCommandSession::StatusCommandHandler;
2014-12-02 18:34:02 +03:00
}
BOBCommandChannel::~BOBCommandChannel ()
{
2014-12-02 19:42:35 +03:00
Stop ();
2016-08-05 21:23:54 +03:00
for (const auto& it: m_Destinations)
2014-12-03 23:24:30 +03:00
delete it.second;
2014-12-02 19:42:35 +03:00
}
void BOBCommandChannel::Start ()
{
Accept ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&BOBCommandChannel::Run, this));
}
void BOBCommandChannel::Stop ()
{
m_IsRunning = false;
2016-08-05 21:23:54 +03:00
for (auto& it: m_Destinations)
2014-12-03 23:24:30 +03:00
it.second->Stop ();
m_Acceptor.cancel ();
2014-12-02 19:42:35 +03:00
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
2014-12-08 05:04:02 +03:00
2014-12-02 19:42:35 +03:00
void BOBCommandChannel::Run ()
{
while (m_IsRunning)
{
try
{
m_Service.run ();
}
catch (std::exception& ex)
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
2014-12-02 19:42:35 +03:00
}
}
}
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
2014-12-03 05:45:01 +03:00
{
m_Destinations[name] = dest;
2014-12-03 05:45:01 +03:00
}
2014-12-03 23:24:30 +03:00
2014-12-08 05:04:02 +03:00
void BOBCommandChannel::DeleteDestination (const std::string& name)
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
{
it->second->Stop ();
delete it->second;
m_Destinations.erase (it);
}
}
BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
2014-12-03 23:24:30 +03:00
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
2014-12-03 23:24:30 +03:00
return it->second;
return nullptr;
}
2014-12-03 05:45:01 +03:00
2014-12-02 19:42:35 +03:00
void BOBCommandChannel::Accept ()
{
2014-12-02 23:47:44 +03:00
auto newSession = std::make_shared<BOBCommandSession> (*this);
m_Acceptor.async_accept (newSession->GetSocket (), std::bind (&BOBCommandChannel::HandleAccept, this,
std::placeholders::_1, newSession));
2014-12-02 19:42:35 +03:00
}
2014-12-02 23:47:44 +03:00
void BOBCommandChannel::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session)
2014-12-02 19:42:35 +03:00
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (!ecode)
{
2015-12-18 09:27:35 +03:00
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
2014-12-06 00:03:43 +03:00
session->SendVersion ();
2014-12-02 19:42:35 +03:00
}
else
2015-12-18 09:27:35 +03:00
LogPrint (eLogError, "BOB: accept error: ", ecode.message ());
2014-12-02 18:34:02 +03:00
}
}
}