diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 061cc820..af9ba6a8 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -765,12 +765,69 @@ namespace client void SAMSocket::ProcessSessionAdd (char * buf, size_t len) { - // TODO: implement + auto session = m_Owner.FindSession(m_ID); + if (session && session->Type == eSAMSessionTypeMaster) + { + LogPrint (eLogDebug, "SAM: subsession add: ", buf); + auto masterSession = std::static_pointer_cast(session); + std::map params; + ExtractParams (buf, params); + std::string& id = params[SAM_PARAM_ID]; + if (masterSession->subsessions.count (id) > 1) + { + // session exists + SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); + return; + } + std::string& style = params[SAM_PARAM_STYLE]; + SAMSessionType type = eSAMSessionTypeUnknown; + if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; + // TODO: implement other styles + if (type == eSAMSessionTypeUnknown) + { + // unknown style + SendI2PError("Unsupported STYLE"); + return; + } + auto fromPort = std::stoi(params[SAM_PARAM_FROM_PORT]); + if (fromPort == -1) + { + SendI2PError("Invalid from port"); + return; + } + auto subsession = std::make_shared(masterSession, id, type, fromPort); + if (m_Owner.AddSession (subsession)) + { + masterSession->subsessions.insert (id); + SendSessionCreateReplyOk (); + } + else + SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); + } + else + SendI2PError ("Wrong session type"); } void SAMSocket::ProcessSessionRemove (char * buf, size_t len) { - // TODO: implement + auto session = m_Owner.FindSession(m_ID); + if (session && session->Type == eSAMSessionTypeMaster) + { + LogPrint (eLogDebug, "SAM: subsession remove: ", buf); + auto masterSession = std::static_pointer_cast(session); + std::map params; + ExtractParams (buf, params); + std::string& id = params[SAM_PARAM_ID]; + if (!masterSession->subsessions.erase (id)) + { + SendMessageReply (SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), false); + return; + } + m_Owner.CloseSession (id); + SendSessionCreateReplyOk (); + } + else + SendI2PError ("Wrong session type"); } void SAMSocket::SendI2PError(const std::string & msg) @@ -1153,6 +1210,14 @@ namespace client localDestination->StopAcceptingStreams (); } + void SAMMasterSession::Close () + { + SAMSingleSession::Close (); + for (const auto& it: subsessions) + m_Bridge.CloseSession (it); + subsessions.clear (); + } + SAMSubSession::SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, int port): SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port) { @@ -1225,7 +1290,7 @@ namespace client { std::unique_lock l(m_SessionsMutex); for (auto& it: m_Sessions) - it.second->CloseStreams (); + it.second->Close (); m_Sessions.clear (); } StopIOService (); @@ -1328,6 +1393,13 @@ namespace client return nullptr; } + bool SAMBridge::AddSession (std::shared_ptr session) + { + if (!session) return false; + auto ret = m_Sessions.emplace (session->Name, session); + return ret.second; + } + void SAMBridge::CloseSession (const std::string& id) { std::shared_ptr session; @@ -1343,7 +1415,7 @@ namespace client if (session) { session->StopLocalDestination (); - session->CloseStreams (); + session->Close (); if (m_IsSingleThread) { auto timer = std::make_shared(GetService ()); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 8669538a..d92cf009 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -74,6 +75,7 @@ namespace client const char SAM_PARAM_SIZE[] = "SIZE"; const char SAM_PARAM_HOST[] = "HOST"; const char SAM_PARAM_PORT[] = "PORT"; + const char SAM_PARAM_FROM_PORT[] = "FROM_PORT"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; @@ -192,6 +194,7 @@ namespace client virtual std::shared_ptr GetLocalDestination () = 0; virtual void StopLocalDestination () = 0; + virtual void Close () { CloseStreams (); }; void CloseStreams (); }; @@ -209,8 +212,10 @@ namespace client struct SAMMasterSession: public SAMSingleSession { + std::set subsessions; SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest): SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; + void Close (); }; struct SAMSubSession: public SAMSession @@ -237,6 +242,7 @@ namespace client boost::asio::io_service& GetService () { return GetIOService (); }; std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); + bool AddSession (std::shared_ptr session); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const;