From 218b26ebd91fbc2cc440782a7a5142ee679126d1 Mon Sep 17 00:00:00 2001 From: PobreGato <315121269+pobregat0@users.noreply.github.com> Date: Fri, 14 Aug 2026 04:14:16 +0300 Subject: [PATCH] datagram and raw subsessions for SAM 3.3 --- libi2pd_client/SAM.cpp | 63 +++++++++++++++++++++++++++++++++++++++++- libi2pd_client/SAM.h | 1 + 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 1282c26a..b5240307 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -886,20 +886,81 @@ namespace client } std::string_view style = params[SAM_PARAM_STYLE]; SAMSessionType type = SAMSessionType::eSAMSessionTypeUnknown; + i2p::datagram::DatagramVersion datagramVersion = i2p::datagram::eDatagramV1; if (style == SAM_VALUE_STREAM) type = SAMSessionType::eSAMSessionTypeStream; - // TODO: implement other styles +#if __cplusplus >= 202002L // C++20 + else if (style.starts_with (SAM_VALUE_DATAGRAM)) +#else + else if (style.substr (0, SAM_VALUE_DATAGRAM.size ()) == SAM_VALUE_DATAGRAM) +#endif + { + // DATAGRAM, DATAGRAM1, DATAGRAM2, DATAGRAM3 + type = SAMSessionType::eSAMSessionTypeDatagram; + if (style.size () > SAM_VALUE_DATAGRAM.size ()) + { + switch (style[SAM_VALUE_DATAGRAM.size ()]) + { + case '1': datagramVersion = i2p::datagram::eDatagramV1; break; + case '2': datagramVersion = i2p::datagram::eDatagramV2; break; + case '3': datagramVersion = i2p::datagram::eDatagramV3; break; + default: type = SAMSessionType::eSAMSessionTypeUnknown; + } + } + } + else if (style == SAM_VALUE_RAW) type = SAMSessionType::eSAMSessionTypeRaw; if (type == SAMSessionType::eSAMSessionTypeUnknown) { // unknown style SendSessionI2PError("Unsupported STYLE"); return; } + + std::shared_ptr forward = nullptr; + if ((type == SAMSessionType::eSAMSessionTypeDatagram || type == SAMSessionType::eSAMSessionTypeRaw) && + params.Contains (SAM_PARAM_HOST) && params.Contains (SAM_PARAM_PORT)) + { + // udp forward selected + boost::system::error_code e; + auto addr = boost::asio::ip::make_address (params[SAM_PARAM_HOST], e); + if (e) + { + SendSessionI2PError("Invalid IP Address in HOST"); + return; + } + uint16_t port = 0; + if (!params.Get (SAM_PARAM_PORT, port)) + { + SendSessionI2PError("Invalid port"); + return; + } + forward = std::make_shared(addr, port); + } + uint16_t fromPort = 0; params.Get (SAM_PARAM_FROM_PORT, fromPort); + // traffic from I2P is routed by port, LISTEN_PORT defaults to FROM_PORT + uint16_t listenPort = fromPort; + params.Get (SAM_PARAM_LISTEN_PORT, listenPort); auto subsession = std::make_shared(masterSession, id, type, fromPort); if (m_Owner.AddSession (subsession)) { + if (type == SAMSessionType::eSAMSessionTypeDatagram || type == SAMSessionType::eSAMSessionTypeRaw) + { + subsession->DatagramVersion = datagramVersion; + subsession->UDPEndpoint = forward; + auto dest = masterSession->GetLocalDestination ()->CreateDatagramDestination (true, datagramVersion); + if (type == SAMSessionType::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, std::placeholders::_6), + listenPort); + else + dest->SetRawReceiver (std::bind (&SAMSocket::HandleI2PRawDatagramReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4), + listenPort); + } masterSession->subsessions.insert (std::string (id)); SendSessionCreateReplyOk (); } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index c65c1870..0f2e63a6 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -81,6 +81,7 @@ namespace client const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE"; const char SAM_PARAM_SIZE[] = "SIZE"; const char SAM_PARAM_HOST[] = "HOST"; + const char SAM_PARAM_LISTEN_PORT[] = "LISTEN_PORT"; const char SAM_PARAM_PORT[] = "PORT"; const char SAM_PARAM_FROM_PORT[] = "FROM_PORT"; const char SAM_PARAM_TO_PORT[] = "TO_PORT";