diff --git a/libi2pd/Datagram.cpp b/libi2pd/Datagram.cpp index 7440f6ba..516dc057 100644 --- a/libi2pd/Datagram.cpp +++ b/libi2pd/Datagram.cpp @@ -56,7 +56,8 @@ namespace datagram return ObtainSession(ident); } - void DatagramDestination::SendDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) + void DatagramDestination::SendDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, + uint16_t fromPort, uint16_t toPort, const i2p::util::Mapping * options) { if (session) { @@ -65,9 +66,18 @@ namespace datagram { case eDatagramV3: { - constexpr uint8_t flags[] = { 0x00, 0x03 }; // datagram3, no options - msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32}, - {flags, 2}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3 + uint8_t flags[] = { 0x00, 0x03 }; // datagram3, no options + if (options) + { + uint8_t optionsBuf[256]; // TODO: evaluate actual size + size_t optionsLen = options->ToBuffer (optionsBuf, 256); + if (optionsLen) flags[1] |= DATAGRAM3_FLAG_OPTIONS; + msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32}, {flags, 2}, + {optionsBuf, optionsLen}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3 + } + else + msg = CreateDataMessage ({{m_Owner->GetIdentity ()->GetIdentHash (), 32}, + {flags, 2}, {payload, len}}, fromPort, toPort, i2p::client::PROTOCOL_TYPE_DATAGRAM3, false); // datagram3 break; } case eDatagramV1: diff --git a/libi2pd/Datagram.h b/libi2pd/Datagram.h index cbe0e6c3..d9d5fedc 100644 --- a/libi2pd/Datagram.h +++ b/libi2pd/Datagram.h @@ -134,12 +134,13 @@ namespace datagram DatagramDestination (std::shared_ptr owner, bool gzip, DatagramVersion version); ~DatagramDestination (); - void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); - void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); + void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); + void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); // TODO: implement calls from other thread from SAM std::shared_ptr GetSession(const i2p::data::IdentHash & ident); - void SendDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); + void SendDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, + uint16_t fromPort, uint16_t toPort, const i2p::util::Mapping * options = nullptr); void SendRawDatagram (std::shared_ptr session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void FlushSendQueue (std::shared_ptr session); diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index e9eb6f20..94f3cd43 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -266,7 +266,7 @@ namespace util return { (const char *)(buf + 1), l }; } - size_t Mapping::ToBuffer (uint8_t * buf, size_t len) + size_t Mapping::ToBuffer (uint8_t * buf, size_t len) const { size_t offset = 2; for (auto it: m_Options) diff --git a/libi2pd/util.h b/libi2pd/util.h index 006fbee3..fd52e39d 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #ifdef ANDROID @@ -234,7 +235,7 @@ namespace util Mapping () = default; size_t FromBuffer (const uint8_t * buf, size_t len); size_t FromBuffer (size_t size, const uint8_t * buf, size_t len); //without 2 bytes size - size_t ToBuffer (uint8_t * buf, size_t len); + size_t ToBuffer (uint8_t * buf, size_t len) const; std::string_view operator[](std::string_view param) const; bool Insert (std::string_view param, std::string_view value); @@ -244,6 +245,20 @@ namespace util static std::string_view ExtractString (const uint8_t * buf, size_t len); static size_t WriteString (std::string_view str, uint8_t * buf, size_t len); static size_t WriteOption (std::string_view param, std::string_view value, uint8_t * buf, size_t len); + + template + bool Get(std::string_view param, T& value) + { + auto s = (*this)[param]; + if (s.empty ()) return false; + auto res = std::from_chars(s.data(), s.data() + s.size(), value); + return res.ec != std::errc(); + } + template + bool Put (std::string_view param, T value) + { + return Insert (param, std::to_string (value)); + } private: