2014-09-24 18:59:03 +00:00
|
|
|
#include <string.h>
|
2014-09-30 15:08:38 +00:00
|
|
|
#include <stdio.h>
|
2014-10-27 21:53:01 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#include <stdlib.h>
|
|
|
|
#endif
|
2014-12-16 21:23:42 +00:00
|
|
|
#include <boost/lexical_cast.hpp>
|
2014-09-24 20:39:31 +00:00
|
|
|
#include "base64.h"
|
2014-09-25 17:58:09 +00:00
|
|
|
#include "Identity.h"
|
2014-09-24 16:01:26 +00:00
|
|
|
#include "Log.h"
|
2014-10-05 12:54:59 +00:00
|
|
|
#include "Destination.h"
|
2014-10-16 00:52:17 +00:00
|
|
|
#include "ClientContext.h"
|
2014-09-24 16:01:26 +00:00
|
|
|
#include "SAM.h"
|
|
|
|
|
|
|
|
namespace i2p
|
|
|
|
{
|
2014-10-16 14:28:44 +00:00
|
|
|
namespace client
|
2014-09-24 16:01:26 +00:00
|
|
|
{
|
2014-09-24 18:59:03 +00:00
|
|
|
SAMSocket::SAMSocket (SAMBridge& owner):
|
2014-10-02 16:42:28 +00:00
|
|
|
m_Owner (owner), m_Socket (m_Owner.GetService ()), m_Timer (m_Owner.GetService ()),
|
2014-10-03 01:40:15 +00:00
|
|
|
m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false), m_Stream (nullptr),
|
|
|
|
m_Session (nullptr)
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SAMSocket::~SAMSocket ()
|
|
|
|
{
|
2014-11-23 02:56:59 +00:00
|
|
|
Terminate ();
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
2014-11-23 02:56:59 +00:00
|
|
|
void SAMSocket::CloseStream ()
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
|
|
|
if (m_Stream)
|
2014-11-23 02:56:59 +00:00
|
|
|
{
|
2014-09-24 18:59:03 +00:00
|
|
|
m_Stream->Close ();
|
2014-11-23 16:33:58 +00:00
|
|
|
m_Stream.reset ();
|
2014-11-23 02:56:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::Terminate ()
|
|
|
|
{
|
|
|
|
CloseStream ();
|
2014-11-22 21:35:58 +00:00
|
|
|
|
2014-09-26 19:40:57 +00:00
|
|
|
switch (m_SocketType)
|
2014-09-25 17:58:09 +00:00
|
|
|
{
|
2014-09-26 19:40:57 +00:00
|
|
|
case eSAMSocketTypeSession:
|
|
|
|
m_Owner.CloseSession (m_ID);
|
|
|
|
break;
|
|
|
|
case eSAMSocketTypeStream:
|
|
|
|
{
|
2014-11-23 02:56:59 +00:00
|
|
|
if (m_Session)
|
|
|
|
m_Session->sockets.remove (shared_from_this ());
|
2014-09-26 19:40:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eSAMSocketTypeAcceptor:
|
|
|
|
{
|
2014-11-23 02:56:59 +00:00
|
|
|
if (m_Session)
|
2014-09-26 19:40:57 +00:00
|
|
|
{
|
2014-11-23 02:56:59 +00:00
|
|
|
m_Session->sockets.remove (shared_from_this ());
|
|
|
|
m_Session->localDestination->StopAcceptingStreams ();
|
2014-09-26 19:40:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
;
|
2014-09-25 17:58:09 +00:00
|
|
|
}
|
2014-11-23 02:56:59 +00:00
|
|
|
m_SocketType = eSAMSocketTypeTerminated;
|
2014-10-10 01:40:45 +00:00
|
|
|
m_Socket.close ();
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::ReceiveHandshake ()
|
|
|
|
{
|
|
|
|
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
|
|
|
|
std::placeholders::_1, std::placeholders::_2));
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM handshake read error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Buffer[bytes_transferred] = 0;
|
|
|
|
LogPrint ("SAM handshake ", m_Buffer);
|
2014-12-16 20:54:02 +00:00
|
|
|
char * separator = strchr (m_Buffer, ' ');
|
|
|
|
if (separator)
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
2014-12-16 20:54:02 +00:00
|
|
|
separator = strchr (separator + 1, ' ');
|
|
|
|
if (separator)
|
|
|
|
*separator = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strcmp (m_Buffer, SAM_HANDSHAKE))
|
|
|
|
{
|
|
|
|
std::string version("3.0");
|
|
|
|
// try to find MIN and MAX, 3.0 if not found
|
|
|
|
if (separator)
|
|
|
|
{
|
|
|
|
separator++;
|
|
|
|
std::map<std::string, std::string> params;
|
|
|
|
ExtractParams (separator, bytes_transferred - (separator - m_Buffer), params);
|
|
|
|
auto it = params.find (SAM_PARAM_MAX);
|
|
|
|
// TODO: check MIN as well
|
|
|
|
if (it != params.end ())
|
|
|
|
version = it->second;
|
|
|
|
}
|
|
|
|
if (version[0] == '3') // we support v3 (3.0 and 3.1) only
|
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
|
|
|
|
#else
|
|
|
|
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
|
|
|
|
#endif
|
2014-12-17 00:04:13 +00:00
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (),
|
|
|
|
std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
|
|
|
|
std::placeholders::_1, std::placeholders::_2));
|
2014-12-16 20:54:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
SendMessageReply (SAM_HANDSHAKE_I2P_ERROR, strlen (SAM_HANDSHAKE_I2P_ERROR), true);
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-09-28 13:05:37 +00:00
|
|
|
LogPrint ("SAM handshake mismatch");
|
2014-09-24 18:59:03 +00:00
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM handshake reply send error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
2014-09-25 17:22:25 +00:00
|
|
|
{
|
|
|
|
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind(&SAMSocket::HandleMessage, shared_from_this (),
|
|
|
|
std::placeholders::_1, std::placeholders::_2));
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::SendMessageReply (const char * msg, size_t len, bool close)
|
|
|
|
{
|
2015-02-01 02:49:54 +00:00
|
|
|
if (!m_IsSilent)
|
2014-09-29 18:18:06 +00:00
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
|
|
|
|
std::placeholders::_1, std::placeholders::_2, close));
|
2014-09-29 18:18:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (close)
|
|
|
|
Terminate ();
|
|
|
|
else
|
|
|
|
Receive ();
|
|
|
|
}
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close)
|
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM reply send error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (close)
|
|
|
|
Terminate ();
|
|
|
|
else
|
|
|
|
Receive ();
|
|
|
|
}
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:22:25 +00:00
|
|
|
void SAMSocket::HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM read error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Buffer[bytes_transferred] = 0;
|
|
|
|
char * eol = strchr (m_Buffer, '\n');
|
|
|
|
if (eol)
|
|
|
|
{
|
|
|
|
*eol = 0;
|
2014-09-28 13:05:37 +00:00
|
|
|
char * separator = strchr (m_Buffer, ' ');
|
|
|
|
if (separator)
|
2014-09-30 15:08:38 +00:00
|
|
|
{
|
|
|
|
separator = strchr (separator + 1, ' ');
|
|
|
|
if (separator)
|
|
|
|
*separator = 0;
|
|
|
|
else
|
|
|
|
separator = eol;
|
|
|
|
|
2014-09-28 13:05:37 +00:00
|
|
|
if (!strcmp (m_Buffer, SAM_SESSION_CREATE))
|
|
|
|
ProcessSessionCreate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
|
|
|
else if (!strcmp (m_Buffer, SAM_STREAM_CONNECT))
|
|
|
|
ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
|
|
|
else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT))
|
|
|
|
ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
2014-09-30 15:08:38 +00:00
|
|
|
else if (!strcmp (m_Buffer, SAM_DEST_GENERATE))
|
|
|
|
ProcessDestGenerate ();
|
2014-10-02 20:55:01 +00:00
|
|
|
else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP))
|
|
|
|
ProcessNamingLookup (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
2014-09-28 13:05:37 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
LogPrint ("SAM unexpected message ", m_Buffer);
|
|
|
|
Terminate ();
|
|
|
|
}
|
2014-09-30 15:08:38 +00:00
|
|
|
}
|
2014-09-28 13:05:37 +00:00
|
|
|
else
|
2014-09-30 15:08:38 +00:00
|
|
|
{
|
|
|
|
LogPrint ("SAM malformed message ", m_Buffer);
|
2014-09-25 17:22:25 +00:00
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-09-30 15:08:38 +00:00
|
|
|
LogPrint ("SAM malformed message ", m_Buffer);
|
2014-09-25 17:22:25 +00:00
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::ProcessSessionCreate (char * buf, size_t len)
|
|
|
|
{
|
2014-09-28 13:05:37 +00:00
|
|
|
LogPrint ("SAM session create: ", buf);
|
2014-09-25 17:22:25 +00:00
|
|
|
std::map<std::string, std::string> params;
|
|
|
|
ExtractParams (buf, len, params);
|
2014-10-22 20:42:26 +00:00
|
|
|
std::string& style = params[SAM_PARAM_STYLE];
|
2014-09-25 17:22:25 +00:00
|
|
|
std::string& id = params[SAM_PARAM_ID];
|
|
|
|
std::string& destination = params[SAM_PARAM_DESTINATION];
|
2014-12-16 21:23:42 +00:00
|
|
|
m_ID = id;
|
2014-10-01 18:52:32 +00:00
|
|
|
if (m_Owner.FindSession (id))
|
|
|
|
{
|
|
|
|
// session exists
|
|
|
|
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), true);
|
|
|
|
return;
|
|
|
|
}
|
2014-12-16 21:23:42 +00:00
|
|
|
|
|
|
|
// create destination
|
2014-11-30 15:51:22 +00:00
|
|
|
m_Session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms);
|
2014-10-03 01:40:15 +00:00
|
|
|
if (m_Session)
|
2014-09-25 17:22:25 +00:00
|
|
|
{
|
2014-09-25 17:58:09 +00:00
|
|
|
m_SocketType = eSAMSocketTypeSession;
|
2014-10-16 20:36:12 +00:00
|
|
|
if (m_Session->localDestination->IsReady ())
|
2014-10-22 20:42:26 +00:00
|
|
|
{
|
|
|
|
if (style == SAM_VALUE_DATAGRAM)
|
2014-10-31 20:44:44 +00:00
|
|
|
{
|
|
|
|
auto dest = m_Session->localDestination->CreateDatagramDestination ();
|
2014-11-22 21:35:58 +00:00
|
|
|
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
|
2015-03-03 20:31:49 +00:00
|
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
2014-10-31 20:44:44 +00:00
|
|
|
}
|
2014-10-16 20:36:12 +00:00
|
|
|
SendSessionCreateReplyOk ();
|
2014-10-22 20:42:26 +00:00
|
|
|
}
|
2014-10-16 20:36:12 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
|
2014-11-23 22:00:45 +00:00
|
|
|
m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
|
|
|
|
shared_from_this (), std::placeholders::_1));
|
2014-10-16 20:36:12 +00:00
|
|
|
}
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
else
|
2014-10-01 18:52:32 +00:00
|
|
|
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_DEST, strlen(SAM_SESSION_CREATE_DUPLICATED_DEST), true);
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
|
2014-10-16 20:36:12 +00:00
|
|
|
void SAMSocket::HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode)
|
|
|
|
{
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
{
|
|
|
|
if (m_Session->localDestination->IsReady ())
|
|
|
|
SendSessionCreateReplyOk ();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
|
2014-11-23 22:00:45 +00:00
|
|
|
m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
|
|
|
|
shared_from_this (), std::placeholders::_1));
|
2014-10-16 20:36:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::SendSessionCreateReplyOk ()
|
|
|
|
{
|
|
|
|
uint8_t buf[1024];
|
|
|
|
char priv[1024];
|
|
|
|
size_t l = m_Session->localDestination->GetPrivateKeys ().ToBuffer (buf, 1024);
|
|
|
|
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, priv, 1024);
|
|
|
|
priv[l1] = 0;
|
2014-10-27 21:53:01 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
|
2014-10-23 23:04:46 +00:00
|
|
|
#else
|
2014-10-16 20:36:12 +00:00
|
|
|
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
|
2014-10-27 21:53:01 +00:00
|
|
|
#endif
|
2014-10-16 20:36:12 +00:00
|
|
|
SendMessageReply (m_Buffer, l2, false);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:22:25 +00:00
|
|
|
void SAMSocket::ProcessStreamConnect (char * buf, size_t len)
|
|
|
|
{
|
2014-09-28 13:05:37 +00:00
|
|
|
LogPrint ("SAM stream connect: ", buf);
|
2014-09-25 17:58:09 +00:00
|
|
|
std::map<std::string, std::string> params;
|
|
|
|
ExtractParams (buf, len, params);
|
|
|
|
std::string& id = params[SAM_PARAM_ID];
|
|
|
|
std::string& destination = params[SAM_PARAM_DESTINATION];
|
2014-09-29 18:18:06 +00:00
|
|
|
std::string& silent = params[SAM_PARAM_SILENT];
|
|
|
|
if (silent == SAM_VALUE_TRUE) m_IsSilent = true;
|
2014-09-25 17:58:09 +00:00
|
|
|
m_ID = id;
|
2014-10-07 16:07:10 +00:00
|
|
|
m_Session = m_Owner.FindSession (id);
|
|
|
|
if (m_Session)
|
2014-09-25 17:58:09 +00:00
|
|
|
{
|
|
|
|
i2p::data::IdentityEx dest;
|
2014-12-01 19:50:10 +00:00
|
|
|
dest.FromBase64 (destination);
|
2014-11-28 20:08:23 +00:00
|
|
|
context.GetAddressBook ().InsertAddress (dest);
|
2015-02-01 02:49:54 +00:00
|
|
|
auto leaseSet = m_Session->localDestination->FindLeaseSet (dest.GetIdentHash ());
|
2014-09-25 17:58:09 +00:00
|
|
|
if (leaseSet)
|
2015-01-27 16:27:58 +00:00
|
|
|
Connect (leaseSet);
|
2014-10-02 16:42:28 +00:00
|
|
|
else
|
2014-09-25 17:58:09 +00:00
|
|
|
{
|
2014-12-27 02:06:24 +00:00
|
|
|
m_Session->localDestination->RequestDestination (dest.GetIdentHash (),
|
2015-01-24 20:34:46 +00:00
|
|
|
std::bind (&SAMSocket::HandleConnectLeaseSetRequestComplete,
|
2014-11-23 22:00:45 +00:00
|
|
|
shared_from_this (), std::placeholders::_1, dest.GetIdentHash ()));
|
2014-09-25 17:58:09 +00:00
|
|
|
}
|
2014-10-02 16:42:28 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
|
|
|
}
|
|
|
|
|
2015-01-27 16:27:58 +00:00
|
|
|
void SAMSocket::Connect (std::shared_ptr<const i2p::data::LeaseSet> remote)
|
2014-10-02 16:42:28 +00:00
|
|
|
{
|
|
|
|
m_SocketType = eSAMSocketTypeStream;
|
2014-11-22 21:35:58 +00:00
|
|
|
m_Session->sockets.push_back (shared_from_this ());
|
2014-10-22 18:01:23 +00:00
|
|
|
m_Stream = m_Session->localDestination->CreateStream (remote);
|
2014-10-02 16:42:28 +00:00
|
|
|
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
|
|
|
|
I2PReceive ();
|
|
|
|
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
|
|
|
}
|
|
|
|
|
2015-01-24 20:34:46 +00:00
|
|
|
void SAMSocket::HandleConnectLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident)
|
2014-10-02 16:42:28 +00:00
|
|
|
{
|
2015-01-27 16:27:58 +00:00
|
|
|
std::shared_ptr<const i2p::data::LeaseSet> leaseSet;
|
2015-02-01 02:49:54 +00:00
|
|
|
if (success)
|
2014-12-27 02:06:24 +00:00
|
|
|
leaseSet = m_Session->localDestination->FindLeaseSet (ident);
|
|
|
|
if (leaseSet)
|
2015-01-27 16:27:58 +00:00
|
|
|
Connect (leaseSet);
|
2014-12-27 02:06:24 +00:00
|
|
|
else
|
2014-10-02 16:42:28 +00:00
|
|
|
{
|
2014-12-27 02:06:24 +00:00
|
|
|
LogPrint ("SAM destination to connect not found");
|
|
|
|
SendMessageReply (SAM_STREAM_STATUS_CANT_REACH_PEER, strlen(SAM_STREAM_STATUS_CANT_REACH_PEER), true);
|
2014-09-25 17:58:09 +00:00
|
|
|
}
|
2014-09-26 19:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
|
|
|
|
{
|
2014-09-28 13:05:37 +00:00
|
|
|
LogPrint ("SAM stream accept: ", buf);
|
2014-09-26 19:40:57 +00:00
|
|
|
std::map<std::string, std::string> params;
|
|
|
|
ExtractParams (buf, len, params);
|
|
|
|
std::string& id = params[SAM_PARAM_ID];
|
2014-09-29 18:18:06 +00:00
|
|
|
std::string& silent = params[SAM_PARAM_SILENT];
|
|
|
|
if (silent == SAM_VALUE_TRUE) m_IsSilent = true;
|
2014-09-26 19:40:57 +00:00
|
|
|
m_ID = id;
|
2014-10-07 16:07:10 +00:00
|
|
|
m_Session = m_Owner.FindSession (id);
|
|
|
|
if (m_Session)
|
2014-09-26 19:40:57 +00:00
|
|
|
{
|
2014-10-22 18:01:23 +00:00
|
|
|
if (!m_Session->localDestination->IsAcceptingStreams ())
|
2014-09-26 19:40:57 +00:00
|
|
|
{
|
|
|
|
m_SocketType = eSAMSocketTypeAcceptor;
|
2014-11-22 21:35:58 +00:00
|
|
|
m_Session->sockets.push_back (shared_from_this ());
|
|
|
|
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
|
2014-09-28 13:05:37 +00:00
|
|
|
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
2014-09-26 19:40:57 +00:00
|
|
|
}
|
|
|
|
else
|
2014-09-28 13:05:37 +00:00
|
|
|
SendMessageReply (SAM_STREAM_STATUS_I2P_ERROR, strlen(SAM_STREAM_STATUS_I2P_ERROR), true);
|
2014-09-26 19:40:57 +00:00
|
|
|
}
|
|
|
|
else
|
2014-09-28 13:05:37 +00:00
|
|
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
|
2014-09-30 15:08:38 +00:00
|
|
|
void SAMSocket::ProcessDestGenerate ()
|
|
|
|
{
|
|
|
|
LogPrint ("SAM dest generate");
|
2014-10-16 14:28:44 +00:00
|
|
|
auto localDestination = i2p::client::context.CreateNewLocalDestination ();
|
2014-09-30 15:08:38 +00:00
|
|
|
if (localDestination)
|
|
|
|
{
|
2014-12-01 19:50:10 +00:00
|
|
|
auto priv = localDestination->GetPrivateKeys ().ToBase64 ();
|
|
|
|
auto pub = localDestination->GetIdentity ().ToBase64 ();
|
2014-10-27 21:53:01 +00:00
|
|
|
#ifdef _MSC_VER
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub.c_str (), priv.c_str ());
|
2014-10-23 23:04:46 +00:00
|
|
|
#else
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub.c_str (), priv.c_str ());
|
2014-10-27 21:53:01 +00:00
|
|
|
#endif
|
2014-09-30 15:08:38 +00:00
|
|
|
SendMessageReply (m_Buffer, len, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SendMessageReply (SAM_DEST_REPLY_I2P_ERROR, strlen(SAM_DEST_REPLY_I2P_ERROR), true);
|
|
|
|
}
|
|
|
|
|
2014-10-02 20:55:01 +00:00
|
|
|
void SAMSocket::ProcessNamingLookup (char * buf, size_t len)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM naming lookup: ", buf);
|
|
|
|
std::map<std::string, std::string> params;
|
|
|
|
ExtractParams (buf, len, params);
|
|
|
|
std::string& name = params[SAM_PARAM_NAME];
|
2014-11-26 21:51:36 +00:00
|
|
|
i2p::data::IdentityEx identity;
|
2015-01-24 20:34:46 +00:00
|
|
|
i2p::data::IdentHash ident;
|
2014-10-03 19:08:41 +00:00
|
|
|
if (name == "ME")
|
2015-01-24 20:34:46 +00:00
|
|
|
SendNamingLookupReply (m_Session->localDestination->GetIdentity ());
|
2014-11-26 21:51:36 +00:00
|
|
|
else if (context.GetAddressBook ().GetAddress (name, identity))
|
|
|
|
SendNamingLookupReply (identity);
|
2015-01-25 15:05:19 +00:00
|
|
|
else if (m_Session && m_Session->localDestination &&
|
|
|
|
context.GetAddressBook ().GetIdentHash (name, ident))
|
2015-01-24 20:34:46 +00:00
|
|
|
{
|
2015-01-27 16:27:58 +00:00
|
|
|
auto leaseSet = m_Session->localDestination->FindLeaseSet (ident);
|
2015-01-24 20:34:46 +00:00
|
|
|
if (leaseSet)
|
|
|
|
SendNamingLookupReply (leaseSet->GetIdentity ());
|
|
|
|
else
|
|
|
|
m_Session->localDestination->RequestDestination (ident,
|
|
|
|
std::bind (&SAMSocket::HandleNamingLookupLeaseSetRequestComplete,
|
|
|
|
shared_from_this (), std::placeholders::_1, ident));
|
|
|
|
}
|
2014-11-28 20:08:23 +00:00
|
|
|
else
|
2014-10-02 20:55:01 +00:00
|
|
|
{
|
2015-01-24 20:34:46 +00:00
|
|
|
LogPrint ("SAM naming failed. Unknown address ", name);
|
2014-10-27 21:53:01 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
|
2014-10-23 23:04:46 +00:00
|
|
|
#else
|
2014-10-02 20:55:01 +00:00
|
|
|
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
|
2014-10-27 21:53:01 +00:00
|
|
|
#endif
|
2014-10-03 19:08:41 +00:00
|
|
|
SendMessageReply (m_Buffer, len, false);
|
2014-10-02 20:55:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-24 20:34:46 +00:00
|
|
|
void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident)
|
2014-11-26 21:51:36 +00:00
|
|
|
{
|
2015-01-27 16:27:58 +00:00
|
|
|
std::shared_ptr<const i2p::data::LeaseSet> leaseSet;
|
2015-01-24 20:34:46 +00:00
|
|
|
if (success)
|
|
|
|
leaseSet = m_Session->localDestination->FindLeaseSet (ident);
|
2014-11-26 21:51:36 +00:00
|
|
|
if (leaseSet)
|
2015-01-24 20:34:46 +00:00
|
|
|
{
|
|
|
|
context.GetAddressBook ().InsertAddress (leaseSet->GetIdentity ());
|
|
|
|
SendNamingLookupReply (leaseSet->GetIdentity ());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LogPrint (eLogInfo, "SAM naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
|
|
|
|
context.GetAddressBook ().ToAddress (ident).c_str());
|
|
|
|
#else
|
|
|
|
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
|
|
|
|
context.GetAddressBook ().ToAddress (ident).c_str());
|
|
|
|
#endif
|
|
|
|
SendMessageReply (m_Buffer, len, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-26 21:51:36 +00:00
|
|
|
void SAMSocket::SendNamingLookupReply (const i2p::data::IdentityEx& identity)
|
2014-10-03 19:08:41 +00:00
|
|
|
{
|
2014-12-01 19:50:10 +00:00
|
|
|
auto base64 = identity.ToBase64 ();
|
2014-10-27 21:53:01 +00:00
|
|
|
#ifdef _MSC_VER
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ());
|
2014-10-23 23:04:46 +00:00
|
|
|
#else
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ());
|
2014-10-27 21:53:01 +00:00
|
|
|
#endif
|
2014-12-01 19:50:10 +00:00
|
|
|
SendMessageReply (m_Buffer, l, false);
|
2014-10-03 19:08:41 +00:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:22:25 +00:00
|
|
|
void SAMSocket::ExtractParams (char * buf, size_t len, std::map<std::string, std::string>& params)
|
|
|
|
{
|
2014-10-03 13:43:18 +00:00
|
|
|
char * separator;
|
|
|
|
do
|
2014-09-25 17:22:25 +00:00
|
|
|
{
|
2014-10-03 13:43:18 +00:00
|
|
|
separator = strchr (buf, ' ');
|
|
|
|
if (separator) *separator = 0;
|
2014-09-25 17:22:25 +00:00
|
|
|
char * value = strchr (buf, '=');
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
*value = 0;
|
|
|
|
value++;
|
|
|
|
params[buf] = value;
|
|
|
|
}
|
2014-09-28 13:05:37 +00:00
|
|
|
buf = separator + 1;
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
2014-10-03 13:43:18 +00:00
|
|
|
while (separator);
|
2014-09-25 17:22:25 +00:00
|
|
|
}
|
|
|
|
|
2014-09-24 18:59:03 +00:00
|
|
|
void SAMSocket::Receive ()
|
|
|
|
{
|
|
|
|
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived,
|
|
|
|
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM read error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_Stream)
|
2014-10-02 01:18:41 +00:00
|
|
|
m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred);
|
2014-09-24 18:59:03 +00:00
|
|
|
Receive ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-26 19:40:57 +00:00
|
|
|
void SAMSocket::I2PReceive ()
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
|
|
|
if (m_Stream)
|
|
|
|
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
|
|
|
|
std::placeholders::_1, std::placeholders::_2),
|
2014-09-24 18:59:03 +00:00
|
|
|
SAM_SOCKET_CONNECTION_MAX_IDLE);
|
|
|
|
}
|
|
|
|
|
2014-09-26 19:40:57 +00:00
|
|
|
void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM stream read error: ", ecode.message ());
|
2014-10-04 02:46:20 +00:00
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
2014-10-12 20:22:14 +00:00
|
|
|
Terminate ();
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-26 19:40:57 +00:00
|
|
|
void SAMSocket::HandleWriteI2PData (const boost::system::error_code& ecode)
|
2014-09-24 18:59:03 +00:00
|
|
|
{
|
|
|
|
if (ecode)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM socket write error: ", ecode.message ());
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Terminate ();
|
|
|
|
}
|
|
|
|
else
|
2014-09-26 19:40:57 +00:00
|
|
|
I2PReceive ();
|
2014-09-24 18:59:03 +00:00
|
|
|
}
|
|
|
|
|
2014-11-23 16:33:58 +00:00
|
|
|
void SAMSocket::HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
2014-09-26 19:40:57 +00:00
|
|
|
{
|
2014-09-29 18:18:06 +00:00
|
|
|
if (stream)
|
|
|
|
{
|
2014-10-05 20:19:25 +00:00
|
|
|
LogPrint ("SAM incoming I2P connection for session ", m_ID);
|
2014-09-29 18:18:06 +00:00
|
|
|
m_Stream = stream;
|
2014-11-28 20:08:23 +00:00
|
|
|
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
2014-09-29 18:18:06 +00:00
|
|
|
auto session = m_Owner.FindSession (m_ID);
|
|
|
|
if (session)
|
2014-10-22 18:01:23 +00:00
|
|
|
session->localDestination->StopAcceptingStreams ();
|
2014-09-29 18:18:06 +00:00
|
|
|
if (!m_IsSilent)
|
|
|
|
{
|
|
|
|
// send remote peer address
|
|
|
|
uint8_t ident[1024];
|
|
|
|
size_t l = stream->GetRemoteIdentity ().ToBuffer (ident, 1024);
|
2015-02-01 02:49:54 +00:00
|
|
|
size_t l1 = i2p::data::ByteStreamToBase64 (ident, l, (char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE);
|
|
|
|
m_StreamBuffer[l1] = '\n';
|
|
|
|
HandleI2PReceive (boost::system::error_code (), l1 +1); // we send identity like it has been received from stream
|
2014-09-29 18:18:06 +00:00
|
|
|
}
|
2015-02-01 02:49:54 +00:00
|
|
|
else
|
|
|
|
I2PReceive ();
|
2014-09-29 18:18:06 +00:00
|
|
|
}
|
2015-02-01 14:34:32 +00:00
|
|
|
else
|
|
|
|
LogPrint (eLogInfo, "SAM I2P acceptor has been reset");
|
2014-09-26 19:40:57 +00:00
|
|
|
}
|
|
|
|
|
2015-03-03 20:31:49 +00:00
|
|
|
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
2014-10-31 20:44:44 +00:00
|
|
|
{
|
2015-03-03 20:31:49 +00:00
|
|
|
auto base64 = from.ToBase64 ();
|
2014-10-31 20:44:44 +00:00
|
|
|
#ifdef _MSC_VER
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
|
2014-10-31 20:44:44 +00:00
|
|
|
#else
|
2014-12-01 19:50:10 +00:00
|
|
|
size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
|
2014-10-31 20:44:44 +00:00
|
|
|
#endif
|
2014-12-01 19:50:10 +00:00
|
|
|
if (len < SAM_SOCKET_BUFFER_SIZE - l)
|
2014-10-31 20:44:44 +00:00
|
|
|
{
|
2014-12-01 19:50:10 +00:00
|
|
|
memcpy (m_StreamBuffer + l, buf, len);
|
|
|
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l),
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
|
2014-10-31 20:44:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer");
|
|
|
|
}
|
|
|
|
|
2015-02-24 20:40:50 +00:00
|
|
|
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
|
2014-12-18 00:02:16 +00:00
|
|
|
localDestination (dest)
|
2014-12-17 20:21:50 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SAMSession::~SAMSession ()
|
|
|
|
{
|
|
|
|
for (auto it: sockets)
|
|
|
|
it->SetSocketType (eSAMSocketTypeTerminated);
|
|
|
|
i2p::client::context.DeleteLocalDestination (localDestination);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMSession::CloseStreams ()
|
|
|
|
{
|
|
|
|
for (auto it: sockets)
|
2014-12-18 23:48:36 +00:00
|
|
|
{
|
2014-12-17 20:21:50 +00:00
|
|
|
it->CloseStream ();
|
2014-12-18 23:48:36 +00:00
|
|
|
it->SetSocketType (eSAMSocketTypeTerminated);
|
|
|
|
}
|
2014-12-17 20:21:50 +00:00
|
|
|
sockets.clear ();
|
|
|
|
}
|
|
|
|
|
2014-09-24 16:01:26 +00:00
|
|
|
SAMBridge::SAMBridge (int port):
|
|
|
|
m_IsRunning (false), m_Thread (nullptr),
|
|
|
|
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
|
2014-11-22 21:35:58 +00:00
|
|
|
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
|
2014-09-24 16:01:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SAMBridge::~SAMBridge ()
|
|
|
|
{
|
2014-12-18 00:02:16 +00:00
|
|
|
if (m_IsRunning)
|
|
|
|
Stop ();
|
2014-09-24 16:01:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::Start ()
|
|
|
|
{
|
|
|
|
Accept ();
|
2014-10-22 20:42:26 +00:00
|
|
|
ReceiveDatagram ();
|
2014-09-28 13:05:37 +00:00
|
|
|
m_IsRunning = true;
|
2014-09-24 16:01:26 +00:00
|
|
|
m_Thread = new std::thread (std::bind (&SAMBridge::Run, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::Stop ()
|
|
|
|
{
|
|
|
|
m_IsRunning = false;
|
2014-12-17 20:21:50 +00:00
|
|
|
m_Acceptor.cancel ();
|
2014-12-18 00:02:16 +00:00
|
|
|
for (auto it: m_Sessions)
|
|
|
|
delete it.second;
|
2014-12-17 20:21:50 +00:00
|
|
|
m_Sessions.clear ();
|
2014-09-24 16:01:26 +00:00
|
|
|
m_Service.stop ();
|
|
|
|
if (m_Thread)
|
|
|
|
{
|
|
|
|
m_Thread->join ();
|
|
|
|
delete m_Thread;
|
|
|
|
m_Thread = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::Run ()
|
|
|
|
{
|
|
|
|
while (m_IsRunning)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
m_Service.run ();
|
|
|
|
}
|
|
|
|
catch (std::exception& ex)
|
|
|
|
{
|
|
|
|
LogPrint ("SAM: ", ex.what ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::Accept ()
|
|
|
|
{
|
2014-11-22 21:35:58 +00:00
|
|
|
auto newSocket = std::make_shared<SAMSocket> (*this);
|
2014-11-23 22:00:45 +00:00
|
|
|
m_Acceptor.async_accept (newSocket->GetSocket (), std::bind (&SAMBridge::HandleAccept, this,
|
|
|
|
std::placeholders::_1, newSocket));
|
2014-09-24 16:01:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-22 21:35:58 +00:00
|
|
|
void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
|
2014-09-24 16:01:26 +00:00
|
|
|
{
|
|
|
|
if (!ecode)
|
|
|
|
{
|
2015-02-22 22:04:42 +00:00
|
|
|
boost::system::error_code ec;
|
|
|
|
auto ep = socket->GetSocket ().remote_endpoint (ec);
|
|
|
|
if (!ec)
|
|
|
|
{
|
|
|
|
LogPrint ("New SAM connection from ", ep);
|
|
|
|
socket->ReceiveHandshake ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint (eLogError, "SAM connection from error ", ec.message ());
|
2014-09-24 16:01:26 +00:00
|
|
|
}
|
|
|
|
else
|
2014-09-28 13:05:37 +00:00
|
|
|
LogPrint ("SAM accept error: ", ecode.message ());
|
2014-09-24 16:01:26 +00:00
|
|
|
|
|
|
|
if (ecode != boost::asio::error::operation_aborted)
|
|
|
|
Accept ();
|
|
|
|
}
|
2014-09-24 20:39:31 +00:00
|
|
|
|
2014-11-30 15:51:22 +00:00
|
|
|
SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination,
|
|
|
|
const std::map<std::string, std::string> * params)
|
2014-09-24 20:39:31 +00:00
|
|
|
{
|
2015-02-24 20:40:50 +00:00
|
|
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
2014-09-25 17:22:25 +00:00
|
|
|
if (destination != "")
|
2014-09-24 20:39:31 +00:00
|
|
|
{
|
|
|
|
i2p::data::PrivateKeys keys;
|
2014-12-01 19:50:10 +00:00
|
|
|
keys.FromBase64 (destination);
|
2014-11-30 15:51:22 +00:00
|
|
|
localDestination = i2p::client::context.CreateNewLocalDestination (keys, true, params);
|
2014-09-24 20:39:31 +00:00
|
|
|
}
|
|
|
|
else // transient
|
2014-12-16 21:23:42 +00:00
|
|
|
{
|
|
|
|
// extract signature type
|
|
|
|
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
|
|
|
|
if (params)
|
|
|
|
{
|
|
|
|
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
|
|
|
|
if (it != params->end ())
|
|
|
|
// TODO: extract string values
|
|
|
|
signatureType = boost::lexical_cast<int> (it->second);
|
|
|
|
}
|
2015-02-01 14:34:32 +00:00
|
|
|
localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, params);
|
2014-12-16 21:23:42 +00:00
|
|
|
}
|
2014-09-24 20:39:31 +00:00
|
|
|
if (localDestination)
|
|
|
|
{
|
2014-10-06 01:59:05 +00:00
|
|
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
2014-12-18 00:02:16 +00:00
|
|
|
auto ret = m_Sessions.insert (std::pair<std::string, SAMSession *>(id, new SAMSession (localDestination)));
|
2014-10-01 18:52:32 +00:00
|
|
|
if (!ret.second)
|
|
|
|
LogPrint ("Session ", id, " already exists");
|
2014-12-18 00:02:16 +00:00
|
|
|
return ret.first->second;
|
2014-09-24 20:39:31 +00:00
|
|
|
}
|
2014-09-25 17:22:25 +00:00
|
|
|
return nullptr;
|
2014-09-24 20:39:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::CloseSession (const std::string& id)
|
|
|
|
{
|
2014-10-06 01:59:05 +00:00
|
|
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
2014-09-24 20:39:31 +00:00
|
|
|
auto it = m_Sessions.find (id);
|
|
|
|
if (it != m_Sessions.end ())
|
|
|
|
{
|
2014-12-18 00:02:16 +00:00
|
|
|
auto session = it->second;
|
2015-02-01 14:34:32 +00:00
|
|
|
session->localDestination->StopAcceptingStreams ();
|
2014-12-18 00:02:16 +00:00
|
|
|
session->CloseStreams ();
|
2014-09-24 20:39:31 +00:00
|
|
|
m_Sessions.erase (it);
|
2014-12-18 00:02:16 +00:00
|
|
|
delete session;
|
2014-09-24 20:39:31 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-25 17:22:25 +00:00
|
|
|
|
2015-02-21 03:47:36 +00:00
|
|
|
SAMSession * SAMBridge::FindSession (const std::string& id) const
|
2014-09-25 17:22:25 +00:00
|
|
|
{
|
2014-10-06 01:59:05 +00:00
|
|
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
2014-09-25 17:22:25 +00:00
|
|
|
auto it = m_Sessions.find (id);
|
|
|
|
if (it != m_Sessions.end ())
|
2014-12-18 00:02:16 +00:00
|
|
|
return it->second;
|
2014-09-25 17:22:25 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2014-10-22 20:42:26 +00:00
|
|
|
|
|
|
|
void SAMBridge::ReceiveDatagram ()
|
|
|
|
{
|
|
|
|
m_DatagramSocket.async_receive_from (
|
|
|
|
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
|
|
|
|
m_SenderEndpoint,
|
2014-11-23 22:00:45 +00:00
|
|
|
std::bind (&SAMBridge::HandleReceivedDatagram, this, std::placeholders::_1, std::placeholders::_2));
|
2014-10-22 20:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (!ecode)
|
|
|
|
{
|
2014-10-24 01:14:17 +00:00
|
|
|
m_DatagramReceiveBuffer[bytes_transferred] = 0;
|
|
|
|
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
|
|
|
|
*eol = 0; eol++;
|
|
|
|
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
|
|
|
|
LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
|
|
|
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
|
|
|
|
if (sessionID)
|
|
|
|
{
|
|
|
|
sessionID++;
|
|
|
|
char * destination = strchr (sessionID, ' ');
|
|
|
|
if (destination)
|
|
|
|
{
|
|
|
|
*destination = 0; destination++;
|
|
|
|
auto session = FindSession (sessionID);
|
|
|
|
if (session)
|
|
|
|
{
|
|
|
|
i2p::data::IdentityEx dest;
|
2014-12-01 19:50:10 +00:00
|
|
|
dest.FromBase64 (destination);
|
2014-10-24 01:14:17 +00:00
|
|
|
auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ());
|
|
|
|
if (leaseSet)
|
|
|
|
session->localDestination->GetDatagramDestination ()->
|
2015-01-29 02:37:08 +00:00
|
|
|
SendDatagramTo ((uint8_t *)eol, payloadLen, leaseSet);
|
2014-10-24 01:14:17 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
LogPrint ("SAM datagram destination not found");
|
2014-12-25 21:47:15 +00:00
|
|
|
session->localDestination->RequestDestination (dest.GetIdentHash ());
|
2014-10-24 01:14:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint ("Session ", sessionID, " not found");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint ("Missing destination key");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint ("Missing sessionID");
|
2014-10-22 20:42:26 +00:00
|
|
|
ReceiveDatagram ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
LogPrint ("SAM datagram receive error: ", ecode.message ());
|
|
|
|
}
|
2014-09-24 16:01:26 +00:00
|
|
|
}
|
|
|
|
}
|