From 9ddfc750e590bd28accadf268440581311ed3b87 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 19 May 2016 00:00:00 +0000 Subject: [PATCH 01/37] * update manpage: add --logfile description (#495) --- debian/i2pd.1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index f61e243e..7409cd49 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -36,6 +36,9 @@ Where to write pidfile (don\'t write by default) \fB\-\-log=\fR Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility) .TP +\fB\-\-logfile\fR +Path to logfile (default - autodetect) +.TP \fB\-\-loglevel=\fR Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR) .TP From 89d2505a7cf363d69cb89725ca521c48837579c9 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 19 May 2016 00:00:00 +0000 Subject: [PATCH 02/37] * fix time in webconsole (#496) --- HTTPServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 81515105..4e44e6f9 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -241,15 +241,15 @@ namespace http { if ((num = seconds / 86400) > 0) { s << num << " days, "; - seconds -= num; + seconds -= num * 86400; } if ((num = seconds / 3600) > 0) { s << num << " hours, "; - seconds -= num; + seconds -= num * 3600; } if ((num = seconds / 60) > 0) { s << num << " min, "; - seconds -= num; + seconds -= num * 60; } s << seconds << " seconds"; } From cb68d19bed3a17b677f3b450da738b50025acd88 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 May 2016 10:33:01 -0400 Subject: [PATCH 03/37] ClientDestination/LeaseSetDestination split --- Datagram.cpp | 2 +- Datagram.h | 6 +-- Destination.cpp | 139 +++++++++++++++++++++++++----------------------- Destination.h | 39 +++++++++----- Streaming.cpp | 2 +- Streaming.h | 8 +-- 6 files changed, 107 insertions(+), 89 deletions(-) diff --git a/Datagram.cpp b/Datagram.cpp index 2015622c..f06d62da 100644 --- a/Datagram.cpp +++ b/Datagram.cpp @@ -11,7 +11,7 @@ namespace i2p { namespace datagram { - DatagramDestination::DatagramDestination (std::shared_ptr owner): + DatagramDestination::DatagramDestination (std::shared_ptr owner): m_Owner (owner), m_Receiver (nullptr) { } diff --git a/Datagram.h b/Datagram.h index c593fad2..404facf2 100644 --- a/Datagram.h +++ b/Datagram.h @@ -14,7 +14,7 @@ namespace i2p { namespace client { - class ClientDestination; + class LeaseSetDestination; } namespace datagram { @@ -25,7 +25,7 @@ namespace datagram public: - DatagramDestination (std::shared_ptr owner); + DatagramDestination (std::shared_ptr owner); ~DatagramDestination (); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); @@ -47,7 +47,7 @@ namespace datagram private: - std::shared_ptr m_Owner; + std::shared_ptr m_Owner; Receiver m_Receiver; // default std::map m_ReceiversByPorts; diff --git a/Destination.cpp b/Destination.cpp index f487b9ad..4712ac09 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -13,17 +13,12 @@ namespace i2p { namespace client { - ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, - const std::map * params): + LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map * params): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0), + m_IsPublic (isPublic), m_PublishReplyToken (0), m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service) { - if (m_IsPublic) - PersistTemporaryKeys (); - else - i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY; @@ -103,11 +98,9 @@ namespace client m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity); if (explicitPeers) m_Pool->SetExplicitPeers (explicitPeers); - if (m_IsPublic) - LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); } - ClientDestination::~ClientDestination () + LeaseSetDestination::~LeaseSetDestination () { if (m_IsRunning) Stop (); @@ -120,7 +113,7 @@ namespace client delete m_DatagramDestination; } - void ClientDestination::Run () + void LeaseSetDestination::Run () { while (m_IsRunning) { @@ -135,26 +128,26 @@ namespace client } } - void ClientDestination::Start () + void LeaseSetDestination::Start () { if (!m_IsRunning) { m_IsRunning = true; m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetActive (true); - m_Thread = new std::thread (std::bind (&ClientDestination::Run, shared_from_this ())); + m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); m_StreamingDestination = std::make_shared (shared_from_this ()); // TODO: m_StreamingDestination->Start (); for (auto it: m_StreamingDestinationsByPorts) it.second->Start (); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); - m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer, + m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); } } - void ClientDestination::Stop () + void LeaseSetDestination::Stop () { if (m_IsRunning) { @@ -187,7 +180,7 @@ namespace client } } - std::shared_ptr ClientDestination::FindLeaseSet (const i2p::data::IdentHash& ident) + std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) { auto it = m_RemoteLeaseSets.find (ident); if (it != m_RemoteLeaseSets.end ()) @@ -210,7 +203,7 @@ namespace client return nullptr; } - std::shared_ptr ClientDestination::GetLeaseSet () + std::shared_ptr LeaseSetDestination::GetLeaseSet () { if (!m_Pool) return nullptr; if (!m_LeaseSet) @@ -218,12 +211,12 @@ namespace client return m_LeaseSet; } - void ClientDestination::UpdateLeaseSet () + void LeaseSetDestination::UpdateLeaseSet () { m_LeaseSet.reset (new i2p::data::LeaseSet (m_Pool)); } - bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) + bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) { struct { @@ -239,17 +232,17 @@ namespace client return true; } - void ClientDestination::ProcessGarlicMessage (std::shared_ptr msg) + void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, shared_from_this (), msg)); + m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); } - void ClientDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) + void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); + m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); } - void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) + void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; switch (typeID) @@ -272,7 +265,7 @@ namespace client } } - void ClientDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) + void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) { uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); size_t offset = DATABASE_STORE_HEADER_SIZE; @@ -336,7 +329,7 @@ namespace client } } - void ClientDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len) + void LeaseSetDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len) { i2p::data::IdentHash key (buf); int num = buf[32]; // num @@ -379,7 +372,7 @@ namespace client LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); } - void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) + void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); if (msgID == m_PublishReplyToken) @@ -389,14 +382,14 @@ namespace client m_PublishReplyToken = 0; // schedule verification m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); - m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer, + m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, shared_from_this (), std::placeholders::_1)); } else i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); } - void ClientDestination::SetLeaseSetUpdated () + void LeaseSetDestination::SetLeaseSetUpdated () { i2p::garlic::GarlicDestination::SetLeaseSetUpdated (); UpdateLeaseSet (); @@ -407,7 +400,7 @@ namespace client } } - void ClientDestination::Publish () + void LeaseSetDestination::Publish () { if (!m_LeaseSet || !m_Pool) { @@ -437,12 +430,12 @@ namespace client RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); - m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer, + m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); } - void ClientDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode) + void LeaseSetDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { @@ -455,7 +448,7 @@ namespace client } } - void ClientDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode) + void LeaseSetDestination::HandlePublishVerificationTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { @@ -471,7 +464,7 @@ namespace client // we got latest LeasetSet LogPrint (eLogDebug, "Destination: published LeaseSet verified"); s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); - s->m_PublishVerificationTimer.async_wait (std::bind (&ClientDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); + s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); return; } } @@ -483,7 +476,7 @@ namespace client } } - void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) + void LeaseSetDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); buf += 4; @@ -514,7 +507,7 @@ namespace client } } - void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) + void LeaseSetDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) { if (!streamRequestComplete) { @@ -538,7 +531,7 @@ namespace client } } - std::shared_ptr ClientDestination::CreateStream (std::shared_ptr remote, int port) + std::shared_ptr LeaseSetDestination::CreateStream (std::shared_ptr remote, int port) { if (m_StreamingDestination) return m_StreamingDestination->CreateNewOutgoingStream (remote, port); @@ -546,7 +539,7 @@ namespace client return nullptr; } - std::shared_ptr ClientDestination::GetStreamingDestination (int port) const + std::shared_ptr LeaseSetDestination::GetStreamingDestination (int port) const { if (port) { @@ -558,26 +551,26 @@ namespace client return m_StreamingDestination; } - void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) + void LeaseSetDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) { if (m_StreamingDestination) m_StreamingDestination->SetAcceptor (acceptor); } - void ClientDestination::StopAcceptingStreams () + void LeaseSetDestination::StopAcceptingStreams () { if (m_StreamingDestination) m_StreamingDestination->ResetAcceptor (); } - bool ClientDestination::IsAcceptingStreams () const + bool LeaseSetDestination::IsAcceptingStreams () const { if (m_StreamingDestination) return m_StreamingDestination->IsAcceptorSet (); return false; } - std::shared_ptr ClientDestination::CreateStreamingDestination (int port, bool gzip) + std::shared_ptr LeaseSetDestination::CreateStreamingDestination (int port, bool gzip) { auto dest = std::make_shared (shared_from_this (), port, gzip); if (port) @@ -587,25 +580,25 @@ namespace client return dest; } - i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () + i2p::datagram::DatagramDestination * LeaseSetDestination::CreateDatagramDestination () { if (!m_DatagramDestination) m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ()); return m_DatagramDestination; } - bool ClientDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) + bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { if (!m_Pool || !IsReady ()) { if (requestComplete) requestComplete (nullptr); return false; } - m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete)); + m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete)); return true; } - void ClientDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest) + void LeaseSetDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest) { auto s = shared_from_this (); m_Service.post ([dest, s](void) @@ -620,7 +613,7 @@ namespace client }); } - void ClientDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete) + void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { std::set excluded; auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded); @@ -652,7 +645,7 @@ namespace client } } - bool ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, + bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, std::shared_ptr request) { if (!request->replyTunnel || !request->replyTunnel->IsEstablished ()) @@ -685,7 +678,7 @@ namespace client } }); request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); - request->requestTimeoutTimer.async_wait (std::bind (&ClientDestination::HandleRequestTimoutTimer, + request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer, shared_from_this (), std::placeholders::_1, dest)); } else @@ -693,7 +686,7 @@ namespace client return true; } - void ClientDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest) + void LeaseSetDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest) { if (ecode != boost::asio::error::operation_aborted) { @@ -731,19 +724,19 @@ namespace client } } - void ClientDestination::HandleCleanupTimer (const boost::system::error_code& ecode) + void LeaseSetDestination::HandleCleanupTimer (const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { CleanupExpiredTags (); CleanupRemoteLeaseSets (); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); - m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer, + m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); } } - void ClientDestination::CleanupRemoteLeaseSets () + void LeaseSetDestination::CleanupRemoteLeaseSets () { auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it = m_RemoteLeaseSets.begin (); it != m_RemoteLeaseSets.end ();) @@ -758,6 +751,32 @@ namespace client } } + std::vector > LeaseSetDestination::GetAllStreams () const + { + std::vector > ret; + if (m_StreamingDestination) + { + for (auto& it: m_StreamingDestination->GetStreams ()) + ret.push_back (it.second); + } + for (auto& it: m_StreamingDestinationsByPorts) + for (auto& it1: it.second->GetStreams ()) + ret.push_back (it1.second); + return ret; + } + + ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): + LeaseSetDestination (isPublic, params), + m_Keys (keys) + { + if (isPublic) + PersistTemporaryKeys (); + else + i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); + if (isPublic) + LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); + } + void ClientDestination::PersistTemporaryKeys () { std::string ident = GetIdentHash().ToBase32(); @@ -780,20 +799,6 @@ namespace client return; } LogPrint(eLogError, "Destinations: Can't save keys to ", path); - } - - std::vector > ClientDestination::GetAllStreams () const - { - std::vector > ret; - if (m_StreamingDestination) - { - for (auto& it: m_StreamingDestination->GetStreams ()) - ret.push_back (it.second); - } - for (auto& it: m_StreamingDestinationsByPorts) - for (auto& it1: it.second->GetStreams ()) - ret.push_back (it1.second); - return ret; } } } diff --git a/Destination.h b/Destination.h index 3011b4cb..3cf4ff48 100644 --- a/Destination.h +++ b/Destination.h @@ -49,8 +49,8 @@ namespace client typedef std::function stream)> StreamRequestComplete; - class ClientDestination: public i2p::garlic::GarlicDestination, - public std::enable_shared_from_this + class LeaseSetDestination: public i2p::garlic::GarlicDestination, + public std::enable_shared_from_this { typedef std::function leaseSet)> RequestComplete; // leaseSet = nullptr means not found @@ -68,8 +68,8 @@ namespace client public: - ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); - ~ClientDestination (); + LeaseSetDestination (bool isPublic, const std::map * params = nullptr); + ~LeaseSetDestination (); virtual void Start (); virtual void Stop (); @@ -94,11 +94,6 @@ namespace client // datagram i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * CreateDatagramDestination (); - - // implements LocalDestination - const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; - const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; - const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; // implements GarlicDestination std::shared_ptr GetLeaseSet (); @@ -129,8 +124,7 @@ namespace client bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, std::shared_ptr request); void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleCleanupTimer (const boost::system::error_code& ecode); - void CleanupRemoteLeaseSets (); - void PersistTemporaryKeys (); + void CleanupRemoteLeaseSets (); private: @@ -138,8 +132,6 @@ namespace client std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; - i2p::data::PrivateKeys m_Keys; - uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; std::map > m_RemoteLeaseSets; std::map > m_LeaseSetRequests; @@ -161,6 +153,27 @@ namespace client int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; std::vector > GetAllStreams () const; }; + + class ClientDestination: public LeaseSetDestination + { + public: + + ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); + + // implements LocalDestination + const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; + const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; + const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; + + private: + + void PersistTemporaryKeys (); + + private: + + i2p::data::PrivateKeys m_Keys; + uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; + }; } } diff --git a/Streaming.cpp b/Streaming.cpp index ab0a6df0..bf29caec 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -780,7 +780,7 @@ namespace stream m_CurrentRemoteLease = nullptr; } - StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): + StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_PendingIncomingTimer (m_Owner->GetService ()) { diff --git a/Streaming.h b/Streaming.h index c29b62f9..43061b94 100644 --- a/Streaming.h +++ b/Streaming.h @@ -23,7 +23,7 @@ namespace i2p { namespace client { - class ClientDestination; + class LeaseSetDestination; } namespace stream { @@ -193,7 +193,7 @@ namespace stream typedef std::function)> Acceptor; - StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0, bool gzip = true); + StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0, bool gzip = true); ~StreamingDestination (); void Start (); @@ -204,7 +204,7 @@ namespace stream void SetAcceptor (const Acceptor& acceptor); void ResetAcceptor (); bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; - std::shared_ptr GetOwner () const { return m_Owner; }; + std::shared_ptr GetOwner () const { return m_Owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; void HandleDataMessagePayload (const uint8_t * buf, size_t len); @@ -218,7 +218,7 @@ namespace stream private: - std::shared_ptr m_Owner; + std::shared_ptr m_Owner; uint16_t m_LocalPort; bool m_Gzip; // gzip compression of data messages std::mutex m_StreamsMutex; From f6103d3841fe220090e38fecc74e65fdafdce9e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 May 2016 14:31:22 -0400 Subject: [PATCH 04/37] moved streaming and datagram destination from LeaseSetDestination to ClientDestination --- Destination.cpp | 323 ++++++++++++++++++++++++++---------------------- Destination.h | 63 ++++++---- 2 files changed, 215 insertions(+), 171 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index 4712ac09..c5a3beff 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -14,9 +14,8 @@ namespace i2p namespace client { LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map * params): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_IsPublic (isPublic), m_PublishReplyToken (0), - m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsPublic (isPublic), + m_PublishReplyToken (0), m_PublishConfirmationTimer (m_Service), m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service) { int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; @@ -109,8 +108,6 @@ namespace client m_LeaseSetRequests.clear (); if (m_Pool) i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); - if (m_DatagramDestination) - delete m_DatagramDestination; } void LeaseSetDestination::Run () @@ -128,7 +125,7 @@ namespace client } } - void LeaseSetDestination::Start () + bool LeaseSetDestination::Start () { if (!m_IsRunning) { @@ -136,18 +133,17 @@ namespace client m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetActive (true); m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); - m_StreamingDestination = std::make_shared (shared_from_this ()); // TODO: - m_StreamingDestination->Start (); - for (auto it: m_StreamingDestinationsByPorts) - it.second->Start (); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, shared_from_this (), std::placeholders::_1)); + return true; } + else + return false; } - void LeaseSetDestination::Stop () + bool LeaseSetDestination::Stop () { if (m_IsRunning) { @@ -155,16 +151,6 @@ namespace client m_PublishConfirmationTimer.cancel (); m_PublishVerificationTimer.cancel (); m_IsRunning = false; - m_StreamingDestination->Stop (); - m_StreamingDestination = nullptr; - for (auto it: m_StreamingDestinationsByPorts) - it.second->Stop (); - if (m_DatagramDestination) - { - auto d = m_DatagramDestination; - m_DatagramDestination = nullptr; - delete d; - } if (m_Pool) { m_Pool->SetLocalDestination (nullptr); @@ -177,7 +163,10 @@ namespace client delete m_Thread; m_Thread = 0; } + return true; } + else + return false; } std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) @@ -476,117 +465,6 @@ namespace client } } - void LeaseSetDestination::HandleDataMessage (const uint8_t * buf, size_t len) - { - uint32_t length = bufbe32toh (buf); - buf += 4; - // we assume I2CP payload - uint16_t fromPort = bufbe16toh (buf + 4), // source - toPort = bufbe16toh (buf + 6); // destination - switch (buf[9]) - { - case PROTOCOL_TYPE_STREAMING: - { - // streaming protocol - auto dest = GetStreamingDestination (toPort); - if (dest) - dest->HandleDataMessagePayload (buf, length); - else - LogPrint (eLogError, "Destination: Missing streaming destination"); - } - break; - case PROTOCOL_TYPE_DATAGRAM: - // datagram protocol - if (m_DatagramDestination) - m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length); - else - LogPrint (eLogError, "Destination: Missing datagram destination"); - break; - default: - LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); - } - } - - void LeaseSetDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) - { - if (!streamRequestComplete) - { - LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); - return; - } - auto leaseSet = FindLeaseSet (dest); - if (leaseSet) - streamRequestComplete(CreateStream (leaseSet, port)); - else - { - auto s = shared_from_this (); - RequestDestination (dest, - [s, streamRequestComplete, port](std::shared_ptr ls) - { - if (ls) - streamRequestComplete(s->CreateStream (ls, port)); - else - streamRequestComplete (nullptr); - }); - } - } - - std::shared_ptr LeaseSetDestination::CreateStream (std::shared_ptr remote, int port) - { - if (m_StreamingDestination) - return m_StreamingDestination->CreateNewOutgoingStream (remote, port); - else - return nullptr; - } - - std::shared_ptr LeaseSetDestination::GetStreamingDestination (int port) const - { - if (port) - { - auto it = m_StreamingDestinationsByPorts.find (port); - if (it != m_StreamingDestinationsByPorts.end ()) - return it->second; - } - // if port is zero or not found, use default destination - return m_StreamingDestination; - } - - void LeaseSetDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) - { - if (m_StreamingDestination) - m_StreamingDestination->SetAcceptor (acceptor); - } - - void LeaseSetDestination::StopAcceptingStreams () - { - if (m_StreamingDestination) - m_StreamingDestination->ResetAcceptor (); - } - - bool LeaseSetDestination::IsAcceptingStreams () const - { - if (m_StreamingDestination) - return m_StreamingDestination->IsAcceptorSet (); - return false; - } - - std::shared_ptr LeaseSetDestination::CreateStreamingDestination (int port, bool gzip) - { - auto dest = std::make_shared (shared_from_this (), port, gzip); - if (port) - m_StreamingDestinationsByPorts[port] = dest; - else // update default - m_StreamingDestination = dest; - return dest; - } - - i2p::datagram::DatagramDestination * LeaseSetDestination::CreateDatagramDestination () - { - if (!m_DatagramDestination) - m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ()); - return m_DatagramDestination; - } - bool LeaseSetDestination::RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete) { if (!m_Pool || !IsReady ()) @@ -751,23 +629,9 @@ namespace client } } - std::vector > LeaseSetDestination::GetAllStreams () const - { - std::vector > ret; - if (m_StreamingDestination) - { - for (auto& it: m_StreamingDestination->GetStreams ()) - ret.push_back (it.second); - } - for (auto& it: m_StreamingDestinationsByPorts) - for (auto& it1: it.second->GetStreams ()) - ret.push_back (it1.second); - return ret; - } - ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (isPublic, params), - m_Keys (keys) + m_Keys (keys), m_DatagramDestination (nullptr) { if (isPublic) PersistTemporaryKeys (); @@ -777,6 +641,157 @@ namespace client LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); } + ClientDestination::~ClientDestination () + { + if (m_DatagramDestination) + delete m_DatagramDestination; + } + + bool ClientDestination::Start () + { + if (LeaseSetDestination::Start ()) + { + m_StreamingDestination = std::make_shared (shared_from_this ()); // TODO: + m_StreamingDestination->Start (); + for (auto it: m_StreamingDestinationsByPorts) + it.second->Start (); + return true; + } + else + return false; + } + + bool ClientDestination::Stop () + { + if (LeaseSetDestination::Stop ()) + { + m_StreamingDestination->Stop (); + m_StreamingDestination = nullptr; + for (auto it: m_StreamingDestinationsByPorts) + it.second->Stop (); + if (m_DatagramDestination) + { + auto d = m_DatagramDestination; + m_DatagramDestination = nullptr; + delete d; + } + return true; + } + else + return false; + } + + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) + { + uint32_t length = bufbe32toh (buf); + buf += 4; + // we assume I2CP payload + uint16_t fromPort = bufbe16toh (buf + 4), // source + toPort = bufbe16toh (buf + 6); // destination + switch (buf[9]) + { + case PROTOCOL_TYPE_STREAMING: + { + // streaming protocol + auto dest = GetStreamingDestination (toPort); + if (dest) + dest->HandleDataMessagePayload (buf, length); + else + LogPrint (eLogError, "Destination: Missing streaming destination"); + } + break; + case PROTOCOL_TYPE_DATAGRAM: + // datagram protocol + if (m_DatagramDestination) + m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length); + else + LogPrint (eLogError, "Destination: Missing datagram destination"); + break; + default: + LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); + } + } + + void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port) + { + if (!streamRequestComplete) + { + LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); + return; + } + auto leaseSet = FindLeaseSet (dest); + if (leaseSet) + streamRequestComplete(CreateStream (leaseSet, port)); + else + { + auto s = std::static_pointer_cast(shared_from_this ()); + RequestDestination (dest, + [s, streamRequestComplete, port](std::shared_ptr ls) + { + if (ls) + streamRequestComplete(s->CreateStream (ls, port)); + else + streamRequestComplete (nullptr); + }); + } + } + + std::shared_ptr ClientDestination::CreateStream (std::shared_ptr remote, int port) + { + if (m_StreamingDestination) + return m_StreamingDestination->CreateNewOutgoingStream (remote, port); + else + return nullptr; + } + + std::shared_ptr ClientDestination::GetStreamingDestination (int port) const + { + if (port) + { + auto it = m_StreamingDestinationsByPorts.find (port); + if (it != m_StreamingDestinationsByPorts.end ()) + return it->second; + } + // if port is zero or not found, use default destination + return m_StreamingDestination; + } + + void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) + { + if (m_StreamingDestination) + m_StreamingDestination->SetAcceptor (acceptor); + } + + void ClientDestination::StopAcceptingStreams () + { + if (m_StreamingDestination) + m_StreamingDestination->ResetAcceptor (); + } + + bool ClientDestination::IsAcceptingStreams () const + { + if (m_StreamingDestination) + return m_StreamingDestination->IsAcceptorSet (); + return false; + } + + std::shared_ptr ClientDestination::CreateStreamingDestination (int port, bool gzip) + { + auto dest = std::make_shared (shared_from_this (), port, gzip); + if (port) + m_StreamingDestinationsByPorts[port] = dest; + else // update default + m_StreamingDestination = dest; + return dest; + } + + i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () + { + if (!m_DatagramDestination) + m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ()); + return m_DatagramDestination; + } + void ClientDestination::PersistTemporaryKeys () { std::string ident = GetIdentHash().ToBase32(); @@ -800,5 +815,19 @@ namespace client } LogPrint(eLogError, "Destinations: Can't save keys to ", path); } + + std::vector > ClientDestination::GetAllStreams () const + { + std::vector > ret; + if (m_StreamingDestination) + { + for (auto& it: m_StreamingDestination->GetStreams ()) + ret.push_back (it.second); + } + for (auto& it: m_StreamingDestinationsByPorts) + for (auto& it1: it.second->GetStreams ()) + ret.push_back (it1.second); + return ret; + } } } diff --git a/Destination.h b/Destination.h index 3cf4ff48..c2292cfe 100644 --- a/Destination.h +++ b/Destination.h @@ -71,8 +71,8 @@ namespace client LeaseSetDestination (bool isPublic, const std::map * params = nullptr); ~LeaseSetDestination (); - virtual void Start (); - virtual void Stop (); + virtual bool Start (); + virtual bool Stop (); bool IsRunning () const { return m_IsRunning; }; boost::asio::io_service& GetService () { return m_Service; }; std::shared_ptr GetTunnelPool () { return m_Pool; }; @@ -81,20 +81,6 @@ namespace client bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); void CancelDestinationRequest (const i2p::data::IdentHash& dest); - // streaming - std::shared_ptr CreateStreamingDestination (int port, bool gzip = true); // additional - std::shared_ptr GetStreamingDestination (int port = 0) const; - // following methods operate with default streaming destination - void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0); - std::shared_ptr CreateStream (std::shared_ptr remote, int port = 0); - void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor); - void StopAcceptingStreams (); - bool IsAcceptingStreams () const; - - // datagram - i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; - i2p::datagram::DatagramDestination * CreateDatagramDestination (); - // implements GarlicDestination std::shared_ptr GetLeaseSet (); std::shared_ptr GetTunnelPool () const { return m_Pool; } @@ -106,9 +92,11 @@ namespace client void ProcessDeliveryStatusMessage (std::shared_ptr msg); void SetLeaseSetUpdated (); - // I2CP - void HandleDataMessage (const uint8_t * buf, size_t len); + protected: + // I2CP + virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; + private: void Run (); @@ -125,7 +113,7 @@ namespace client void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleCleanupTimer (const boost::system::error_code& ecode); void CleanupRemoteLeaseSets (); - + private: volatile bool m_IsRunning; @@ -140,10 +128,6 @@ namespace client bool m_IsPublic; uint32_t m_PublishReplyToken; std::set m_ExcludedFloodfills; // for publishing - - std::shared_ptr m_StreamingDestination; // default - std::map > m_StreamingDestinationsByPorts; - i2p::datagram::DatagramDestination * m_DatagramDestination; boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, m_CleanupTimer; @@ -151,7 +135,6 @@ namespace client // for HTTP only int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; - std::vector > GetAllStreams () const; }; class ClientDestination: public LeaseSetDestination @@ -159,12 +142,35 @@ namespace client public: ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); + ~ClientDestination (); + + bool Start (); + bool Stop (); + // streaming + std::shared_ptr CreateStreamingDestination (int port, bool gzip = true); // additional + std::shared_ptr GetStreamingDestination (int port = 0) const; + // following methods operate with default streaming destination + void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0); + std::shared_ptr CreateStream (std::shared_ptr remote, int port = 0); + void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor); + void StopAcceptingStreams (); + bool IsAcceptingStreams () const; + + // datagram + i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; + i2p::datagram::DatagramDestination * CreateDatagramDestination (); + // implements LocalDestination const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; + protected: + + // I2CP + void HandleDataMessage (const uint8_t * buf, size_t len); + private: void PersistTemporaryKeys (); @@ -173,6 +179,15 @@ namespace client i2p::data::PrivateKeys m_Keys; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; + + std::shared_ptr m_StreamingDestination; // default + std::map > m_StreamingDestinationsByPorts; + i2p::datagram::DatagramDestination * m_DatagramDestination; + + public: + + // for HTTP only + std::vector > GetAllStreams () const; }; } } From 50ff0d251ae6b75121143fa4fdf81af809fe1f21 Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 05/37] * HTTP.h : add base class HTTPMsg --- HTTP.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/HTTP.h b/HTTP.h index 9bd31c75..82594874 100644 --- a/HTTP.h +++ b/HTTP.h @@ -54,8 +54,11 @@ namespace http { std::string to_string (); }; - struct HTTPReq { + struct HTTPMsg { std::map headers; + }; + + struct HTTPReq : HTTPMsg { std::string version; std::string method; std::string uri; @@ -75,8 +78,7 @@ namespace http { std::string to_string(); }; - struct HTTPRes { - std::map headers; + struct HTTPRes : HTTPMsg { std::string version; std::string status; unsigned short int code; From a461f462d223d1004423aff3fce5276800fca7e0 Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 06/37] * HTTP.{cpp,h} : add HTTPMsg::{add,del}_header() helpers --- HTTP.cpp | 15 +++++++++++++++ HTTP.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/HTTP.cpp b/HTTP.cpp index ef43d55f..f74e9429 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -184,6 +184,21 @@ namespace http { return out; } + void HTTPMsg::add_header(const char *name, const char *value, bool replace) { + std::size_t count = headers.count(name); + if (count && !replace) + return; + if (count) { + headers[name] = value; + return; + } + headers.insert(std::pair(name, value)); + } + + void HTTPMsg::del_header(const char *name) { + headers.erase(name); + } + int HTTPReq::parse(const char *buf, size_t len) { std::string str(buf, len); return parse(str); diff --git a/HTTP.h b/HTTP.h index 82594874..e13fe547 100644 --- a/HTTP.h +++ b/HTTP.h @@ -56,6 +56,9 @@ namespace http { struct HTTPMsg { std::map headers; + + void add_header(const char *name, const char *value, bool replace = false); + void del_header(const char *name); }; struct HTTPReq : HTTPMsg { From 70e9d85a756357a2f018b58d3ac1d3a4e4f6bd57 Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 07/37] * HTTP.cpp : add internal function gen_rfc1123_date() --- HTTP.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HTTP.cpp b/HTTP.cpp index f74e9429..6747c35b 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -8,6 +8,7 @@ #include "HTTP.h" #include +#include namespace i2p { namespace http { @@ -54,6 +55,13 @@ namespace http { return true; } + void gen_rfc1123_date(std::string & out) { + std::time_t now = std::time(nullptr); + char buf[128]; + std::strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&now)); + out = buf; + } + bool URL::parse(const char *str, std::size_t len) { std::string url(str, len ? len : strlen(str)); return parse(url); From 2ce61402bb4a300f6b79a21efb924d1a0306bb0e Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 08/37] * HTTP.{cpp,h} * add 'body' member ot HTTPRes * change HTTPRes::to_string() to add 'Date', 'Content-Length' headers and body --- HTTP.cpp | 12 ++++++++++++ HTTP.h | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/HTTP.cpp b/HTTP.cpp index 6747c35b..254cab95 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -334,12 +334,24 @@ namespace http { } std::string HTTPRes::to_string() { + if (version == "HTTP/1.1" && headers.count("Date") == 0) { + std::string date; + gen_rfc1123_date(date); + add_header("Date", date.c_str()); + } + if (status == "OK" && code != 200) + status = HTTPCodeToStatus(code); // update + if (body.length() > 0 && headers.count("Content-Length") == 0) + add_header("Content-Length", std::to_string(body.length()).c_str()); + /* build response */ std::stringstream ss; ss << version << " " << code << " " << status << CRLF; for (auto & h : headers) { ss << h.first << ": " << h.second << CRLF; } ss << CRLF; + if (body.length() > 0) + ss << body; return ss.str(); } diff --git a/HTTP.h b/HTTP.h index e13fe547..7f73285f 100644 --- a/HTTP.h +++ b/HTTP.h @@ -85,6 +85,12 @@ namespace http { std::string version; std::string status; unsigned short int code; + /** simplifies response generation + * If this variable is set: + * a) Content-Length header will be added if missing + * b) contents of body will be included in response + */ + std::string body; HTTPRes (): version("HTTP/1.1"), status("OK"), code(200) {} @@ -96,7 +102,13 @@ namespace http { int parse(const char *buf, size_t len); int parse(const std::string& buf); - /** @brief Serialize HTTP response to string */ + /** + * @brief Serialize HTTP response to string + * @note If version is set to HTTP/1.1, and Date header is missing, + * it will be generated based on current time and added to headers + * @note If body member is set and Content-Length header is missing, + * this header will be added, based on body's length + */ std::string to_string(); /** @brief Checks that response declared as chunked data */ From b68f06ca83c6521998715513ae7d80287e3bc56d Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 09/37] * update tests --- tests/test-http-req.cpp | 7 ++++++- tests/test-http-res.cpp | 15 ++++++++++++++- tests/test-http-url.cpp | 2 +- tests/test-http-url_decode.cpp | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/test-http-req.cpp b/tests/test-http-req.cpp index 484a7ad6..10ea621f 100644 --- a/tests/test-http-req.cpp +++ b/tests/test-http-req.cpp @@ -3,11 +3,12 @@ using namespace i2p::http; -int main(int argc, char *argv[]) { +int main() { HTTPReq *req; int ret = 0, len = 0; const char *buf; + /* test: parsing request with body */ buf = "GET / HTTP/1.0\r\n" "User-Agent: curl/7.26.0\r\n" @@ -31,6 +32,7 @@ int main(int argc, char *argv[]) { assert(req->headers.find("User-Agent")->second == "curl/7.26.0"); delete req; + /* test: parsing request without body */ buf = "GET / HTTP/1.0\r\n" "\r\n"; @@ -44,6 +46,7 @@ int main(int argc, char *argv[]) { assert(req->headers.size() == 0); delete req; + /* test: parsing request without body */ buf = "GET / HTTP/1.1\r\n" "\r\n"; @@ -52,6 +55,7 @@ int main(int argc, char *argv[]) { assert((ret = req->parse(buf, len)) == -1); /* no host header */ delete req; + /* test: parsing incomplete request */ buf = "GET / HTTP/1.0\r\n" ""; @@ -60,6 +64,7 @@ int main(int argc, char *argv[]) { assert((ret = req->parse(buf, len)) == 0); /* request not completed */ delete req; + /* test: parsing slightly malformed request */ buf = "GET http://inr.i2p HTTP/1.1\r\n" "Host: stats.i2p\r\n" diff --git a/tests/test-http-res.cpp b/tests/test-http-res.cpp index 6188a68d..7dd74e1e 100644 --- a/tests/test-http-res.cpp +++ b/tests/test-http-res.cpp @@ -3,11 +3,12 @@ using namespace i2p::http; -int main(int argc, char *argv[]) { +int main() { HTTPRes *res; int ret = 0, len = 0; const char *buf; + /* test: parsing valid response without body */ buf = "HTTP/1.1 304 Not Modified\r\n" "Date: Thu, 14 Apr 2016 00:00:00 GMT\r\n" @@ -31,6 +32,18 @@ int main(int argc, char *argv[]) { assert(res->length() == 536); delete res; + /* test: building request */ + buf = + "HTTP/1.0 304 Not Modified\r\n" + "Content-Length: 0\r\n" + "\r\n"; + res = new HTTPRes; + res->version = "HTTP/1.0"; + res->code = 304; + res->status = "Not Modified"; + res->add_header("Content-Length", "0"); + assert(res->to_string() == buf); + return 0; } diff --git a/tests/test-http-url.cpp b/tests/test-http-url.cpp index 71b2f703..d574f1e2 100644 --- a/tests/test-http-url.cpp +++ b/tests/test-http-url.cpp @@ -3,7 +3,7 @@ using namespace i2p::http; -int main(int argc, char *argv[]) { +int main() { std::map params; URL *url; diff --git a/tests/test-http-url_decode.cpp b/tests/test-http-url_decode.cpp index 1c548e6f..f72b2c50 100644 --- a/tests/test-http-url_decode.cpp +++ b/tests/test-http-url_decode.cpp @@ -3,7 +3,7 @@ using namespace i2p::http; -int main(int argc, char *argv[]) { +int main() { std::string in("/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0/"); std::string out = UrlDecode(in); From f10064ce39a8deea81d6c5157a5d3177fdfd71bc Mon Sep 17 00:00:00 2001 From: hagen Date: Tue, 24 May 2016 00:00:00 +0000 Subject: [PATCH 10/37] * HTTPServer.cpp : update response building --- HTTPServer.cpp | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 4e44e6f9..5d54711d 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -749,7 +748,7 @@ namespace http { if (needAuth && !CheckAuth(req)) { res.code = 401; - res.headers.insert(std::pair("WWW-Authenticate", "Basic realm=\"WebAdmin\"")); + res.add_header("WWW-Authenticate", "Basic realm=\"WebAdmin\""); SendReply(res, content); return; } @@ -763,6 +762,8 @@ namespace http { else ShowStatus (s); ShowPageTail (s); + + res.code = 200; content = s.str (); SendReply (res, content); } @@ -845,21 +846,11 @@ namespace http { void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) { - std::time_t time_now = std::time(nullptr); - char time_buff[128]; - std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)); - reply.status = HTTPCodeToStatus(reply.code); - reply.headers.insert(std::pair("Date", time_buff)); - reply.headers.insert(std::pair("Content-Type", "text/html")); - reply.headers.insert(std::pair("Content-Length", std::to_string(content.size()))); + reply.add_header("Content-Type", "text/html"); + reply.body = content; std::string res = reply.to_string(); - std::vector buffers; - - buffers.push_back(boost::asio::buffer(res)); - buffers.push_back(boost::asio::buffer(content)); - - boost::asio::async_write (*m_Socket, buffers, + boost::asio::async_write (*m_Socket, boost::asio::buffer(res), std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } From f01f6e94d1487f2036ecee5daaf146d0d75bc409 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 24 May 2016 16:27:34 -0400 Subject: [PATCH 11/37] fix #500. check result of readline --- AddressBook.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AddressBook.cpp b/AddressBook.cpp index 766d8c95..40e4c383 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -716,12 +716,14 @@ namespace client if (status == 200) // OK { bool isChunked = false, isGzip = false; + m_Etag = ""; m_LastModified = ""; std::string header, statusMessage; std::getline (response, statusMessage); // read until new line meaning end of header while (!response.eof () && header != "\r") { std::getline (response, header); + if (response.fail ()) break; auto colon = header.find (':'); if (colon != std::string::npos) { @@ -741,7 +743,7 @@ namespace client } } LogPrint (eLogInfo, "Addressbook: received ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified); - if (!response.eof ()) + if (!response.eof () && !response.fail ()) { success = true; if (!isChunked) From 7035ead9e774406c45ff7c286a3a71ff1e3b8e5f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 12:55:58 -0400 Subject: [PATCH 12/37] provide reply tunnel expcilitly for LeaseSet --- Destination.cpp | 8 +++++++- I2NPProtocol.cpp | 11 +++++------ I2NPProtocol.h | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index c5a3beff..f64fe208 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -407,6 +407,12 @@ namespace client LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels"); return; } + auto inbound = m_Pool->GetNextInboundTunnel (); + if (!inbound) + { + LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels"); + return; + } auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills); if (!floodfill) { @@ -417,7 +423,7 @@ namespace client m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); - auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)); + auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken, inbound)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index e2451f68..1f1caab7 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -249,7 +249,7 @@ namespace i2p return m; } - std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken) + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken, std::shared_ptr replyTunnel) { if (!leaseSet) return nullptr; auto m = NewI2NPShortMessage (); @@ -258,14 +258,13 @@ namespace i2p payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken); size_t size = DATABASE_STORE_HEADER_SIZE; - if (replyToken) + if (replyToken && replyTunnel) { - auto leases = leaseSet->GetNonExpiredLeases (); - if (leases.size () > 0) + if (replyTunnel) { - htobe32buf (payload + size, leases[0]->tunnelID); + htobe32buf (payload + size, replyTunnel->GetNextTunnelID ()); size += 4; // reply tunnelID - memcpy (payload + size, leases[0]->tunnelGateway, 32); + memcpy (payload + size, replyTunnel->GetNextIdentHash (), 32); size += 32; // reply tunnel gateway } else diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 113e8eb8..1eff8c16 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -224,7 +224,7 @@ namespace tunnel std::shared_ptr CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers); std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr router = nullptr, uint32_t replyToken = 0); - std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0); + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0, std::shared_ptr replyTunnel = nullptr); bool IsRouterInfoMsg (std::shared_ptr msg); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); From f2292fd618e90758916fd1367607db1476502360 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 14:17:34 -0400 Subject: [PATCH 13/37] LocalLeaseSet added --- LeaseSet.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- LeaseSet.h | 27 +++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 5d259b33..0bc380f6 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -4,6 +4,7 @@ #include "Log.h" #include "Timestamp.h" #include "NetDb.h" +#include "Tunnel.h" #include "TunnelPool.h" #include "LeaseSet.h" @@ -195,7 +196,7 @@ namespace data if (size > len) return 0; uint8_t num = buf[size]; size++; // num - if (size + num*44 > len) return 0; + if (size + num*LEASE_SIZE > len) return 0; uint64_t timestamp= 0 ; for (int i = 0; i < num; i++) { @@ -243,6 +244,47 @@ namespace data if (IsEmpty ()) return true; auto ts = i2p::util::GetMillisecondsSinceEpoch (); return ts > m_ExpirationTime; + } + + LocalLeaseSet::LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels): + m_Identity (identity) + { + int num = tunnels.size (); + if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; + // identity + m_BufferLen = m_Identity->GetFullLen () + 256 + num*LEASE_SIZE + m_Identity->GetSignatureLen (); + m_Buffer = new uint8_t[m_BufferLen]; + auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen); + memcpy (m_Buffer + offset, encryptionPublicKey, 256); + offset += 256; + auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); + memset (m_Buffer + offset, 0, signingKeyLen); + offset += signingKeyLen; + // num leases + m_Buffer[offset] = num; + offset++; + // leases + auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); + for (int i = 0; i < num; i++) + { + memcpy (m_Buffer + offset, tunnels[i]->GetNextIdentHash (), 32); + offset += 32; // gateway id + htobe32buf (m_Buffer + offset, tunnels[i]->GetNextTunnelID ()); + offset += 4; // tunnel id + uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration + ts *= 1000; // in milliseconds + // make sure leaseset is newer than previous, but adding some time to expiration date + ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs + htobe64buf (m_Buffer + offset, ts); + offset += 8; // end date + } + // we don't sign it yet. must be signed later on } + + void LocalLeaseSet::SetSignature (const uint8_t * signature) + { + auto signatureLen = GetSignatureLen (); + memcpy (m_Buffer + m_BufferLen - signatureLen, signature, signatureLen); + } } } diff --git a/LeaseSet.h b/LeaseSet.h index f5685210..644e0ef4 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -12,6 +12,7 @@ namespace i2p namespace tunnel { + class InboundTunnel; class TunnelPool; } @@ -37,14 +38,15 @@ namespace data }; }; - const int MAX_LS_BUFFER_SIZE = 3072; + const size_t MAX_LS_BUFFER_SIZE = 3072; + const size_t LEASE_SIZE = 44; // 32 + 4 + 8 const uint8_t MAX_NUM_LEASES = 16; class LeaseSet: public RoutingDestination { public: LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true); - LeaseSet (std::shared_ptr pool); + LeaseSet (std::shared_ptr pool); // deprecated ~LeaseSet () { delete[] m_Buffer; }; void Update (const uint8_t * buf, size_t len); bool IsNewer (const uint8_t * buf, size_t len) const; @@ -82,6 +84,27 @@ namespace data uint8_t * m_Buffer; size_t m_BufferLen; }; + + class LocalLeaseSet + { + public: + + LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels); + ~LocalLeaseSet () { delete[] m_Buffer; }; + + void SetSignature (const uint8_t * signature); + + const uint8_t * GetBuffer () const { return m_Buffer; }; + size_t GetBufferLen () const { return m_BufferLen; }; + size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); }; + const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; + + private: + + std::shared_ptr m_Identity; + uint8_t * m_Buffer; + size_t m_BufferLen; + }; } } From 4e4f9b6f8beab91e44e3bdbf39132408dd3fbc09 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 15:10:28 -0400 Subject: [PATCH 14/37] use LocalLeaseSet for own LeaseSets --- Destination.cpp | 9 +++++++-- Destination.h | 4 ++-- Garlic.h | 2 +- I2NPProtocol.cpp | 18 +++++++++++++++++- I2NPProtocol.h | 3 ++- LeaseSet.cpp | 13 +++++++------ LeaseSet.h | 8 ++++++-- RouterContext.h | 2 +- 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index f64fe208..a7d33454 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -192,7 +192,7 @@ namespace client return nullptr; } - std::shared_ptr LeaseSetDestination::GetLeaseSet () + std::shared_ptr LeaseSetDestination::GetLeaseSet () { if (!m_Pool) return nullptr; if (!m_LeaseSet) @@ -202,7 +202,12 @@ namespace client void LeaseSetDestination::UpdateLeaseSet () { - m_LeaseSet.reset (new i2p::data::LeaseSet (m_Pool)); + int numTunnels = m_Pool->GetNumInboundTunnels () + 2; // 2 backup tunnels + if (numTunnels > i2p::data::MAX_NUM_LEASES) numTunnels = i2p::data::MAX_NUM_LEASES; // 16 tunnels maximum + auto leaseSet = new i2p::data::LocalLeaseSet (GetIdentity (), GetEncryptionPublicKey (), + m_Pool->GetInboundTunnels (numTunnels)); + Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); // TODO + m_LeaseSet.reset (leaseSet); } bool LeaseSetDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) diff --git a/Destination.h b/Destination.h index c2292cfe..85b4b5ab 100644 --- a/Destination.h +++ b/Destination.h @@ -82,7 +82,7 @@ namespace client void CancelDestinationRequest (const i2p::data::IdentHash& dest); // implements GarlicDestination - std::shared_ptr GetLeaseSet (); + std::shared_ptr GetLeaseSet (); std::shared_ptr GetTunnelPool () const { return m_Pool; } void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); @@ -124,7 +124,7 @@ namespace client std::map > m_LeaseSetRequests; std::shared_ptr m_Pool; - std::shared_ptr m_LeaseSet; + std::shared_ptr m_LeaseSet; bool m_IsPublic; uint32_t m_PublishReplyToken; std::set m_ExcludedFloodfills; // for publishing diff --git a/Garlic.h b/Garlic.h index ea53dd03..6d25fd39 100644 --- a/Garlic.h +++ b/Garlic.h @@ -163,7 +163,7 @@ namespace garlic virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); virtual void SetLeaseSetUpdated (); - virtual std::shared_ptr GetLeaseSet () = 0; // TODO + virtual std::shared_ptr GetLeaseSet () = 0; // TODO virtual std::shared_ptr GetTunnelPool () const = 0; virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 1f1caab7..c47a1657 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -249,7 +249,23 @@ namespace i2p return m; } - std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken, std::shared_ptr replyTunnel) + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet) + { + if (!leaseSet) return nullptr; + auto m = NewI2NPShortMessage (); + uint8_t * payload = m->GetPayload (); + memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32); + payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet + htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); + size_t size = DATABASE_STORE_HEADER_SIZE; + memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ()); + size += leaseSet->GetBufferLen (); + m->len += size; + m->FillI2NPMessageHeader (eI2NPDatabaseStore); + return m; + } + + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken, std::shared_ptr replyTunnel) { if (!leaseSet) return nullptr; auto m = NewI2NPShortMessage (); diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 1eff8c16..1ade55ed 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -224,7 +224,8 @@ namespace tunnel std::shared_ptr CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers); std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr router = nullptr, uint32_t replyToken = 0); - std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0, std::shared_ptr replyTunnel = nullptr); + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet); // for floodfill only + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0, std::shared_ptr replyTunnel = nullptr); bool IsRouterInfoMsg (std::shared_ptr msg); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 0bc380f6..e78cc9ce 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -247,7 +247,7 @@ namespace data } LocalLeaseSet::LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels): - m_Identity (identity) + m_ExpirationTime (0), m_Identity (identity) { int num = tunnels.size (); if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; @@ -273,18 +273,19 @@ namespace data offset += 4; // tunnel id uint64_t ts = tunnels[i]->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration ts *= 1000; // in milliseconds + if (ts > m_ExpirationTime) m_ExpirationTime = ts; // make sure leaseset is newer than previous, but adding some time to expiration date ts += (currentTime - tunnels[i]->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs htobe64buf (m_Buffer + offset, ts); offset += 8; // end date } // we don't sign it yet. must be signed later on - } + } - void LocalLeaseSet::SetSignature (const uint8_t * signature) + bool LocalLeaseSet::IsExpired () const { - auto signatureLen = GetSignatureLen (); - memcpy (m_Buffer + m_BufferLen - signatureLen, signature, signatureLen); - } + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + return ts > m_ExpirationTime; + } } } diff --git a/LeaseSet.h b/LeaseSet.h index 644e0ef4..faeda67f 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -92,15 +92,19 @@ namespace data LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels); ~LocalLeaseSet () { delete[] m_Buffer; }; - void SetSignature (const uint8_t * signature); - const uint8_t * GetBuffer () const { return m_Buffer; }; + uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); }; size_t GetBufferLen () const { return m_BufferLen; }; size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); }; const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; + bool IsExpired () const; + bool operator== (const LeaseSet& other) const + { return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); }; + private: + uint64_t m_ExpirationTime; // in milliseconds std::shared_ptr m_Identity; uint8_t * m_Buffer; size_t m_BufferLen; diff --git a/RouterContext.h b/RouterContext.h index 5a72ad58..29164f4b 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -79,7 +79,7 @@ namespace i2p void SetLeaseSetUpdated () {}; // implements GarlicDestination - std::shared_ptr GetLeaseSet () { return nullptr; }; + std::shared_ptr GetLeaseSet () { return nullptr; }; std::shared_ptr GetTunnelPool () const; void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); From e686fad5468b62b9dc4bf68e3ff6760a3ae4da02 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 15:18:21 -0400 Subject: [PATCH 15/37] rmoved deprecated constructor --- LeaseSet.cpp | 50 -------------------------------------------------- LeaseSet.h | 1 - 2 files changed, 51 deletions(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index e78cc9ce..0c1d5b37 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -22,56 +22,6 @@ namespace data ReadFromBuffer (); } - LeaseSet::LeaseSet (std::shared_ptr pool): - m_IsValid (true), m_StoreLeases (true), m_ExpirationTime (0) - { - if (!pool) return; - // header - auto localDestination = pool->GetLocalDestination (); - if (!localDestination) - { - m_Buffer = nullptr; - m_BufferLen = 0; - m_IsValid = false; - LogPrint (eLogError, "LeaseSet: Destination for local LeaseSet doesn't exist"); - return; - } - m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE]; - m_BufferLen = localDestination->GetIdentity ()->ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); - memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256); - m_BufferLen += 256; - auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen (); - memset (m_Buffer + m_BufferLen, 0, signingKeyLen); - m_BufferLen += signingKeyLen; - int numTunnels = pool->GetNumInboundTunnels () + 2; // 2 backup tunnels - if (numTunnels > 16) numTunnels = 16; // 16 tunnels maximum - auto tunnels = pool->GetInboundTunnels (numTunnels); - m_Buffer[m_BufferLen] = tunnels.size (); // num leases - m_BufferLen++; - // leases - auto currentTime = i2p::util::GetMillisecondsSinceEpoch (); - for (auto it: tunnels) - { - memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32); - m_BufferLen += 32; // gateway id - htobe32buf (m_Buffer + m_BufferLen, it->GetNextTunnelID ()); - m_BufferLen += 4; // tunnel id - uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration - ts *= 1000; // in milliseconds - if (ts > m_ExpirationTime) m_ExpirationTime = ts; - // make sure leaseset is newer than previous, but adding some time to expiration date - ts += (currentTime - it->GetCreationTime ()*1000LL)*2/i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; // up to 2 secs - htobe64buf (m_Buffer + m_BufferLen, ts); - m_BufferLen += 8; // end date - } - // signature - localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen); - m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen (); - LogPrint (eLogDebug, "LeaseSet: Local LeaseSet of ", tunnels.size (), " leases created"); - - ReadFromBuffer (); - } - void LeaseSet::Update (const uint8_t * buf, size_t len) { if (len > m_BufferLen) diff --git a/LeaseSet.h b/LeaseSet.h index faeda67f..c8604412 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -46,7 +46,6 @@ namespace data public: LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true); - LeaseSet (std::shared_ptr pool); // deprecated ~LeaseSet () { delete[] m_Buffer; }; void Update (const uint8_t * buf, size_t len); bool IsNewer (const uint8_t * buf, size_t len) const; From 789eb48698bfb8617ed2b05b3a8acbd41d2c872c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 15:30:04 -0400 Subject: [PATCH 16/37] removed deprecated constructor --- LeaseSet.cpp | 1 - LeaseSet.h | 1 - 2 files changed, 2 deletions(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 0c1d5b37..42b961fa 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -5,7 +5,6 @@ #include "Timestamp.h" #include "NetDb.h" #include "Tunnel.h" -#include "TunnelPool.h" #include "LeaseSet.h" namespace i2p diff --git a/LeaseSet.h b/LeaseSet.h index c8604412..289ae25c 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -13,7 +13,6 @@ namespace i2p namespace tunnel { class InboundTunnel; - class TunnelPool; } namespace data From c7173d5e1c54e896d39d5ff2b91b7eb09f1bab77 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 16:18:02 -0400 Subject: [PATCH 17/37] use shared ClientDestination --- Datagram.cpp | 2 +- Datagram.h | 6 +++--- Destination.cpp | 8 ++++---- Destination.h | 4 +++- Streaming.cpp | 2 +- Streaming.h | 8 ++++---- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Datagram.cpp b/Datagram.cpp index f06d62da..2015622c 100644 --- a/Datagram.cpp +++ b/Datagram.cpp @@ -11,7 +11,7 @@ namespace i2p { namespace datagram { - DatagramDestination::DatagramDestination (std::shared_ptr owner): + DatagramDestination::DatagramDestination (std::shared_ptr owner): m_Owner (owner), m_Receiver (nullptr) { } diff --git a/Datagram.h b/Datagram.h index 404facf2..c593fad2 100644 --- a/Datagram.h +++ b/Datagram.h @@ -14,7 +14,7 @@ namespace i2p { namespace client { - class LeaseSetDestination; + class ClientDestination; } namespace datagram { @@ -25,7 +25,7 @@ namespace datagram public: - DatagramDestination (std::shared_ptr owner); + DatagramDestination (std::shared_ptr owner); ~DatagramDestination (); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); @@ -47,7 +47,7 @@ namespace datagram private: - std::shared_ptr m_Owner; + std::shared_ptr m_Owner; Receiver m_Receiver; // default std::map m_ReceiversByPorts; diff --git a/Destination.cpp b/Destination.cpp index a7d33454..46ff688f 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -662,7 +662,7 @@ namespace client { if (LeaseSetDestination::Start ()) { - m_StreamingDestination = std::make_shared (shared_from_this ()); // TODO: + m_StreamingDestination = std::make_shared (GetSharedFromThis ()); // TODO: m_StreamingDestination->Start (); for (auto it: m_StreamingDestinationsByPorts) it.second->Start (); @@ -735,7 +735,7 @@ namespace client streamRequestComplete(CreateStream (leaseSet, port)); else { - auto s = std::static_pointer_cast(shared_from_this ()); + auto s = GetSharedFromThis (); RequestDestination (dest, [s, streamRequestComplete, port](std::shared_ptr ls) { @@ -788,7 +788,7 @@ namespace client std::shared_ptr ClientDestination::CreateStreamingDestination (int port, bool gzip) { - auto dest = std::make_shared (shared_from_this (), port, gzip); + auto dest = std::make_shared (GetSharedFromThis (), port, gzip); if (port) m_StreamingDestinationsByPorts[port] = dest; else // update default @@ -799,7 +799,7 @@ namespace client i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () { if (!m_DatagramDestination) - m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ()); + m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ()); return m_DatagramDestination; } diff --git a/Destination.h b/Destination.h index 85b4b5ab..4c8bfc80 100644 --- a/Destination.h +++ b/Destination.h @@ -174,7 +174,9 @@ namespace client private: void PersistTemporaryKeys (); - + std::shared_ptr GetSharedFromThis () + { return std::static_pointer_cast(shared_from_this ()); } + private: i2p::data::PrivateKeys m_Keys; diff --git a/Streaming.cpp b/Streaming.cpp index bf29caec..ab0a6df0 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -780,7 +780,7 @@ namespace stream m_CurrentRemoteLease = nullptr; } - StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): + StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_PendingIncomingTimer (m_Owner->GetService ()) { diff --git a/Streaming.h b/Streaming.h index 43061b94..c29b62f9 100644 --- a/Streaming.h +++ b/Streaming.h @@ -23,7 +23,7 @@ namespace i2p { namespace client { - class LeaseSetDestination; + class ClientDestination; } namespace stream { @@ -193,7 +193,7 @@ namespace stream typedef std::function)> Acceptor; - StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0, bool gzip = true); + StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0, bool gzip = true); ~StreamingDestination (); void Start (); @@ -204,7 +204,7 @@ namespace stream void SetAcceptor (const Acceptor& acceptor); void ResetAcceptor (); bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; - std::shared_ptr GetOwner () const { return m_Owner; }; + std::shared_ptr GetOwner () const { return m_Owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; void HandleDataMessagePayload (const uint8_t * buf, size_t len); @@ -218,7 +218,7 @@ namespace stream private: - std::shared_ptr m_Owner; + std::shared_ptr m_Owner; uint16_t m_LocalPort; bool m_Gzip; // gzip compression of data messages std::mutex m_StreamsMutex; From 0d2df220741654c43f1815132eaf27a70be29445 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 17:41:24 -0400 Subject: [PATCH 18/37] fixed crash --- LeaseSet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 42b961fa..75d8a1ae 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -201,12 +201,12 @@ namespace data int num = tunnels.size (); if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; // identity - m_BufferLen = m_Identity->GetFullLen () + 256 + num*LEASE_SIZE + m_Identity->GetSignatureLen (); + auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); + m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + num*LEASE_SIZE + m_Identity->GetSignatureLen (); m_Buffer = new uint8_t[m_BufferLen]; auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen); memcpy (m_Buffer + offset, encryptionPublicKey, 256); offset += 256; - auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); memset (m_Buffer + offset, 0, signingKeyLen); offset += signingKeyLen; // num leases From 57bb0da1d6895444c5e740fbe32a41dfd62989b5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 May 2016 18:47:16 -0400 Subject: [PATCH 19/37] correct LeaseSet message size --- LeaseSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 75d8a1ae..5efe2b16 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -202,7 +202,7 @@ namespace data if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; // identity auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); - m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + num*LEASE_SIZE + m_Identity->GetSignatureLen (); + m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen (); m_Buffer = new uint8_t[m_BufferLen]; auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen); memcpy (m_Buffer + offset, encryptionPublicKey, 256); From 2e1a9a8df92abb5e564e3f91db7deabe6d0f2725 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 20/37] * HTTP.{cpp,h} : move length() method to base class --- HTTP.cpp | 2 +- HTTP.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HTTP.cpp b/HTTP.cpp index 254cab95..83f1ac3f 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -279,7 +279,7 @@ namespace http { return false; } - long int HTTPRes::length() { + long int HTTPMsg::length() { unsigned long int length = 0; auto it = headers.find("Content-Length"); if (it == headers.end()) diff --git a/HTTP.h b/HTTP.h index 7f73285f..15efc989 100644 --- a/HTTP.h +++ b/HTTP.h @@ -59,6 +59,9 @@ namespace http { void add_header(const char *name, const char *value, bool replace = false); void del_header(const char *name); + + /** @brief Returns declared message length or -1 if unknown */ + long int length(); }; struct HTTPReq : HTTPMsg { @@ -113,9 +116,6 @@ namespace http { /** @brief Checks that response declared as chunked data */ bool is_chunked(); - - /** @brief Returns declared response length or -1 if unknown */ - long int length(); }; /** From 43a90d7b98b1b317022f468bcf23027e039142fe Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 21/37] * HTTP.cpp : fix parse_header_line (#501) --- HTTP.cpp | 3 ++- tests/test-http-req.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/HTTP.cpp b/HTTP.cpp index 83f1ac3f..66dbc763 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -45,9 +45,10 @@ namespace http { bool parse_header_line(const std::string & line, std::map & headers) { std::size_t pos = 0; std::size_t len = 2; /* strlen(": ") */ + std::size_t max = line.length(); if ((pos = line.find(": ", pos)) == std::string::npos) return false; - while (isspace(line.at(pos + len))) + while ((pos + len) < max && isspace(line.at(pos + len))) len++; std::string name = line.substr(0, pos); std::string value = line.substr(pos + len); diff --git a/tests/test-http-req.cpp b/tests/test-http-req.cpp index 10ea621f..d5362622 100644 --- a/tests/test-http-req.cpp +++ b/tests/test-http-req.cpp @@ -68,6 +68,7 @@ int main() { buf = "GET http://inr.i2p HTTP/1.1\r\n" "Host: stats.i2p\r\n" + "Accept-Encoding: \r\n" "Accept: */*\r\n" "\r\n"; len = strlen(buf); @@ -76,9 +77,13 @@ int main() { assert(req->method == "GET"); assert(req->uri == "http://inr.i2p"); assert(req->host == "stats.i2p"); - assert(req->headers.size() == 2); + assert(req->headers.size() == 3); assert(req->headers.count("Host") == 1); assert(req->headers.count("Accept") == 1); + assert(req->headers.count("Accept-Encoding") == 1); + assert(req->headers["Host"] == "stats.i2p"); + assert(req->headers["Accept"] == "*/*"); + assert(req->headers["Accept-Encoding"] == ""); delete req; return 0; From f245feb0b0c003c3aba37e464dd0d415094bbd77 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 22/37] * HTTP.h : export MergeChunkedResponse() --- HTTP.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HTTP.h b/HTTP.h index 15efc989..0aa31b1e 100644 --- a/HTTP.h +++ b/HTTP.h @@ -132,6 +132,14 @@ namespace http { * @return Decoded string */ std::string UrlDecode(const std::string& data, bool null = false); + + /** + * @brief Merge HTTP response content with Transfer-Encoding: chunked + * @param in Input stream + * @param out Output stream + * @return true on success, false otherwise + */ + bool MergeChunkedResponse (std::istream& in, std::ostream& out); } // http } // i2p From a76d8f0f9f7c63c3468ba93a5a13efd31c8d73aa Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 23/37] * HTTP.{cpp,h} : add add_header() variant with std::string --- HTTP.cpp | 4 ++++ HTTP.h | 1 + 2 files changed, 5 insertions(+) diff --git a/HTTP.cpp b/HTTP.cpp index 66dbc763..3f6fd937 100644 --- a/HTTP.cpp +++ b/HTTP.cpp @@ -193,6 +193,10 @@ namespace http { return out; } + void HTTPMsg::add_header(const char *name, std::string & value, bool replace) { + add_header(name, value.c_str(), replace); + } + void HTTPMsg::add_header(const char *name, const char *value, bool replace) { std::size_t count = headers.count(name); if (count && !replace) diff --git a/HTTP.h b/HTTP.h index 0aa31b1e..f227271f 100644 --- a/HTTP.h +++ b/HTTP.h @@ -57,6 +57,7 @@ namespace http { struct HTTPMsg { std::map headers; + void add_header(const char *name, std::string & value, bool replace = false); void add_header(const char *name, const char *value, bool replace = false); void del_header(const char *name); From ebc411bbbd465bb930235dc546911199a1b1b342 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 24/37] * I2PControl.cpp : * use new http classes for building HTTP response * drop boost::lexical_cast & boost::local_time deps --- I2PControl.cpp | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index ab9feeed..0f92a5db 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include @@ -16,6 +14,7 @@ #include "Crypto.h" #include "FS.h" #include "Log.h" +#include "HTTP.h" #include "Config.h" #include "NetDb.h" #include "RouterContext.h" @@ -278,24 +277,21 @@ namespace client void I2PControlService::SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::ostringstream& response, bool isHtml) { - size_t len = response.str ().length (), offset = 0; - if (isHtml) - { - std::ostringstream header; - header << "HTTP/1.1 200 OK\r\n"; - header << "Connection: close\r\n"; - header << "Content-Length: " << boost::lexical_cast(len) << "\r\n"; - header << "Content-Type: application/json\r\n"; - header << "Date: "; - auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT"); - header.imbue(std::locale (header.getloc(), facet)); - header << boost::posix_time::second_clock::local_time() << "\r\n"; - header << "\r\n"; - offset = header.str ().size (); - memcpy (buf->data (), header.str ().c_str (), offset); + std::string out; + std::size_t len; + if (isHtml) { + i2p::http::HTTPRes res; + res.code = 200; + res.add_header("Content-Type", "application/json"); + res.add_header("Connection", "close"); + res.body = response.str(); + out = res.to_string(); + } else { + out = response.str(); } - memcpy (buf->data () + offset, response.str ().c_str (), len); - boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), + std::copy(out.begin(), out.end(), buf->begin()); + len = out.length(); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), len), boost::asio::transfer_all (), std::bind(&I2PControlService::HandleResponseSent, this, std::placeholders::_1, std::placeholders::_2, socket, buf)); @@ -322,7 +318,7 @@ namespace client } InsertParam (results, "API", api); results << ","; - std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); + std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ()); m_Tokens.insert (token); InsertParam (results, "Token", token); } From 0e1765e04563f526cbc066d31cde4ae3d28c87fc Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 25/37] * I2PControl.cpp : SendResponse() third arg now std::string & --- I2PControl.cpp | 20 +++++++++----------- I2PControl.h | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 0f92a5db..7a5014ec 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -192,6 +192,7 @@ namespace client try { bool isHtml = !memcmp (buf->data (), "POST", 4); + std::string content; std::stringstream ss; ss.write (buf->data (), bytes_transferred); if (isHtml) @@ -242,7 +243,8 @@ namespace client response << "\"jsonrpc\":\"2.0\"}"; } #endif - SendResponse (socket, buf, response, isHtml); + content = response.str(); + SendResponse (socket, buf, content, isHtml); } catch (std::exception& ex) { @@ -275,23 +277,19 @@ namespace client } void I2PControlService::SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::ostringstream& response, bool isHtml) + std::shared_ptr buf, std::string& content, bool isHtml) { - std::string out; - std::size_t len; if (isHtml) { i2p::http::HTTPRes res; res.code = 200; res.add_header("Content-Type", "application/json"); res.add_header("Connection", "close"); - res.body = response.str(); - out = res.to_string(); - } else { - out = response.str(); + res.body = content; + std::string tmp = res.to_string(); + content = tmp; } - std::copy(out.begin(), out.end(), buf->begin()); - len = out.length(); - boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), len), + std::copy(content.begin(), content.end(), buf->begin()); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), content.length()), boost::asio::transfer_all (), std::bind(&I2PControlService::HandleResponseSent, this, std::placeholders::_1, std::placeholders::_2, socket, buf)); diff --git a/I2PControl.h b/I2PControl.h index f2e82254..ed572c42 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -46,7 +46,7 @@ namespace client void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); void SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::ostringstream& response, bool isHtml); + std::shared_ptr buf, std::string& response, bool isHtml); void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); From 4f8db487e77675ebd691f309ac4143c05fefd158 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 26/37] * I2PControl.{cpp,h} : add BuildErrorResponse() --- I2PControl.cpp | 19 ++++++++++++------- I2PControl.h | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 7a5014ec..047f211e 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -221,9 +221,7 @@ namespace client std::ostringstream response; #if GCC47_BOOST149 LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); - response << "{\"id\":null,\"error\":"; - response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},"; - response << "\"jsonrpc\":\"2.0\"}"; + BuildErrorResponse(content, 32603, "JSON requests is not supported with this version of boost"); #else boost::property_tree::ptree pt; boost::property_tree::read_json (ss, pt); @@ -236,19 +234,18 @@ namespace client response << "{\"id\":" << id << ",\"result\":{"; (this->*(it->second))(pt.get_child ("params"), response); response << "},\"jsonrpc\":\"2.0\"}"; + content = response.str(); } else { LogPrint (eLogWarning, "I2PControl: unknown method ", method); - response << "{\"id\":null,\"error\":"; - response << "{\"code\":-32601,\"message\":\"Method not found\"},"; - response << "\"jsonrpc\":\"2.0\"}"; + BuildErrorResponse(content, 32601, "Method not found"); } #endif - content = response.str(); SendResponse (socket, buf, content, isHtml); } catch (std::exception& ex) { LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); + /* TODO: also send error, code 32603 */ } catch (...) { @@ -276,6 +273,14 @@ namespace client ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value; } + void I2PControlService::BuildErrorResponse (std::string & content, int code, const char *message) { + std::stringstream ss; + ss << "{\"id\":null,\"error\":"; + ss << "{\"code\":" << -code << ",\"message\":\"" << message << "\"},"; + ss << "\"jsonrpc\":\"2.0\"}"; + content = ss.str(); + } + void I2PControlService::SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::string& content, bool isHtml) { diff --git a/I2PControl.h b/I2PControl.h index ed572c42..bd5b9bad 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -45,6 +45,7 @@ namespace client void ReadRequest (std::shared_ptr socket); void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); + void BuildErrorResponse (std::string & content, int code, const char *message); void SendResponse (std::shared_ptr socket, std::shared_ptr buf, std::string& response, bool isHtml); void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, From 0ab5f993c7d576e055de3cb22b2cf29b92445bc3 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 27/37] * I2PControl.cpp : * use new http classes for parsing request * implement correct reading rest of json data if HTTP/Content-length is used * general cleanup --- I2PControl.cpp | 69 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 047f211e..d24c0b31 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -191,56 +191,55 @@ namespace client } else { try { - bool isHtml = !memcmp (buf->data (), "POST", 4); - std::string content; - std::stringstream ss; - ss.write (buf->data (), bytes_transferred); - if (isHtml) - { - std::string header; - size_t contentLength = 0; - while (!ss.eof () && header != "\r") - { - std::getline(ss, header); - auto colon = header.find (':'); - if (colon != std::string::npos && header.substr (0, colon) == "Content-Length") - contentLength = std::stoi (header.substr (colon + 1)); - } - if (ss.eof ()) - { - LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected"); - return; // TODO: + std::stringstream json; + std::string response; + bool isHTTP = false; + if (memcmp (buf->data (), "POST", 4) == 0) { + long int remains = 0; + isHTTP = true; + i2p::http::HTTPReq req; + std::size_t len = req.parse(buf->data(), bytes_transferred); + if (len <= 0) { + LogPrint(eLogError, "I2PControl: incomplete/malformed POST request"); + return; } - std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read - if (rem > 0) - { - bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), rem)); - ss.write (buf->data (), bytes_transferred); + /* append to json chunk of data from 1st request */ + json.write(buf->begin() + len, bytes_transferred - len); + remains = req.length() - len; + /* if request has Content-Length header, fetch rest of data and store to json buffer */ + while (remains > 0) { + len = ((long int) buf->size() < remains) ? buf->size() : remains; + bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len)); + json.write(buf->begin(), bytes_transferred); + remains -= bytes_transferred; } + } else { + json.write(buf->begin(), bytes_transferred); } - std::ostringstream response; + LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); #if GCC47_BOOST149 LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); - BuildErrorResponse(content, 32603, "JSON requests is not supported with this version of boost"); + BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost"); #else boost::property_tree::ptree pt; - boost::property_tree::read_json (ss, pt); + boost::property_tree::read_json (json, pt); std::string id = pt.get("id"); std::string method = pt.get("method"); auto it = m_MethodHandlers.find (method); if (it != m_MethodHandlers.end ()) { - response << "{\"id\":" << id << ",\"result\":{"; - (this->*(it->second))(pt.get_child ("params"), response); - response << "},\"jsonrpc\":\"2.0\"}"; - content = response.str(); + std::ostringstream ss; + ss << "{\"id\":" << id << ",\"result\":{"; + (this->*(it->second))(pt.get_child ("params"), ss); + ss << "},\"jsonrpc\":\"2.0\"}"; + response = ss.str(); } else { LogPrint (eLogWarning, "I2PControl: unknown method ", method); - BuildErrorResponse(content, 32601, "Method not found"); + BuildErrorResponse(response, 32601, "Method not found"); } #endif - SendResponse (socket, buf, content, isHtml); + SendResponse (socket, buf, response, isHTTP); } catch (std::exception& ex) { @@ -282,9 +281,9 @@ namespace client } void I2PControlService::SendResponse (std::shared_ptr socket, - std::shared_ptr buf, std::string& content, bool isHtml) + std::shared_ptr buf, std::string& content, bool isHTTP) { - if (isHtml) { + if (isHTTP) { i2p::http::HTTPRes res; res.code = 200; res.add_header("Content-Type", "application/json"); From 9291f5c9c6ea4c794361a9dfd6f94b3979c72a9e Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 28/37] * I2PControl.cpp : * unwrap big else {} block * smaller try {} block, only for json parsing & request handling * respond with valid error message on exception --- I2PControl.cpp | 111 +++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index d24c0b31..c87db150 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -188,69 +188,64 @@ namespace client if (ecode) { LogPrint (eLogError, "I2PControl: read error: ", ecode.message ()); return; + } + /* try to parse received data */ + std::stringstream json; + std::string response; + bool isHTTP = false; + if (memcmp (buf->data (), "POST", 4) == 0) { + long int remains = 0; + isHTTP = true; + i2p::http::HTTPReq req; + std::size_t len = req.parse(buf->data(), bytes_transferred); + if (len <= 0) { + LogPrint(eLogError, "I2PControl: incomplete/malformed POST request"); + return; + } + /* append to json chunk of data from 1st request */ + json.write(buf->begin() + len, bytes_transferred - len); + remains = req.length() - len; + /* if request has Content-Length header, fetch rest of data and store to json buffer */ + while (remains > 0) { + len = ((long int) buf->size() < remains) ? buf->size() : remains; + bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len)); + json.write(buf->begin(), bytes_transferred); + remains -= bytes_transferred; + } } else { - try - { - std::stringstream json; - std::string response; - bool isHTTP = false; - if (memcmp (buf->data (), "POST", 4) == 0) { - long int remains = 0; - isHTTP = true; - i2p::http::HTTPReq req; - std::size_t len = req.parse(buf->data(), bytes_transferred); - if (len <= 0) { - LogPrint(eLogError, "I2PControl: incomplete/malformed POST request"); - return; - } - /* append to json chunk of data from 1st request */ - json.write(buf->begin() + len, bytes_transferred - len); - remains = req.length() - len; - /* if request has Content-Length header, fetch rest of data and store to json buffer */ - while (remains > 0) { - len = ((long int) buf->size() < remains) ? buf->size() : remains; - bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len)); - json.write(buf->begin(), bytes_transferred); - remains -= bytes_transferred; - } - } else { - json.write(buf->begin(), bytes_transferred); - } - LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); + json.write(buf->begin(), bytes_transferred); + } + LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); #if GCC47_BOOST149 - LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); - BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost"); + LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7"); + BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost"); #else - boost::property_tree::ptree pt; - boost::property_tree::read_json (json, pt); - - std::string id = pt.get("id"); - std::string method = pt.get("method"); - auto it = m_MethodHandlers.find (method); - if (it != m_MethodHandlers.end ()) - { - std::ostringstream ss; - ss << "{\"id\":" << id << ",\"result\":{"; - (this->*(it->second))(pt.get_child ("params"), ss); - ss << "},\"jsonrpc\":\"2.0\"}"; - response = ss.str(); - } else { - LogPrint (eLogWarning, "I2PControl: unknown method ", method); - BuildErrorResponse(response, 32601, "Method not found"); - } -#endif - SendResponse (socket, buf, response, isHTTP); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); - /* TODO: also send error, code 32603 */ - } - catch (...) - { - LogPrint (eLogError, "I2PControl: handle request unknown exception"); + /* now try to parse json itself */ + try { + boost::property_tree::ptree pt; + boost::property_tree::read_json (json, pt); + + std::string id = pt.get("id"); + std::string method = pt.get("method"); + auto it = m_MethodHandlers.find (method); + if (it != m_MethodHandlers.end ()) { + std::ostringstream ss; + ss << "{\"id\":" << id << ",\"result\":{"; + (this->*(it->second))(pt.get_child ("params"), ss); + ss << "},\"jsonrpc\":\"2.0\"}"; + response = ss.str(); + } else { + LogPrint (eLogWarning, "I2PControl: unknown method ", method); + BuildErrorResponse(response, 32601, "Method not found"); } + } catch (std::exception& ex) { + LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); + BuildErrorResponse(response, 32603, ex.what()); + } catch (...) { + LogPrint (eLogError, "I2PControl: handle request unknown exception"); } +#endif + SendResponse (socket, buf, response, isHTTP); } void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const From 3c9459e489486fa77dc8964496dbf6593e711ba5 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 29/37] * fix mistype in log message --- Family.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Family.cpp b/Family.cpp index 90c5ccd0..ff09f2f5 100644 --- a/Family.cpp +++ b/Family.cpp @@ -94,7 +94,7 @@ namespace data int numCertificates = 0; if (!i2p::fs::ReadDir(certDir, files)) { - LogPrint(eLogWarning, "Reseed: Can't load reseed certificates from ", certDir); + LogPrint(eLogWarning, "Family: Can't load family certificates from ", certDir); return; } From 827a54435d6425340e6ceb825d67784722783bd0 Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 30/37] * Tunnel.cpp : tune log messages --- Tunnel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index bf81dc5e..ebaf98c8 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -562,7 +562,7 @@ namespace tunnel case eTunnelStatePending: if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT) { - LogPrint (eLogWarning, "Tunnel: pending build request ", it->first, " timeout, deleted"); + LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " timeout, deleted"); // update stats auto config = tunnel->GetTunnelConfig (); if (config) @@ -587,7 +587,7 @@ namespace tunnel it++; break; case eTunnelStateBuildFailed: - LogPrint (eLogWarning, "Tunnel: pending build request ", it->first, " failed, deleted"); + LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted"); it = pendingTunnels.erase (it); m_NumFailedTunnelCreations++; break; From 99398bf0daf572312f9f93315d4542f08cf5423c Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 31/37] * HTTPProxy.{cpp,h} : move & sort headers --- AddressBook.cpp | 1 - ClientContext.h | 1 + HTTPProxy.cpp | 8 +++++++- HTTPProxy.h | 7 ------- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/AddressBook.cpp b/AddressBook.cpp index 40e4c383..5a07b3c8 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "Base.h" #include "util.h" diff --git a/ClientContext.h b/ClientContext.h index cfbc039f..f5696902 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -6,6 +6,7 @@ #include #include #include "Destination.h" +#include "I2PService.h" #include "HTTPProxy.h" #include "SOCKS.h" #include "I2PTunnel.h" diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 6104e15e..d7af51e5 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -4,6 +4,13 @@ #include #include #include +#include +#include +#include +#include + +#include "I2PService.h" +#include "Destination.h" #include "HTTPProxy.h" #include "util.h" #include "Identity.h" @@ -351,6 +358,5 @@ namespace proxy { return std::make_shared (this, socket); } - } } diff --git a/HTTPProxy.h b/HTTPProxy.h index b5ed77b9..0356adb5 100644 --- a/HTTPProxy.h +++ b/HTTPProxy.h @@ -1,13 +1,6 @@ #ifndef HTTP_PROXY_H__ #define HTTP_PROXY_H__ -#include -#include -#include -#include -#include "I2PService.h" -#include "Destination.h" - namespace i2p { namespace proxy From 896bb2187e1e54ba7938f7455dc33a99fdca18fc Mon Sep 17 00:00:00 2001 From: hagen Date: Thu, 26 May 2016 00:00:00 +0000 Subject: [PATCH 32/37] * HTTPProxy.cpp : HTTPRequestFailed() now responds with error message --- HTTPProxy.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index d7af51e5..cc63ed0f 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -43,7 +43,7 @@ namespace proxy void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void Terminate(); void AsyncSockRead(); - void HTTPRequestFailed(/*std::string message*/); + void HTTPRequestFailed(const char *message); void RedirectToJumpService(); void ExtractRequest(); bool IsI2PAddress(); @@ -98,10 +98,17 @@ namespace proxy /* All hope is lost beyond this point */ //TODO: handle this apropriately - void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/) + void HTTPProxyHandler::HTTPRequestFailed(const char *message) { - static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n"; - boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), + std::size_t size = std::strlen(message); + static std::stringstream ss; + ss << "HTTP/1.0 500 Internal Server Error\r\n" + << "Content-Type: text/plain\r\n"; + ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" + << "\r\n"; /* end of headers */ + ss << message << "\r\n"; + std::string response = ss.str(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } @@ -146,7 +153,7 @@ namespace proxy if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) { LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); - HTTPRequestFailed(); //TODO: send right stuff + HTTPRequestFailed("unsupported HTTP version"); return false; } return true; @@ -283,13 +290,13 @@ namespace proxy case '\n': EnterState(DONE); break; default: LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); - HTTPRequestFailed(); //TODO: add correct code + HTTPRequestFailed("rejected invalid request"); return false; } break; default: LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); - HTTPRequestFailed(); //TODO: add correct code 500 + HTTPRequestFailed("invalid parser state"); return false; } http_buff++; @@ -345,7 +352,7 @@ namespace proxy else { LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); - HTTPRequestFailed(); // TODO: Send correct error message host unreachable + HTTPRequestFailed("error when creating the stream, check logs"); } } From fc25da37c549c1ecc1bb2466ee3185858ede812d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 May 2016 14:54:33 -0400 Subject: [PATCH 33/37] removed GetPrivateKeys from LocalDestination --- Destination.h | 5 ++++- Identity.h | 8 ++------ RouterContext.h | 4 +++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Destination.h b/Destination.h index 4c8bfc80..b42aba3d 100644 --- a/Destination.h +++ b/Destination.h @@ -147,6 +147,8 @@ namespace client bool Start (); bool Stop (); + const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; + // streaming std::shared_ptr CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr GetStreamingDestination (int port = 0) const; @@ -162,9 +164,10 @@ namespace client i2p::datagram::DatagramDestination * CreateDatagramDestination (); // implements LocalDestination - const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; + std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; + void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; protected: diff --git a/Identity.h b/Identity.h index d8abd6f4..541a7801 100644 --- a/Identity.h +++ b/Identity.h @@ -178,16 +178,12 @@ namespace data public: virtual ~LocalDestination() {}; - virtual const PrivateKeys& GetPrivateKeys () const = 0; virtual const uint8_t * GetEncryptionPrivateKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; + virtual std::shared_ptr GetIdentity () const = 0; + virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; - std::shared_ptr GetIdentity () const { return GetPrivateKeys ().GetPublic (); }; const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; - void Sign (const uint8_t * buf, int len, uint8_t * signature) const - { - GetPrivateKeys ().Sign (buf, len, signature); - }; }; } } diff --git a/RouterContext.h b/RouterContext.h index 29164f4b..05339847 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -30,6 +30,7 @@ namespace i2p RouterContext (); void Init (); + const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; std::shared_ptr GetSharedRouterInfo () const { @@ -73,9 +74,10 @@ namespace i2p void UpdateStats (); // implements LocalDestination - const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; + std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); }; const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetStandardIdentity ().publicKey; }; + void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void SetLeaseSetUpdated () {}; // implements GarlicDestination From 3d6c93cd6bd98e333ec600e39e3849e37063ae83 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 May 2016 15:53:32 -0400 Subject: [PATCH 34/37] moved transient encryption keys to LeaseSetDestination --- Destination.cpp | 56 ++++++++++++++++++++++++------------------------- Destination.h | 14 ++++++++----- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Destination.cpp b/Destination.cpp index 46ff688f..40c8768e 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -130,6 +130,10 @@ namespace client if (!m_IsRunning) { m_IsRunning = true; + if (m_IsPublic) + PersistTemporaryKeys (); + else + i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); m_Pool->SetLocalDestination (shared_from_this ()); m_Pool->SetActive (true); m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); @@ -640,14 +644,34 @@ namespace client } } + void LeaseSetDestination::PersistTemporaryKeys () + { + std::string ident = GetIdentHash().ToBase32(); + std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat")); + std::ifstream f(path, std::ifstream::binary); + + if (f) { + f.read ((char *)m_EncryptionPublicKey, 256); + f.read ((char *)m_EncryptionPrivateKey, 256); + return; + } + + LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p"); + i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); + + std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); + if (f1) { + f1.write ((char *)m_EncryptionPublicKey, 256); + f1.write ((char *)m_EncryptionPrivateKey, 256); + return; + } + LogPrint(eLogError, "Destinations: Can't save keys to ", path); + } + ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (isPublic, params), m_Keys (keys), m_DatagramDestination (nullptr) { - if (isPublic) - PersistTemporaryKeys (); - else - i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); if (isPublic) LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); } @@ -802,30 +826,6 @@ namespace client m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ()); return m_DatagramDestination; } - - void ClientDestination::PersistTemporaryKeys () - { - std::string ident = GetIdentHash().ToBase32(); - std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat")); - std::ifstream f(path, std::ifstream::binary); - - if (f) { - f.read ((char *)m_EncryptionPublicKey, 256); - f.read ((char *)m_EncryptionPrivateKey, 256); - return; - } - - LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p"); - i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); - - std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); - if (f1) { - f1.write ((char *)m_EncryptionPublicKey, 256); - f1.write ((char *)m_EncryptionPrivateKey, 256); - return; - } - LogPrint(eLogError, "Destinations: Can't save keys to ", path); - } std::vector > ClientDestination::GetAllStreams () const { diff --git a/Destination.h b/Destination.h index b42aba3d..e2531699 100644 --- a/Destination.h +++ b/Destination.h @@ -80,7 +80,11 @@ namespace client std::shared_ptr FindLeaseSet (const i2p::data::IdentHash& ident); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); void CancelDestinationRequest (const i2p::data::IdentHash& dest); - + + // implements LocalDestination + const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; + const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; + // implements GarlicDestination std::shared_ptr GetLeaseSet (); std::shared_ptr GetTunnelPool () const { return m_Pool; } @@ -113,9 +117,13 @@ namespace client void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleCleanupTimer (const boost::system::error_code& ecode); void CleanupRemoteLeaseSets (); + + void PersistTemporaryKeys (); private: + uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; + volatile bool m_IsRunning; std::thread * m_Thread; boost::asio::io_service m_Service; @@ -165,8 +173,6 @@ namespace client // implements LocalDestination std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; - const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; - const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; protected: @@ -176,14 +182,12 @@ namespace client private: - void PersistTemporaryKeys (); std::shared_ptr GetSharedFromThis () { return std::static_pointer_cast(shared_from_this ()); } private: i2p::data::PrivateKeys m_Keys; - uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; std::shared_ptr m_StreamingDestination; // default std::map > m_StreamingDestinationsByPorts; From 95f100f378ff1da4820f888b9e7ae1132a7eb95a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 May 2016 16:21:27 -0400 Subject: [PATCH 35/37] HTTP error message cleanup --- HTTPProxy.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index cc63ed0f..70c1dba3 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -101,14 +101,15 @@ namespace proxy void HTTPProxyHandler::HTTPRequestFailed(const char *message) { std::size_t size = std::strlen(message); - static std::stringstream ss; + std::stringstream ss; ss << "HTTP/1.0 500 Internal Server Error\r\n" << "Content-Type: text/plain\r\n"; ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" << "\r\n"; /* end of headers */ ss << message << "\r\n"; - std::string response = ss.str(); - boost::asio::async_write(*m_sock, boost::asio::buffer(response, response.size()), + static std::string response; + response = ss.str(); + boost::asio::async_write(*m_sock, boost::asio::buffer(response), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } @@ -119,7 +120,9 @@ namespace proxy uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; - boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()), + static std::string s; + s = response.str (); + boost::asio::async_write(*m_sock, boost::asio::buffer(s), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } From 5ad10955be548691b667ad2b043c6a837f1a1556 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 May 2016 16:27:53 -0400 Subject: [PATCH 36/37] use m_Response field for HTTP proxy response --- HTTPProxy.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 70c1dba3..f681f365 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -56,6 +56,7 @@ namespace proxy uint8_t m_http_buff[http_buffer_size]; std::shared_ptr m_sock; std::string m_request; //Data left to be sent + std::string m_Response; std::string m_url; //URL std::string m_method; //Method std::string m_version; //HTTP version @@ -107,9 +108,8 @@ namespace proxy ss << "Content-Length: " << std::to_string(size + 2) << "\r\n" << "\r\n"; /* end of headers */ ss << message << "\r\n"; - static std::string response; - response = ss.str(); - boost::asio::async_write(*m_sock, boost::asio::buffer(response), + m_Response = ss.str(); + boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } @@ -120,9 +120,8 @@ namespace proxy uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n"; - static std::string s; - s = response.str (); - boost::asio::async_write(*m_sock, boost::asio::buffer(s), + m_Response = response.str (); + boost::asio::async_write(*m_sock, boost::asio::buffer(m_Response), std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); } From 8622385e884bbf4bb3f0a005242aca82ddb5e5b8 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 27 May 2016 13:46:28 -0400 Subject: [PATCH 37/37] I2CPDestination added --- I2CP.cpp | 6 ++++++ I2CP.h | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/I2CP.cpp b/I2CP.cpp index d6ba4e42..5c718a48 100644 --- a/I2CP.cpp +++ b/I2CP.cpp @@ -8,6 +8,12 @@ namespace i2p { namespace client { + + I2CPDestination::I2CPDestination (I2CPSession& owner, std::shared_ptr identity, bool isPublic): + LeaseSetDestination (isPublic), m_Owner (owner), m_Identity (identity) + { + } + I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr socket): m_Owner (owner), m_Socket (socket), m_NextMessage (nullptr), m_NextMessageLen (0), m_NextMessageOffset (0) diff --git a/I2CP.h b/I2CP.h index cb17626d..020fd22a 100644 --- a/I2CP.h +++ b/I2CP.h @@ -5,6 +5,7 @@ #include #include #include +#include "Destination.h" namespace i2p { @@ -19,6 +20,28 @@ namespace client const uint8_t I2CP_GET_DATE_MESSAGE = 32; + class I2CPSession; + class I2CPDestination: public LeaseSetDestination + { + public: + + I2CPDestination (I2CPSession& owner, std::shared_ptr identity, bool isPublic); + + protected: + + // implements LocalDestination + std::shared_ptr GetIdentity () const { return m_Identity; }; + void Sign (const uint8_t * buf, int len, uint8_t * signature) const { /* TODO */}; + + // I2CP + void HandleDataMessage (const uint8_t * buf, size_t len) {}; + + private: + + I2CPSession& m_Owner; + std::shared_ptr m_Identity; + }; + class I2CPServer; class I2CPSession: public std::enable_shared_from_this { @@ -44,6 +67,8 @@ namespace client std::shared_ptr m_Socket; uint8_t m_Buffer[I2CP_SESSION_BUFFER_SIZE], * m_NextMessage; size_t m_NextMessageLen, m_NextMessageOffset; + + std::shared_ptr m_Destination; }; typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);