From 7ef6c72fc0365e2a4497c6a7306a6c43d855d124 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 1 Jan 2017 08:52:36 -0500 Subject: [PATCH 01/24] fix http auth fail when auth too long --- HTTPServer.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 1ba22303..b9c26cc5 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -713,9 +713,11 @@ namespace http { } /* method #2: 'Authorization' header sent */ if (req.headers.count("Authorization") > 0) { + bool result = false; std::string provided = req.headers.find("Authorization")->second; std::string expected = user + ":" + pass; - char b64_creds[64]; + size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()); + char * b64_creds = new char[b64_sz+1]; std::size_t len = 0; len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); /* if we decoded properly then check credentials */ @@ -723,10 +725,10 @@ namespace http { b64_creds[len] = '\0'; expected = "Basic "; expected += b64_creds; - return expected == provided; + result = expected == provided; } - /** we decoded wrong so it's not a correct login credential */ - return false; + delete [] b64_creds; + return result; } LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); From 75d790137dc9823da671c6f4c8c65fb9103c4ee8 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 1 Jan 2017 08:54:11 -0500 Subject: [PATCH 02/24] don't use sizeof --- HTTPServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index b9c26cc5..9cd8954d 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -716,10 +716,10 @@ namespace http { bool result = false; std::string provided = req.headers.find("Authorization")->second; std::string expected = user + ":" + pass; - size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()); - char * b64_creds = new char[b64_sz+1]; + size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1; + char * b64_creds = new char[b64_sz]; std::size_t len = 0; - len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); + len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, b64_sz); /* if we decoded properly then check credentials */ if(len) { b64_creds[len] = '\0'; From a8973f5463359956771cea8454f1baaf480181a3 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 1 Jan 2017 08:58:21 -0500 Subject: [PATCH 03/24] add peer count to transports --- HTTPServer.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 9cd8954d..184e02b1 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -494,8 +494,9 @@ namespace http { auto ntcpServer = i2p::transport::transports.GetNTCPServer (); if (ntcpServer) { - s << "NTCP
\r\n"; - for (const auto& it: ntcpServer->GetNTCPSessions ()) + auto sessions = ntcpServer->GetNTCPSessions (); + s << "NTCP ( " << (int) sessions.size() << " )
\r\n"; + for (const auto& it: sessions ) { if (it.second && it.second->IsEstablished ()) { @@ -512,8 +513,9 @@ namespace http { auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) { - s << "
\r\nSSU
\r\n"; - for (const auto& it: ssuServer->GetSessions ()) + auto sessions = ssuServer->GetSessions (); + s << "
\r\nSSU ( " << (int) sessions.size() << " )
\r\n"; + for (const auto& it: sessions) { auto endpoint = it.second->GetRemoteEndpoint (); if (it.second->IsOutgoing ()) s << " ⇒ "; From c2e7bc13a67b4ba6efe434db8ad4df68346ab032 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Jan 2017 14:29:39 -0500 Subject: [PATCH 04/24] last sample should have more relevance for latency --- Tunnel.cpp | 31 +++---------------------------- Tunnel.h | 31 ++++++++----------------------- 2 files changed, 11 insertions(+), 51 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index e1f5c035..84c4979f 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -19,36 +19,11 @@ namespace i2p { namespace tunnel -{ - - void TunnelLatency::AddSample(Sample s) - { - std::unique_lock l(m_access); - m_samples.push_back(s); - } - - bool TunnelLatency::HasSamples() const - { - std::unique_lock l(m_access); - return m_samples.size() > 0; - } - - TunnelLatency::Latency TunnelLatency::GetMeanLatency() const - { - std::unique_lock lock(m_access); - if (m_samples.size() > 0) { - Latency l = 0; - for(auto s : m_samples) - l += s; - return l / m_samples.size(); - } - return 0; - } - - +{ Tunnel::Tunnel (std::shared_ptr config): TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), - m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false) + m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false), + m_Latency (0) { } diff --git a/Tunnel.h b/Tunnel.h index f3c31461..08533ec4 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -78,21 +78,6 @@ namespace tunnel eTunnelStateFailed, eTunnelStateExpiring }; - - /** @brief for storing latency history */ - struct TunnelLatency - { - typedef uint64_t Sample; - typedef uint64_t Latency; - - - void AddSample(Sample s); - bool HasSamples() const; - Latency GetMeanLatency() const; - - std::vector m_samples; - mutable std::mutex m_access; - }; class OutboundTunnel; class InboundTunnel; @@ -133,14 +118,14 @@ namespace tunnel void SendTunnelDataMsg (std::shared_ptr msg); void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); - /** @brief add latency sample */ - void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); } - /** @brief get this tunnel's estimated latency */ - uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); } - /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */ - bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; + /** @brief add latency sample */ + void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; } + /** @brief get this tunnel's estimated latency */ + uint64_t GetMeanLatency() const { return m_Latency; } + /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */ + bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; - bool LatencyIsKnown() const { return m_Latency.HasSamples(); } + bool LatencyIsKnown() const { return m_Latency > 0; } protected: void PrintHops (std::stringstream& s) const; @@ -152,7 +137,7 @@ namespace tunnel std::shared_ptr m_Pool; // pool, tunnel belongs to, or null TunnelState m_State; bool m_IsRecreated; - TunnelLatency m_Latency; + uint64_t m_Latency; // in milliseconds }; class OutboundTunnel: public Tunnel From 7d5a929b5e23984727d28558e53fac2c6605b612 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Jan 2017 09:03:12 -0500 Subject: [PATCH 05/24] #761 info instead error --- Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Transports.cpp b/Transports.cpp index 23e90e29..163a7da9 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -384,7 +384,7 @@ namespace transport } } } - LogPrint (eLogError, "Transports: No NTCP or SSU addresses available"); + LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available"); peer.Done (); std::unique_lock l(m_PeersMutex); m_Peers.erase (ident); From b35e5f158295fecbd873e1e865d933a772dc2ef4 Mon Sep 17 00:00:00 2001 From: hypnosis-i2p Date: Sun, 18 Dec 2016 18:13:35 +0800 Subject: [PATCH 06/24] Create README.md --- qt/i2pd_qt/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 qt/i2pd_qt/README.md diff --git a/qt/i2pd_qt/README.md b/qt/i2pd_qt/README.md new file mode 100644 index 00000000..9016be06 --- /dev/null +++ b/qt/i2pd_qt/README.md @@ -0,0 +1,3 @@ +# Build Requirements + + * Qt 5 is necessary since Qt4 lacks QtWidgets/ folder From b776b85fc384576dc627303d6200f5498768dd61 Mon Sep 17 00:00:00 2001 From: hypnosis-i2p Date: Sun, 18 Dec 2016 18:19:46 +0800 Subject: [PATCH 07/24] Update README.md --- qt/i2pd_qt/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/i2pd_qt/README.md b/qt/i2pd_qt/README.md index 9016be06..94186ecf 100644 --- a/qt/i2pd_qt/README.md +++ b/qt/i2pd_qt/README.md @@ -1,3 +1,3 @@ # Build Requirements - * Qt 5 is necessary since Qt4 lacks QtWidgets/ folder + * Qt 5 is necessary (because Qt4 lacks QtWidgets/ folder) From c91f6db68a4d0feb4b1e1eb2b0f7f6ccc5bee39f Mon Sep 17 00:00:00 2001 From: hypnosis-i2p Date: Mon, 2 Jan 2017 23:38:08 +0800 Subject: [PATCH 08/24] updated to newer android sdk --- android/project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/project.properties b/android/project.properties index 7ce68660..f72b9716 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-24 +target=android-25 From 52035651758351077d14ec9b534abce4458ed81e Mon Sep 17 00:00:00 2001 From: hypnosis-i2p Date: Tue, 3 Jan 2017 01:14:44 +0800 Subject: [PATCH 09/24] updated icons --- android/res/drawable/icon.png | Bin 8712 -> 37177 bytes .../drawable/itoopie_notification_icon.png | Bin 33199 -> 37239 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png index a5dc7b680ba9dee30161ffb1c9fcd17bbd6ddd84..9a2f7404a20eef22adc6da0fb1538b6c507c97f4 100644 GIT binary patch literal 37177 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 RE#UwF002ovPDHLkV1gi%A?yGE literal 8712 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 diff --git a/android/res/drawable/itoopie_notification_icon.png b/android/res/drawable/itoopie_notification_icon.png index 8fbe24689b0af36100a6afa238829d7ce96a6529..d055bc8f897bdceee70c5a3e78ebedd926765a88 100644 GIT binary patch literal 37239 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 Date: Mon, 2 Jan 2017 16:36:59 -0500 Subject: [PATCH 10/24] don't store SSU-specific data for NTCP address --- RouterContext.cpp | 8 ++++--- RouterInfo.cpp | 55 +++++++++++++++++++++++++++++------------------ RouterInfo.h | 13 +++++++---- SSU.cpp | 4 ++-- SSUData.cpp | 10 ++++----- SSUSession.cpp | 14 ++++++------ 6 files changed, 62 insertions(+), 42 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 3c37e88c..966da6ac 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -266,8 +266,9 @@ namespace i2p } } // delete previous introducers - for (auto& addr : addresses) - addr->introducers.clear (); + for (auto& addr : addresses) + if (addr->ssu) + addr->ssu->introducers.clear (); // update UpdateRouterInfo (); @@ -298,7 +299,8 @@ namespace i2p } // delete previous introducers for (auto& addr : addresses) - addr->introducers.clear (); + if (addr->ssu) + addr->ssu->introducers.clear (); // update UpdateRouterInfo (); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 4ae2f9e5..08d46ecb 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -175,11 +175,14 @@ namespace data if (!strcmp (transportStyle, "NTCP")) address->transportStyle = eTransportNTCP; else if (!strcmp (transportStyle, "SSU")) + { address->transportStyle = eTransportSSU; + address->ssu.reset (new SSUExt ()); + address->ssu->mtu = 0; + } else address->transportStyle = eTransportUnknown; address->port = 0; - address->mtu = 0; uint16_t size, r = 0; s.read ((char *)&size, sizeof (size)); if (!s) return; size = be16toh (size); @@ -220,9 +223,19 @@ namespace data else if (!strcmp (key, "port")) address->port = boost::lexical_cast(value); else if (!strcmp (key, "mtu")) - address->mtu = boost::lexical_cast(value); + { + if (address->ssu) + address->ssu->mtu = boost::lexical_cast(value); + else + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP"); + } else if (!strcmp (key, "key")) - Base64ToByteStream (value, strlen (value), address->key, 32); + { + if (address->ssu) + Base64ToByteStream (value, strlen (value), address->ssu->key, 32); + else + LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); + } else if (!strcmp (key, "caps")) ExtractCaps (value); else if (key[0] == 'i') @@ -237,9 +250,9 @@ namespace data LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped"); if (s) continue; else return; } - if (index >= address->introducers.size ()) - address->introducers.resize (index + 1); - Introducer& introducer = address->introducers.at (index); + if (index >= address->ssu->introducers.size ()) + address->ssu->introducers.resize (index + 1); + Introducer& introducer = address->ssu->introducers.at (index); if (!strcmp (key, "ihost")) { boost::system::error_code ecode; @@ -417,10 +430,10 @@ namespace data if (address.transportStyle == eTransportSSU) { // write introducers if any - if (address.introducers.size () > 0) + if (address.ssu->introducers.size () > 0) { int i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("ihost" + boost::lexical_cast(i), properties); properties << '='; @@ -429,7 +442,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("ikey" + boost::lexical_cast(i), properties); properties << '='; @@ -441,7 +454,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("iport" + boost::lexical_cast(i), properties); properties << '='; @@ -450,7 +463,7 @@ namespace data i++; } i = 0; - for (const auto& introducer: address.introducers) + for (const auto& introducer: address.ssu->introducers) { WriteString ("itag" + boost::lexical_cast(i), properties); properties << '='; @@ -463,16 +476,16 @@ namespace data WriteString ("key", properties); properties << '='; char value[64]; - size_t l = ByteStreamToBase64 (address.key, 32, value, 64); + size_t l = ByteStreamToBase64 (address.ssu->key, 32, value, 64); value[l] = 0; WriteString (value, properties); properties << ';'; // write mtu - if (address.mtu) + if (address.ssu->mtu) { WriteString ("mtu", properties); properties << '='; - WriteString (boost::lexical_cast(address.mtu), properties); + WriteString (boost::lexical_cast(address.ssu->mtu), properties); properties << ';'; } } @@ -589,7 +602,6 @@ namespace data addr->transportStyle = eTransportNTCP; addr->cost = 2; addr->date = 0; - addr->mtu = 0; for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; @@ -604,8 +616,9 @@ namespace data addr->transportStyle = eTransportSSU; addr->cost = 10; // NTCP should have priority over SSU addr->date = 0; - addr->mtu = mtu; - memcpy (addr->key, key, 32); + addr->ssu.reset (new SSUExt ()); + addr->ssu->mtu = mtu; + memcpy (addr->ssu->key, key, 32); for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; @@ -621,9 +634,9 @@ namespace data { if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto& intro: addr->introducers) + for (auto& intro: addr->ssu->introducers) if (intro.iTag == introducer.iTag) return false; // already presented - addr->introducers.push_back (introducer); + addr->ssu->introducers.push_back (introducer); return true; } } @@ -636,10 +649,10 @@ namespace data { if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto it = addr->introducers.begin (); it != addr->introducers.end (); ++it) + for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { - addr->introducers.erase (it); + addr->ssu->introducers.erase (it); return true; } } diff --git a/RouterInfo.h b/RouterInfo.h index c51d3ce4..7300e579 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -79,17 +79,22 @@ namespace data uint32_t iTag; }; + struct SSUExt + { + int mtu; + IntroKey key; // intro key for SSU + std::vector introducers; + }; + struct Address { TransportStyle transportStyle; boost::asio::ip::address host; std::string addressString; - int port, mtu; + int port; uint64_t date; uint8_t cost; - // SSU only - IntroKey key; // intro key for SSU - std::vector introducers; + std::unique_ptr ssu; // not null for SSU bool IsCompatible (const boost::asio::ip::address& other) const { diff --git a/SSU.cpp b/SSU.cpp index 9f74185f..9dc05608 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -417,7 +417,7 @@ namespace transport return; } // create new session - int numIntroducers = address->introducers.size (); + int numIntroducers = address->ssu->introducers.size (); if (numIntroducers > 0) { std::shared_ptr introducerSession; @@ -425,7 +425,7 @@ namespace transport // we might have a session to introducer already for (int i = 0; i < numIntroducers; i++) { - auto intr = &(address->introducers[i]); + auto intr = &(address->ssu->introducers[i]); boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); if (ep.address ().is_v4 ()) // ipv4 only { diff --git a/SSUData.cpp b/SSUData.cpp index ad38cf25..1782da26 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -54,23 +54,23 @@ namespace transport { if (remoteRouter) return; auto ssuAddress = remoteRouter->GetSSUAddress (); - if (ssuAddress && ssuAddress->mtu) + if (ssuAddress && ssuAddress->ssu->mtu) { if (m_Session.IsV6 ()) - m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; + m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; else - m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; + m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; if (m_PacketSize > 0) { // make sure packet size multiple of 16 m_PacketSize >>= 4; m_PacketSize <<= 4; if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize; - LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize); + LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize); } else { - LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu); + LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu); m_PacketSize = m_MaxPacketSize; } } diff --git a/SSUSession.cpp b/SSUSession.cpp index a47295fa..540cf907 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -22,14 +22,14 @@ namespace transport { // we are client auto address = router->GetSSUAddress (false); - if (address) m_IntroKey = address->key; + if (address) m_IntroKey = address->ssu->key; m_Data.AdjustPacketSize (router); // mtu } else { // we are server auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); - if (address) m_IntroKey = address->key; + if (address) m_IntroKey = address->ssu->key; } m_CreationTime = i2p::util::GetSecondsSinceEpoch (); } @@ -115,8 +115,8 @@ namespace transport LogPrint (eLogInfo, "SSU is not supported"); return; } - if (Validate (buf, len, address->key)) - Decrypt (buf, len, address->key); + if (Validate (buf, len, address->ssu->key)) + Decrypt (buf, len, address->ssu->key); else { LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint); @@ -402,7 +402,7 @@ namespace transport payload += 2; *payload = 0; // challenge payload++; - memcpy (payload, (const uint8_t *)address->key, 32); + memcpy (payload, (const uint8_t *)address->ssu->key, 32); payload += 32; htobe32buf (payload, nonce); // nonce @@ -1075,7 +1075,7 @@ namespace transport // send our intro key to address instead it's own auto addr = i2p::context.GetRouterInfo ().GetSSUAddress (); if (addr) - memcpy (payload, addr->key, 32); // intro key + memcpy (payload, addr->ssu->key, 32); // intro key else LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); } @@ -1114,7 +1114,7 @@ namespace transport if (!nonce) nonce = 1; m_IsPeerTest = false; m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ()); - SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice + SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice } void SSUSession::SendKeepAlive () From 57310fdbd698e7bce166abe653e6b51e4f98e6b7 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jan 2017 11:52:28 -0500 Subject: [PATCH 11/24] reduced memory footprint --- NTCPSession.cpp | 7 +++++-- NTCPSession.h | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 712006c4..dca322c3 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -525,7 +525,7 @@ namespace transport memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); // try to read more - if (numReloads < 5) + if (numReloads < 16) // ~16K { boost::system::error_code ec; size_t moreBytes = m_Socket.available(ec); @@ -541,9 +541,12 @@ namespace transport return; } m_NumReceivedBytes += moreBytes; + i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); m_ReceiveBufferOffset += moreBytes; numReloads++; - } + } + else + break; // no more data } } while (m_ReceiveBufferOffset >= 16); diff --git a/NTCPSession.h b/NTCPSession.h index b02543be..a5d6f99f 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -35,12 +35,11 @@ namespace transport }; const size_t NTCP_MAX_MESSAGE_SIZE = 16384; - const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028) + const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448 - const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second const int NTCP_CLOCK_SKEW = 60; // in seconds const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up From cea6ea43443e120b7bb0c8f58919ed0b8c31cf5d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jan 2017 12:29:36 -0500 Subject: [PATCH 12/24] correct receive stats --- NTCPSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index dca322c3..18d04479 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -541,7 +541,7 @@ namespace transport return; } m_NumReceivedBytes += moreBytes; - i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); + i2p::transport::transports.UpdateReceivedBytes (moreBytes); m_ReceiveBufferOffset += moreBytes; numReloads++; } From 2e1c508bc4331b539ddbec522de8ac4277fa0255 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jan 2017 13:19:35 -0500 Subject: [PATCH 13/24] allocated bigger buffer for remaining data --- NTCPSession.cpp | 91 ++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 18d04479..fb324f54 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -493,7 +493,8 @@ namespace transport void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - if (ecode) { + if (ecode) + { if (ecode != boost::asio::error::operation_aborted) LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ()); //if (ecode != boost::asio::error::operation_aborted) @@ -507,51 +508,57 @@ namespace transport if (m_ReceiveBufferOffset >= 16) { - int numReloads = 0; - do - { - uint8_t * nextBlock = m_ReceiveBuffer; - while (m_ReceiveBufferOffset >= 16) + // process received data + uint8_t * nextBlock = m_ReceiveBuffer; + while (m_ReceiveBufferOffset >= 16) + { + if (!DecryptNextBlock (nextBlock)) // 16 bytes { - if (!DecryptNextBlock (nextBlock)) // 16 bytes - { - Terminate (); - return; - } - nextBlock += 16; - m_ReceiveBufferOffset -= 16; + Terminate (); + return; } - if (m_ReceiveBufferOffset > 0) - memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); - - // try to read more - if (numReloads < 16) // ~16K - { - boost::system::error_code ec; - size_t moreBytes = m_Socket.available(ec); - if (moreBytes && !ec) - { - if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset) - moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset; - moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes), ec); - if (ec) - { - LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ()); - Terminate (); - return; - } - m_NumReceivedBytes += moreBytes; - i2p::transport::transports.UpdateReceivedBytes (moreBytes); - m_ReceiveBufferOffset += moreBytes; - numReloads++; - } - else - break; // no more data + nextBlock += 16; + m_ReceiveBufferOffset -= 16; + } + if (m_ReceiveBufferOffset > 0) + memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); + } + + // read and process more is available + boost::system::error_code ec; + size_t moreBytes = m_Socket.available(ec); + if (moreBytes && !ec) + { + uint8_t * buf = nullptr, * moreBuf = m_ReceiveBuffer; + if (moreBytes + m_ReceiveBufferOffset > NTCP_BUFFER_SIZE) + { + buf = new uint8_t[moreBytes + m_ReceiveBufferOffset]; + if (m_ReceiveBufferOffset) + memcpy (buf, m_ReceiveBuffer, m_ReceiveBufferOffset); + moreBuf = buf; + } + moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec); + m_ReceiveBufferOffset += moreBytes; + m_NumReceivedBytes += moreBytes; + i2p::transport::transports.UpdateReceivedBytes (moreBytes); + // process more data + uint8_t * nextBlock = moreBuf; + while (m_ReceiveBufferOffset >= 16) + { + if (!DecryptNextBlock (nextBlock)) // 16 bytes + { + delete[] buf; + Terminate (); + return; } + nextBlock += 16; + m_ReceiveBufferOffset -= 16; } - while (m_ReceiveBufferOffset >= 16); - m_Handler.Flush (); - } + if (m_ReceiveBufferOffset > 0) + memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); // nextBlock points to memory inside buf + delete[] buf; + } + m_Handler.Flush (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); Receive (); From 1aae921ce71e35b4b797ce45498a142f48055aeb Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jan 2017 13:22:42 -0500 Subject: [PATCH 14/24] allocated bigger buffer for remaining data --- NTCPSession.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index fb324f54..5e44429d 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -538,6 +538,13 @@ namespace transport moreBuf = buf; } moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec); + if (ec) + { + LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ()); + delete[] buf; + Terminate (); + return; + } m_ReceiveBufferOffset += moreBytes; m_NumReceivedBytes += moreBytes; i2p::transport::transports.UpdateReceivedBytes (moreBytes); From 4f0c1d11eb29c7ac185e171a97d1f02cd9fea61d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Jan 2017 17:25:30 -0500 Subject: [PATCH 15/24] 16 bytes alignment for extra buffer --- NTCPSession.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 5e44429d..65da5def 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -532,10 +532,12 @@ namespace transport uint8_t * buf = nullptr, * moreBuf = m_ReceiveBuffer; if (moreBytes + m_ReceiveBufferOffset > NTCP_BUFFER_SIZE) { - buf = new uint8_t[moreBytes + m_ReceiveBufferOffset]; - if (m_ReceiveBufferOffset) - memcpy (buf, m_ReceiveBuffer, m_ReceiveBufferOffset); + buf = new uint8_t[moreBytes + m_ReceiveBufferOffset + 16]; moreBuf = buf; + uint8_t rem = ((size_t)buf) & 0x0f; + if (rem) moreBuf += (16 - rem); // align 16 + if (m_ReceiveBufferOffset) + memcpy (moreBuf, m_ReceiveBuffer, m_ReceiveBufferOffset); } moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec); if (ec) From 025d9d32767ad521aa8e419ebc0311240a16634a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Jan 2017 19:12:43 -0500 Subject: [PATCH 16/24] fixed #765 --- SAM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SAM.cpp b/SAM.cpp index cb704ebd..697c19c5 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -693,9 +693,9 @@ namespace client LogPrint (eLogDebug, "SAM: datagram received ", len); auto base64 = from.ToBase64 (); #ifdef _MSC_VER - size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len); + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (int)len); #else - size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len); + size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (int)len); #endif if (len < SAM_SOCKET_BUFFER_SIZE - l) { From 723f35ec5aa02ac84133c04eaa261a1677118f89 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Jan 2017 20:55:18 -0500 Subject: [PATCH 17/24] fixed crash --- I2PTunnel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index e94b5ed4..1a01a3c4 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -178,7 +178,7 @@ namespace client { if (bytes_transferred > 0) Write (m_StreamBuffer, bytes_transferred); // postpone termination - else if (ecode == boost::asio::error::timed_out && m_Stream->IsOpen ()) + else if (ecode == boost::asio::error::timed_out && m_Stream && m_Stream->IsOpen ()) StreamReceive (); else Terminate (); From 8ce55f90d35f29d346b7a6996173bd1bbab75612 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Jan 2017 10:30:27 -0500 Subject: [PATCH 18/24] more i2pcontrol options --- docs/configuration.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index b04be9fb..3212aea9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -73,9 +73,12 @@ All options below still possible in cmdline, but better write it in config file: * --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid * --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP -* --i2pcontrol.address= - The address to listen on (I2P control service) -* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified -* --i2pcontrol.enabled= - If I2P control is enabled. false by default +* --i2pcontrol.address= - The address to listen on (I2P control service) +* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified +* --i2pcontrol.enabled= - If I2P control is enabled. false by default +* --i2pcontrol.password= - I2P control authentication password. itoopie by default +* --i2pcontrol.cert= - I2P control HTTPS certificate file name. i2pcontrol.crt.pem by default +* --i2pcontrol.key= - I2P control HTTPS certificate key file name. i2pcontrol.key.pem by default * --upnp.enabled= - Enable or disable UPnP, false by default for CLI and true for GUI (Windows, Android) * --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default From f1eea6a0bf2456496eb190053985d0ac08bae987 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 5 Jan 2017 11:57:17 -0500 Subject: [PATCH 19/24] fix i2pcontrol bugs --- I2PControl.cpp | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 3e2e3997..1e8546ac 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -205,7 +205,7 @@ namespace client } /* append to json chunk of data from 1st request */ json.write(buf->data() + len, bytes_transferred - len); - remains = req.content_length() - len; + remains = req.content_length(); /* 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; @@ -216,15 +216,17 @@ namespace client } else { json.write(buf->data(), bytes_transferred); } - LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); + //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"); #else /* now try to parse json itself */ + std::string j_str = json.str(); + std::stringstream _json(j_str); try { boost::property_tree::ptree pt; - boost::property_tree::read_json (json, pt); + boost::property_tree::read_json (_json, pt); std::string id = pt.get("id"); std::string method = pt.get("method"); @@ -342,9 +344,10 @@ namespace client (this->*(it1->second))(it.second.data ()); InsertParam (results, it.first, ""); } - else + else { LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first); - } + } + } } void I2PControlService::PasswordHandler (const std::string& value) @@ -361,14 +364,17 @@ namespace client for (auto it = params.begin (); it != params.end (); ++it) { LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); + if (it != params.begin ()) results << ","; auto it1 = m_RouterInfoHandlers.find (it->first); if (it1 != m_RouterInfoHandlers.end ()) { - if (it != params.begin ()) results << ","; (this->*(it1->second))(results); } else + { + InsertParam(results, it->first, ""); LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first); + } } } @@ -436,13 +442,18 @@ namespace client { for (auto it = params.begin (); it != params.end (); ++it) { - if (it != params.begin ()) results << ","; + if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) { - (this->*(it1->second))(results); - } else + if (it1 != m_RouterManagerHandlers.end ()) + { + (this->*(it1->second))(results); + } + else + { + InsertParam(results, it->first, ""); LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); + } } } @@ -488,10 +499,15 @@ namespace client if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) { - (this->*(it1->second))(it->second.data (), results); - } else + if (it1 != m_NetworkSettingHandlers.end ()) + { + (this->*(it1->second))(it->second.data (), results); + } + else + { + InsertParam(results, it->first, ""); LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); + } } } From 11231abe8a7cd2375acf0d85f0f670a60211ca65 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Jan 2017 13:31:23 -0500 Subject: [PATCH 20/24] fixed warning --- SAM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SAM.cpp b/SAM.cpp index 697c19c5..c3b4faf1 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -693,9 +693,9 @@ namespace client LogPrint (eLogDebug, "SAM: datagram received ", len); auto base64 = from.ToBase64 (); #ifdef _MSC_VER - size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (int)len); + size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #else - size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (int)len); + size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len); #endif if (len < SAM_SOCKET_BUFFER_SIZE - l) { From 5ad25376bb07cc54a672340707e8d53e6a135a6f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Jan 2017 16:03:53 -0500 Subject: [PATCH 21/24] send all outgoing messages in one buffer --- NTCPSession.cpp | 36 +++++++++++++++++++----------------- NTCPSession.h | 5 ++--- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 65da5def..88c926fd 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -635,14 +635,7 @@ namespace transport return true; } - void NTCPSession::Send (std::shared_ptr msg) - { - m_IsSending = true; - boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (), - std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector >{ msg })); - } - - boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr msg) + size_t NTCPSession::CreateMsgBuffer (std::shared_ptr msg, uint8_t * buf) { uint8_t * sendBuffer; int len; @@ -674,24 +667,29 @@ namespace transport htobe32buf (sendBuffer + len + 2 + padding, adler32 (adler32 (0, Z_NULL, 0), sendBuffer, len + 2+ padding)); int l = len + padding + 6; - m_Encryption.Encrypt(sendBuffer, l, sendBuffer); - return boost::asio::buffer ((const uint8_t *)sendBuffer, l); + m_Encryption.Encrypt(sendBuffer, l, buf); + return l; } void NTCPSession::Send (const std::vector >& msgs) { + if (!msgs.size ()) return; m_IsSending = true; - std::vector bufs; + size_t len = 0; + for (const auto& it: msgs) + len += it->GetLength () + 22; // 6 + 16 + uint8_t * buf = new uint8_t[len]; + len = 0; for (const auto& it: msgs) - bufs.push_back (CreateMsgBuffer (it)); - boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (), - std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); + len += CreateMsgBuffer (it, buf + len); + boost::asio::async_write (m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), + std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, buf)); } - void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs) + void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint8_t * buf) { - (void) msgs; + delete[] buf; m_IsSending = false; if (ecode) { @@ -716,7 +714,11 @@ namespace transport void NTCPSession::SendTimeSyncMessage () { - Send (nullptr); + uint8_t * buf = new uint8_t[16]; + m_IsSending = true; + auto len = CreateMsgBuffer (nullptr, buf); // nullptr means timestamp + boost::asio::async_write (m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), + std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, buf)); } diff --git a/NTCPSession.h b/NTCPSession.h index a5d6f99f..bd3f3369 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -91,10 +91,9 @@ namespace transport void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); bool DecryptNextBlock (const uint8_t * encrypted); - void Send (std::shared_ptr msg); - boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr msg); + size_t CreateMsgBuffer (std::shared_ptr msg, uint8_t * buf); void Send (const std::vector >& msgs); - void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs); + void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint8_t * buf); private: From 0b28812f7ed357f64a436ac41c5bc49da73887d8 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Jan 2017 17:37:39 -0500 Subject: [PATCH 22/24] rollback --- NTCPSession.cpp | 36 +++++++++++++++++------------------- NTCPSession.h | 5 +++-- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 88c926fd..65da5def 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -635,7 +635,14 @@ namespace transport return true; } - size_t NTCPSession::CreateMsgBuffer (std::shared_ptr msg, uint8_t * buf) + void NTCPSession::Send (std::shared_ptr msg) + { + m_IsSending = true; + boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (), + std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector >{ msg })); + } + + boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr msg) { uint8_t * sendBuffer; int len; @@ -667,29 +674,24 @@ namespace transport htobe32buf (sendBuffer + len + 2 + padding, adler32 (adler32 (0, Z_NULL, 0), sendBuffer, len + 2+ padding)); int l = len + padding + 6; - m_Encryption.Encrypt(sendBuffer, l, buf); - return l; + m_Encryption.Encrypt(sendBuffer, l, sendBuffer); + return boost::asio::buffer ((const uint8_t *)sendBuffer, l); } void NTCPSession::Send (const std::vector >& msgs) { - if (!msgs.size ()) return; m_IsSending = true; - size_t len = 0; - for (const auto& it: msgs) - len += it->GetLength () + 22; // 6 + 16 - uint8_t * buf = new uint8_t[len]; - len = 0; + std::vector bufs; for (const auto& it: msgs) - len += CreateMsgBuffer (it, buf + len); - boost::asio::async_write (m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), - std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, buf)); + bufs.push_back (CreateMsgBuffer (it)); + boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (), + std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); } - void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint8_t * buf) + void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs) { - delete[] buf; + (void) msgs; m_IsSending = false; if (ecode) { @@ -714,11 +716,7 @@ namespace transport void NTCPSession::SendTimeSyncMessage () { - uint8_t * buf = new uint8_t[16]; - m_IsSending = true; - auto len = CreateMsgBuffer (nullptr, buf); // nullptr means timestamp - boost::asio::async_write (m_Socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), - std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, buf)); + Send (nullptr); } diff --git a/NTCPSession.h b/NTCPSession.h index bd3f3369..a5d6f99f 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -91,9 +91,10 @@ namespace transport void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); bool DecryptNextBlock (const uint8_t * encrypted); - size_t CreateMsgBuffer (std::shared_ptr msg, uint8_t * buf); + void Send (std::shared_ptr msg); + boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr msg); void Send (const std::vector >& msgs); - void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint8_t * buf); + void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs); private: From 417eb56a9be3b47d44a3c15ec14a6abbc0f2baef Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Jan 2017 09:59:22 -0500 Subject: [PATCH 23/24] rollback to 2.6.0 --- I2PControl.cpp | 199 +++++++++++++++++++++++-------------------------- I2PControl.h | 4 +- 2 files changed, 96 insertions(+), 107 deletions(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 1e8546ac..6d6a5ee3 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include @@ -14,7 +16,6 @@ #include "Crypto.h" #include "FS.h" #include "Log.h" -#include "HTTP.h" #include "Config.h" #include "NetDb.h" #include "RouterContext.h" @@ -189,66 +190,71 @@ 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->data() + len, bytes_transferred - len); - remains = req.content_length(); - /* 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->data(), bytes_transferred); - remains -= bytes_transferred; - } } else { - json.write(buf->data(), bytes_transferred); - } - //LogPrint(eLogDebug, "I2PControl: json from request: ", json.str()); + try + { + bool isHtml = !memcmp (buf->data (), "POST", 4); + 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::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); + } + } + std::ostringstream response; #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"); + response << "{\"id\":null,\"error\":"; + response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},"; + response << "\"jsonrpc\":\"2.0\"}"; #else - /* now try to parse json itself */ - std::string j_str = json.str(); - std::stringstream _json(j_str); - 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"); + boost::property_tree::ptree pt; + boost::property_tree::read_json (ss, 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\"}"; + } else { + LogPrint (eLogWarning, "I2PControl: unknown method ", method); + response << "{\"id\":null,\"error\":"; + response << "{\"code\":-32601,\"message\":\"Method not found\"},"; + response << "\"jsonrpc\":\"2.0\"}"; + } +#endif + SendResponse (socket, buf, response, isHtml); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); + } + catch (...) + { + LogPrint (eLogError, "I2PControl: handle request unknown exception"); } - } 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 @@ -270,28 +276,27 @@ 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 isHTTP) - { - if (isHTTP) { - i2p::http::HTTPRes res; - res.code = 200; - res.add_header("Content-Type", "application/json"); - res.add_header("Connection", "close"); - res.body = content; - std::string tmp = res.to_string(); - content = tmp; + 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::copy(content.begin(), content.end(), buf->begin()); - boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), content.length()), + memcpy (buf->data () + offset, response.str ().c_str (), len); + boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len), boost::asio::transfer_all (), std::bind(&I2PControlService::HandleResponseSent, this, std::placeholders::_1, std::placeholders::_2, socket, buf)); @@ -318,7 +323,7 @@ namespace client } InsertParam (results, "API", api); results << ","; - std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ()); + std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); m_Tokens.insert (token); InsertParam (results, "Token", token); } @@ -344,10 +349,9 @@ namespace client (this->*(it1->second))(it.second.data ()); InsertParam (results, it.first, ""); } - else { + else LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first); - } - } + } } void I2PControlService::PasswordHandler (const std::string& value) @@ -361,20 +365,17 @@ namespace client void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); - if (it != params.begin ()) results << ","; auto it1 = m_RouterInfoHandlers.find (it->first); if (it1 != m_RouterInfoHandlers.end ()) { + if (it != params.begin ()) results << ","; (this->*(it1->second))(results); } else - { - InsertParam(results, it->first, ""); LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first); - } } } @@ -440,20 +441,15 @@ namespace client void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { - if (it != params.begin ()) results << ","; + if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) - { - (this->*(it1->second))(results); - } - else - { - InsertParam(results, it->first, ""); + if (it1 != m_RouterManagerHandlers.end ()) { + (this->*(it1->second))(results); + } else LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); - } } } @@ -494,20 +490,15 @@ namespace client // network setting void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - for (auto it = params.begin (); it != params.end (); ++it) + for (auto it = params.begin (); it != params.end (); it++) { if (it != params.begin ()) results << ","; LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) - { - (this->*(it1->second))(it->second.data (), results); - } - else - { - InsertParam(results, it->first, ""); + if (it1 != m_NetworkSettingHandlers.end ()) { + (this->*(it1->second))(it->second.data (), results); + } else LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); - } } } diff --git a/I2PControl.h b/I2PControl.h index bd5b9bad..047c2fe2 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -45,9 +45,8 @@ 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); + std::shared_ptr buf, std::ostringstream& response, bool isHtml); void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); @@ -120,4 +119,3 @@ namespace client } #endif - From fde1c08945a173518a9274005a3a3e4edb33cdb1 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Jan 2017 14:02:54 -0500 Subject: [PATCH 24/24] change country code to A1 --- I2PControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/I2PControl.cpp b/I2PControl.cpp index 6d6a5ee3..523f10e1 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -536,7 +536,7 @@ namespace client X509_gmtime_adj (X509_get_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration X509_set_pubkey (x509, pkey); // public key X509_NAME * name = X509_get_subject_name (x509); - X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"RU", -1, -1, 0); // country (Russia by default) + X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy) X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name X509_set_issuer_name (x509, name); // set issuer to ourselves