From cc451809cca87842a8431eafe8bee601fa0bb5a8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 10 Jul 2019 11:32:56 -0400 Subject: [PATCH] send/receive raw datagrams through the SAM --- libi2pd_client/SAM.cpp | 77 +++++++++++++++++++++++++++++++++++------- libi2pd_client/SAM.h | 15 ++++++-- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index acb9ea80..24e28c73 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -337,8 +337,20 @@ namespace client return; } + SAMSessionType type = eSAMSessionTypeUnknown; + if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; + else if (style == SAM_VALUE_DATAGRAM) type = eSAMSessionTypeDatagram; + else if (style == SAM_VALUE_RAW) type = eSAMSessionTypeRaw; + if (type == eSAMSessionTypeUnknown) + { + // unknown style + SendI2PError("Unknown STYLE"); + return; + } + std::shared_ptr forward = nullptr; - if (style == SAM_VALUE_DATAGRAM && params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end()) + if ((type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) && + params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end()) { // udp forward selected boost::system::error_code e; @@ -379,16 +391,20 @@ namespace client } // create destination - auto session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms); + auto session = m_Owner.CreateSession (id, type, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms); if (session) { m_SocketType = eSAMSocketTypeSession; - if (style == SAM_VALUE_DATAGRAM) + if (type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) { session->UDPEndpoint = forward; auto dest = session->localDestination->CreateDatagramDestination (); - dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + if (type == eSAMSessionTypeDatagram) + dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + else // raw + dest->SetRawReceiver (std::bind (&SAMSocket::HandleI2PRawDatagramReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); } if (session->localDestination->IsReady ()) @@ -550,7 +566,10 @@ namespace client { i2p::data::IdentityEx dest; dest.FromBase64 (params[SAM_PARAM_DESTINATION]); - d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); + if (session->Type == eSAMSessionTypeDatagram) + d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); + else // raw + d->SendRawDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ()); } else LogPrint (eLogError, "SAM: missing datagram destination"); @@ -926,16 +945,44 @@ namespace client } } + void SAMSocket::HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + LogPrint (eLogDebug, "SAM: raw datagram received ", len); + auto session = m_Owner.FindSession(m_ID); + if(session) + { + auto ep = session->UDPEndpoint; + if (ep) + // udp forward enabled + m_Owner.SendTo(buf, len, ep); + else + { +#ifdef _MSC_VER + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); +#else + size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_RAW_RECEIVED, (long unsigned int)len); +#endif + if (len < SAM_SOCKET_BUFFER_SIZE - l) + { + memcpy (m_StreamBuffer + l, buf, len); + WriteI2PData(len + l); + } + else + LogPrint (eLogWarning, "SAM: received raw datagram size ", len," exceeds buffer"); + } + } + } + void SAMSocket::HandleStreamSend(const boost::system::error_code & ec) { m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); } - SAMSession::SAMSession (SAMBridge & parent, const std::string & id, std::shared_ptr dest): + SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type, std::shared_ptr dest): m_Bridge(parent), localDestination (dest), UDPEndpoint(nullptr), - Name(id) + Name(id), Type (type) { } @@ -1061,8 +1108,8 @@ namespace client Accept (); } - std::shared_ptr SAMBridge::CreateSession (const std::string& id, const std::string& destination, - const std::map * params) + std::shared_ptr SAMBridge::CreateSession (const std::string& id, SAMSessionType type, + const std::string& destination, const std::map * params) { std::shared_ptr localDestination = nullptr; if (destination != "") @@ -1102,7 +1149,7 @@ namespace client if (localDestination) { localDestination->Acquire (); - auto session = std::make_shared(*this, id, localDestination); + auto session = std::make_shared(*this, id, type, localDestination); std::unique_lock l(m_SessionsMutex); auto ret = m_Sessions.insert (std::make_pair(id, session)); if (!ret.second) @@ -1193,8 +1240,12 @@ namespace client { i2p::data::IdentityEx dest; dest.FromBase64 (destination); - session->localDestination->GetDatagramDestination ()-> - SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + if (session->Type == eSAMSessionTypeDatagram) + session->localDestination->GetDatagramDestination ()-> + SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + else // raw + session->localDestination->GetDatagramDestination ()-> + SendRawDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); } else LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 7cd3fd4c..44ad752d 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -46,6 +46,7 @@ namespace client const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP"; const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n"; const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n"; + const char SAM_RAW_RECEIVED[] = "RAW RECEIVED SIZE=%lu\n"; const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n"; const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=KEY_NOT_FOUND NAME=%s\n"; const char SAM_PARAM_MIN[] = "MIN"; @@ -111,6 +112,7 @@ namespace client void HandleI2PAccept (std::shared_ptr stream); void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz); void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void ProcessSessionCreate (char * buf, size_t len); void ProcessStreamConnect (char * buf, size_t len, size_t rem); @@ -149,14 +151,23 @@ namespace client std::shared_ptr m_Stream; }; + enum SAMSessionType + { + eSAMSessionTypeUnknown, + eSAMSessionTypeStream, + eSAMSessionTypeDatagram, + eSAMSessionTypeRaw + }; + struct SAMSession { SAMBridge & m_Bridge; std::shared_ptr localDestination; std::shared_ptr UDPEndpoint; std::string Name; + SAMSessionType Type; - SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); + SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest); ~SAMSession (); void CloseStreams (); @@ -173,7 +184,7 @@ namespace client void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient + std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const;