From 59d1695ee53f078768a16c4534347c448556f3b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 5 Jul 2025 21:06:49 -0400 Subject: [PATCH] use std::string_view to extract params --- libi2pd_client/SAM.cpp | 170 +++++++++++++++++++++-------------------- libi2pd_client/SAM.h | 31 ++++---- 2 files changed, 103 insertions(+), 98 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 96f2c2ee..90a1937f 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -11,6 +11,7 @@ #ifdef _MSC_VER #include #endif +#include #include "Base.h" #include "Identity.h" #include "Log.h" @@ -126,8 +127,7 @@ namespace client if (separator) { separator++; - std::map params; - ExtractParams (separator, params); + auto params = ExtractParams (separator); auto it = params.find (SAM_PARAM_MAX); if (it != params.end ()) maxver = it->second; @@ -172,7 +172,7 @@ namespace client } } - bool SAMSocket::IsSession(const std::string & id) const + bool SAMSocket::IsSession(std::string_view id) const { return id == m_ID; } @@ -314,7 +314,7 @@ namespace client } } - static bool IsAcceptableSessionName(const std::string & str) + static bool IsAcceptableSessionName(std::string_view str) { auto itr = str.begin(); while(itr != str.end()) @@ -330,11 +330,10 @@ namespace client void SAMSocket::ProcessSessionCreate (char * buf, size_t len) { LogPrint (eLogDebug, "SAM: Session create: ", buf); - std::map params; - ExtractParams (buf, params); - std::string& style = params[SAM_PARAM_STYLE]; - std::string& id = params[SAM_PARAM_ID]; - std::string& destination = params[SAM_PARAM_DESTINATION]; + auto params = ExtractParams (buf); + std::string_view style = params[SAM_PARAM_STYLE]; + std::string_view id = params[SAM_PARAM_ID]; + std::string_view destination = params[SAM_PARAM_DESTINATION]; if(!IsAcceptableSessionName(id)) { @@ -377,8 +376,10 @@ namespace client return; } - auto port = std::stoi(params[SAM_PARAM_PORT]); - if (port == -1) + uint16_t port = 0; + std::string_view p = params[SAM_PARAM_PORT]; + auto res = std::from_chars(p.data(), p.data() + p.size(), port); + if (res.ec != std::errc()) { SendSessionI2PError("Invalid port"); return; @@ -405,7 +406,7 @@ namespace client } // create destination - auto session = m_Owner.CreateSession (id, type, destination == SAM_VALUE_TRANSIENT ? "" : destination, ¶ms); + auto session = m_Owner.CreateSession (id, type, destination == SAM_VALUE_TRANSIENT ? "" : destination, params); if (session) { m_SocketType = eSAMSocketTypeSession; @@ -413,7 +414,13 @@ namespace client { session->UDPEndpoint = forward; auto dest = session->GetLocalDestination ()->CreateDatagramDestination (); - auto port = forward ? std::stoi(params[SAM_PARAM_PORT]) : 0; + uint16_t port = 0; + if (forward) + { + std::string_view p = params[SAM_PARAM_PORT]; + auto res = std::from_chars(p.data(), p.data() + p.size(), port); + if (res.ec != std::errc()) port = 0; + } 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), @@ -486,11 +493,10 @@ namespace client SendSessionI2PError ("Socket already in use"); return; } - std::map params; - ExtractParams (buf, params); - std::string& id = params[SAM_PARAM_ID]; - std::string& destination = params[SAM_PARAM_DESTINATION]; - std::string& silent = params[SAM_PARAM_SILENT]; + auto params = ExtractParams (buf); + std::string_view id = params[SAM_PARAM_ID]; + std::string_view destination = params[SAM_PARAM_DESTINATION]; + std::string_view silent = params[SAM_PARAM_SILENT]; if (silent == SAM_VALUE_TRUE) m_IsSilent = true; m_ID = id; auto session = m_Owner.FindSession (id); @@ -594,10 +600,9 @@ namespace client SendSessionI2PError ("Socket already in use"); return; } - std::map params; - ExtractParams (buf, params); - std::string& id = params[SAM_PARAM_ID]; - std::string& silent = params[SAM_PARAM_SILENT]; + auto params = ExtractParams (buf); + std::string_view id = params[SAM_PARAM_ID]; + std::string_view silent = params[SAM_PARAM_SILENT]; if (silent == SAM_VALUE_TRUE) m_IsSilent = true; m_ID = id; auto session = m_Owner.FindSession (id); @@ -640,17 +645,15 @@ namespace client void SAMSocket::ProcessStreamForward(char* buf, size_t len) { LogPrint(eLogDebug, "SAM: Stream forward: ", buf); - - std::map params; - ExtractParams(buf, params); - + + auto params = ExtractParams(buf); const auto itId = params.find(SAM_PARAM_ID); if (itId == params.end()) { SendSessionI2PError("Missing ID"); return; } - const std::string& id = itId->second; + std::string_view id = itId->second; auto session = m_Owner.FindSession(id); if (!session) @@ -671,15 +674,16 @@ namespace client return; } - const std::string& portStr = itPort->second; + std::string_view portStr = itPort->second; if (!std::all_of(portStr.begin(), portStr.end(), ::isdigit)) { SendSessionI2PError("Port must be numeric"); return; } - int port = std::stoi(portStr); - if (port <= 0 || port >= 0xFFFF) + uint16_t port = 0; + auto res = std::from_chars(portStr.data(), portStr.data() + portStr.size(), port); + if (res.ec != std::errc()) { SendSessionI2PError("Invalid port"); return; @@ -729,9 +733,12 @@ namespace client size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data) { LogPrint (eLogDebug, "SAM: Datagram send: ", buf, " ", len); - std::map params; - ExtractParams (buf, params); - size_t size = std::stoi(params[SAM_PARAM_SIZE]), offset = data - buf; + auto params = ExtractParams (buf); + size_t size = 0; + std::string_view sizeStr = params[SAM_PARAM_SIZE]; + auto res = std::from_chars(sizeStr.data(), sizeStr.data() + sizeStr.size(), size); + if (res.ec != std::errc()) size = 0; + size_t offset = data - buf; if (offset + size <= len) { auto session = m_Owner.FindSession(m_ID); @@ -764,8 +771,7 @@ namespace client void SAMSocket::ProcessDestGenerate (char * buf, size_t len) { LogPrint (eLogDebug, "SAM: Dest generate"); - std::map params; - ExtractParams (buf, params); + auto params = ExtractParams (buf); // extract signature type i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; @@ -780,7 +786,7 @@ namespace client { try { - cryptoType = std::stoi(it->second); + cryptoType = std::stoi(std::string (it->second)); } catch (const std::exception& ex) { @@ -801,9 +807,8 @@ namespace client void SAMSocket::ProcessNamingLookup (char * buf, size_t len) { LogPrint (eLogDebug, "SAM: Naming lookup: ", buf); - std::map params; - ExtractParams (buf, params); - std::string& name = params[SAM_PARAM_NAME]; + auto params = ExtractParams (buf); + std::string name (params[SAM_PARAM_NAME]); std::shared_ptr identity; std::shared_ptr addr; auto session = m_Owner.FindSession(m_ID); @@ -848,16 +853,15 @@ namespace client { 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]; + auto params = ExtractParams (buf); + std::string_view 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]; + std::string_view style = params[SAM_PARAM_STYLE]; SAMSessionType type = eSAMSessionTypeUnknown; if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; // TODO: implement other styles @@ -867,7 +871,7 @@ namespace client SendSessionI2PError("Unsupported STYLE"); return; } - auto fromPort = std::stoi(params[SAM_PARAM_FROM_PORT]); + auto fromPort = std::stoi(std::string (params[SAM_PARAM_FROM_PORT])); if (fromPort == -1) { SendSessionI2PError("Invalid from port"); @@ -876,7 +880,7 @@ namespace client auto subsession = std::make_shared(masterSession, id, type, fromPort); if (m_Owner.AddSession (subsession)) { - masterSession->subsessions.insert (id); + masterSession->subsessions.insert (std::string (id)); SendSessionCreateReplyOk (); } else @@ -893,9 +897,8 @@ namespace client { 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]; + auto params = ExtractParams (buf); + 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); @@ -965,8 +968,9 @@ namespace client SendMessageReply (m_Buffer, l, false); } - void SAMSocket::ExtractParams (char * buf, std::map& params) + const std::map SAMSocket::ExtractParams (char * buf) { + std::map params; char * separator; do { @@ -977,11 +981,12 @@ namespace client { *value = 0; value++; - params[buf] = value; + params.emplace (buf, value); } buf = separator + 1; } while (separator); + return params; } void SAMSocket::Receive () @@ -1289,7 +1294,7 @@ namespace client boost::asio::post (m_Owner.GetService (), std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); } - SAMSession::SAMSession (SAMBridge & parent, const std::string & id, SAMSessionType type): + SAMSession::SAMSession (SAMBridge & parent, std::string_view id, SAMSessionType type): m_Bridge(parent), Name(id), Type (type), UDPEndpoint(nullptr) { } @@ -1302,7 +1307,7 @@ namespace client } } - SAMSingleSession::SAMSingleSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest): + SAMSingleSession::SAMSingleSession (SAMBridge & parent, std::string_view name, SAMSessionType type, std::shared_ptr dest): SAMSession (parent, name, type), localDestination (dest) { @@ -1331,7 +1336,7 @@ namespace client subsessions.clear (); } - SAMSubSession::SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, uint16_t port): + SAMSubSession::SAMSubSession (std::shared_ptr master, std::string_view name, SAMSessionType type, uint16_t port): SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port) { if (Type == eSAMSessionTypeStream) @@ -1452,37 +1457,38 @@ namespace client Accept (); } - std::shared_ptr SAMBridge::CreateSession (const std::string& id, SAMSessionType type, - const std::string& destination, const std::map * params) + std::shared_ptr SAMBridge::CreateSession (std::string_view id, SAMSessionType type, + std::string_view destination, const std::map& params) { + std::map p(params.begin (), params.end ()); std::shared_ptr localDestination = nullptr; if (destination != "") { i2p::data::PrivateKeys keys; if (!keys.FromBase64 (destination)) return nullptr; localDestination = m_IsSingleThread ? - i2p::client::context.CreateNewLocalDestination (GetIOService (), keys, true, params) : - i2p::client::context.CreateNewLocalDestination (keys, true, params); + i2p::client::context.CreateNewLocalDestination (GetIOService (), keys, true, &p) : + i2p::client::context.CreateNewLocalDestination (keys, true, &p); } else // transient { // extract signature type i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; - if (params) + if (!params.empty ()) { - auto it = params->find (SAM_PARAM_SIGNATURE_TYPE); - if (it != params->end ()) + auto it = params.find (SAM_PARAM_SIGNATURE_TYPE); + if (it != params.end ()) { if (!ResolveSignatureType (it->second, signatureType)) LogPrint (eLogWarning, "SAM: ", SAM_PARAM_SIGNATURE_TYPE, " is invalid ", it->second); } - it = params->find (SAM_PARAM_CRYPTO_TYPE); - if (it != params->end ()) + it = params.find (SAM_PARAM_CRYPTO_TYPE); + if (it != params.end ()) { try { - cryptoType = std::stoi(it->second); + cryptoType = std::stoi(std::string (it->second)); } catch (const std::exception& ex) { @@ -1491,8 +1497,8 @@ namespace client } } localDestination = m_IsSingleThread ? - i2p::client::context.CreateNewLocalDestination (GetIOService (), true, signatureType, cryptoType, params) : - i2p::client::context.CreateNewLocalDestination (true, signatureType, cryptoType, params); + i2p::client::context.CreateNewLocalDestination (GetIOService (), true, signatureType, cryptoType, &p) : + i2p::client::context.CreateNewLocalDestination (true, signatureType, cryptoType, &p); } if (localDestination) { @@ -1500,7 +1506,7 @@ namespace client auto session = (type == eSAMSessionTypeMaster) ? std::make_shared(*this, id, localDestination) : std::make_shared(*this, id, type, localDestination); std::unique_lock l(m_SessionsMutex); - auto ret = m_Sessions.insert (std::make_pair(id, session)); + auto ret = m_Sessions.emplace (id, session); if (!ret.second) LogPrint (eLogWarning, "SAM: Session ", id, " already exists"); return ret.first->second; @@ -1515,7 +1521,7 @@ namespace client return ret.second; } - void SAMBridge::CloseSession (const std::string& id) + void SAMBridge::CloseSession (std::string_view id) { std::shared_ptr session; { @@ -1565,7 +1571,7 @@ namespace client // session's destructor is called here unless rescheduled } - std::shared_ptr SAMBridge::FindSession (const std::string& id) const + std::shared_ptr SAMBridge::FindSession (std::string_view id) const { std::unique_lock l(m_SessionsMutex); auto it = m_Sessions.find (id); @@ -1574,7 +1580,7 @@ namespace client return nullptr; } - std::list > SAMBridge::ListSockets(const std::string & id) const + std::list > SAMBridge::ListSockets(std::string_view id) const { std::list > list; { @@ -1654,25 +1660,23 @@ namespace client LogPrint (eLogError, "SAM: Datagram receive error: ", ecode.message ()); } - bool SAMBridge::ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const + bool SAMBridge::ResolveSignatureType (std::string_view name, i2p::data::SigningKeyType& type) const { - try + auto res = std::from_chars(name.data(), name.data() + name.size(), type); + if (res.ec != std::errc()) { - type = std::stoi (name); - } - catch (const std::invalid_argument& ex) - { - // name is not numeric, resolving - auto it = m_SignatureTypes.find (name); - if (it != m_SignatureTypes.end ()) - type = it->second; + if (res.ec == std::errc::invalid_argument) + { + // name is not numeric, resolving + auto it = m_SignatureTypes.find (name); + if (it != m_SignatureTypes.end ()) + type = it->second; + else + return false; + } else return false; } - catch (const std::exception& ex) - { - return false; - } // name has been resolved return true; } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index cd619678..acc17e20 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,7 @@ namespace client void Terminate (const char* reason); - bool IsSession(const std::string & id) const; + bool IsSession(std::string_view id) const; private: @@ -151,7 +152,7 @@ namespace client void SendStreamI2PError(const std::string & msg); void SendStreamCantReachPeer(const std::string & msg); size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0 - void ExtractParams (char * buf, std::map& params); + const std::map ExtractParams (char * buf); void Connect (std::shared_ptr remote, std::shared_ptr session = nullptr); void HandleConnectLeaseSetRequestComplete (std::shared_ptr leaseSet); @@ -199,7 +200,7 @@ namespace client std::shared_ptr UDPEndpoint; // TODO: move std::list, uint64_t> > acceptQueue; // socket, receive time in seconds - SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type); + SAMSession (SAMBridge & parent, std::string_view name, SAMSessionType type); virtual ~SAMSession () {}; virtual std::shared_ptr GetLocalDestination () = 0; @@ -213,7 +214,7 @@ namespace client { std::shared_ptr localDestination; - SAMSingleSession (SAMBridge & parent, const std::string & name, SAMSessionType type, std::shared_ptr dest); + SAMSingleSession (SAMBridge & parent, std::string_view name, SAMSessionType type, std::shared_ptr dest); ~SAMSingleSession (); std::shared_ptr GetLocalDestination () { return localDestination; }; @@ -222,8 +223,8 @@ namespace client struct SAMMasterSession: public SAMSingleSession { - std::set subsessions; - SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest): + std::set > subsessions; + SAMMasterSession (SAMBridge & parent, std::string_view name, std::shared_ptr dest): SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; void Close (); }; @@ -233,7 +234,7 @@ namespace client std::shared_ptr masterSession; uint16_t inPort; - SAMSubSession (std::shared_ptr master, const std::string& name, SAMSessionType type, uint16_t port); + SAMSubSession (std::shared_ptr master, std::string_view name, SAMSessionType type, uint16_t port); // implements SAMSession std::shared_ptr GetLocalDestination (); void StopLocalDestination (); @@ -250,13 +251,13 @@ namespace client void Stop (); auto& 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); + std::shared_ptr CreateSession (std::string_view id, SAMSessionType type, std::string_view 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; + void CloseSession (std::string_view id); + std::shared_ptr FindSession (std::string_view id) const; - std::list > ListSockets(const std::string & id) const; + std::list > ListSockets(std::string_view id) const; /** send raw data to remote endpoint from our UDP Socket */ void SendTo (const std::vector& bufs, const boost::asio::ip::udp::endpoint& ep); @@ -264,7 +265,7 @@ namespace client void AddSocket(std::shared_ptr socket); void RemoveSocket(const std::shared_ptr & socket); - bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const; + bool ResolveSignatureType (std::string_view name, i2p::data::SigningKeyType& type) const; private: @@ -285,11 +286,11 @@ namespace client boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; - std::map > m_Sessions; + std::map, std::less<>> m_Sessions; mutable std::mutex m_OpenSocketsMutex; std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; - std::map m_SignatureTypes; + const std::map m_SignatureTypes; public: