From 91ec08df4e2203b06882275b859883b519d3c7cd Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2016 09:52:18 -0400 Subject: [PATCH 01/11] wait for close from other side --- Streaming.cpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 2d3c92ce..0951a6f2 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -66,6 +66,7 @@ namespace stream m_SendHandler = nullptr; handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); } + m_LocalDestination.DeleteStream (shared_from_this ()); } void Stream::HandleNextPacket (Packet * packet) @@ -220,11 +221,18 @@ namespace stream m_LastReceivedSequenceNumber = receivedSeqn; - if (flags & (PACKET_FLAG_CLOSE | PACKET_FLAG_RESET)) + if (flags & PACKET_FLAG_RESET) { m_Status = eStreamStatusReset; Close (); } + else if (flags & PACKET_FLAG_CLOSE) + { + if (m_Status != eStreamStatusClosed) + SendClose (); + m_Status = eStreamStatusClosed; + Terminate (); + } } void Stream::ProcessAck (Packet * packet) @@ -295,7 +303,7 @@ namespace stream SendBuffer (); } if (m_Status == eStreamStatusClosing) - Close (); // all outgoing messages have been sent + Close (); // check is all outgoing messages have been sent and we can send close } size_t Stream::Send (const uint8_t * buf, size_t len) @@ -495,23 +503,19 @@ namespace stream LogPrint (eLogDebug, "Streaming: Trying to send stream data before closing, sSID=", m_SendStreamID); break; case eStreamStatusReset: - SendClose (); - Terminate (); - m_LocalDestination.DeleteStream (shared_from_this ()); + // TODO: send reset + Terminate (); break; case eStreamStatusClosing: if (m_SentPackets.empty () && m_SendBuffer.eof ()) // nothing to send { m_Status = eStreamStatusClosed; SendClose (); - Terminate (); - m_LocalDestination.DeleteStream (shared_from_this ()); } break; case eStreamStatusClosed: // already closed Terminate (); - m_LocalDestination.DeleteStream (shared_from_this ()); break; default: LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status, "sSID=", m_SendStreamID); @@ -578,15 +582,10 @@ namespace stream m_AckSendTimer.cancel (); } SendPackets (std::vector { packet }); - if (m_Status == eStreamStatusOpen) - { - bool isEmpty = m_SentPackets.empty (); - m_SentPackets.insert (packet); - if (isEmpty) - ScheduleResend (); - } - else - delete packet; + bool isEmpty = m_SentPackets.empty (); + m_SentPackets.insert (packet); + if (isEmpty) + ScheduleResend (); return true; } else From 4cf5ce871f32b91e66cdcd2dea71a0cd0c55690e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jul 2016 17:52:11 -0400 Subject: [PATCH 02/11] destroy socket upon receive an ack for close --- Streaming.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 0951a6f2..74046ef7 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -36,7 +36,6 @@ namespace stream Stream::~Stream () { - Terminate (); while (!m_ReceiveQueue.empty ()) { auto packet = m_ReceiveQueue.front (); @@ -302,7 +301,9 @@ namespace stream m_NumResendAttempts = 0; SendBuffer (); } - if (m_Status == eStreamStatusClosing) + if (m_Status == eStreamStatusClosed) + Terminate (); + else if (m_Status == eStreamStatusClosing) Close (); // check is all outgoing messages have been sent and we can send close } From 43ed05d3c299b58781354983a59a66ecfb20e936 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2016 11:29:00 -0400 Subject: [PATCH 03/11] Create build_notes_android.md --- docs/build_notes_android.md | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 docs/build_notes_android.md diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md new file mode 100644 index 00000000..65b1590c --- /dev/null +++ b/docs/build_notes_android.md @@ -0,0 +1,42 @@ +Pre-requesties +-------------- + +You need to install Android SDK, NDK and QT with android support. + +SDK (choose command line tools only) +https://developer.android.com/studio/index.html +NDK +https://developer.android.com/ndk/downloads/index.html + +QT +https://www.qt.io/download-open-source/ +Choose one for your platform for android +For example QT 5.6 under Linux would be +http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run + +You also need Java JDK and Ant. + +QT-Creator +---------- +Open QT-creator that should be installed with QT. +Go to Settings/Anndroid and specify correct paths to SDK and NDK. +If everything is correct you will see two set avaiable: +Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt). + +Dependencies +-------------- +Take following pre-compiled binaries from PurpleI2P's repositories. +git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/android-ifaddrs.git + + +Building the app +---------------- +Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. +Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. +Select appropriate project (usually armeabi-v7a) and build. +You will find an .apk file in android-build/bin folder. + + From cfc80b491f706425fc32f7e3911a32583be8e7db Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2016 11:29:43 -0400 Subject: [PATCH 04/11] Update build_notes_android.md --- docs/build_notes_android.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md index 65b1590c..7e3f91fa 100644 --- a/docs/build_notes_android.md +++ b/docs/build_notes_android.md @@ -8,7 +8,7 @@ https://developer.android.com/studio/index.html NDK https://developer.android.com/ndk/downloads/index.html -QT +QT https://www.qt.io/download-open-source/ Choose one for your platform for android For example QT 5.6 under Linux would be @@ -26,10 +26,10 @@ Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt). Dependencies -------------- Take following pre-compiled binaries from PurpleI2P's repositories. -git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/android-ifaddrs.git +git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/android-ifaddrs.git Building the app From 76e1114a1f81f89403c9ccee3f3428b763443331 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2016 11:30:11 -0400 Subject: [PATCH 05/11] Update build_notes_android.md --- docs/build_notes_android.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md index 7e3f91fa..dcce4a4d 100644 --- a/docs/build_notes_android.md +++ b/docs/build_notes_android.md @@ -5,7 +5,7 @@ You need to install Android SDK, NDK and QT with android support. SDK (choose command line tools only) https://developer.android.com/studio/index.html -NDK +NDK https://developer.android.com/ndk/downloads/index.html QT @@ -34,9 +34,9 @@ git clone https://github.com/PurpleI2P/android-ifaddrs.git Building the app ---------------- -Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. -Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. -Select appropriate project (usually armeabi-v7a) and build. +Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. +Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. +Select appropriate project (usually armeabi-v7a) and build. You will find an .apk file in android-build/bin folder. From ce9e0981a2111a624bcc95780f6041321ba8f542 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Wed, 6 Jul 2016 16:03:54 +0000 Subject: [PATCH 06/11] Update index.rst --- docs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.rst b/docs/index.rst index d0471add..13cd9edb 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,6 +32,7 @@ Contents: build_requirements build_notes_unix build_notes_windows + build_notes_android configuration family From 953d78da9ef10008cdb2291f2ffa6a4e0e097d63 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Wed, 6 Jul 2016 16:10:30 +0000 Subject: [PATCH 07/11] Update build_notes_android.md --- docs/build_notes_android.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md index dcce4a4d..ef53b719 100644 --- a/docs/build_notes_android.md +++ b/docs/build_notes_android.md @@ -1,3 +1,6 @@ +Building on Android +=================== + Pre-requesties -------------- From b64b5d91030503a180197ab54642337bade075a6 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Wed, 6 Jul 2016 17:55:36 +0000 Subject: [PATCH 08/11] Update build_notes_android.md --- docs/build_notes_android.md | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md index ef53b719..71f0b2bc 100644 --- a/docs/build_notes_android.md +++ b/docs/build_notes_android.md @@ -6,16 +6,9 @@ Pre-requesties You need to install Android SDK, NDK and QT with android support. -SDK (choose command line tools only) -https://developer.android.com/studio/index.html -NDK -https://developer.android.com/ndk/downloads/index.html - -QT -https://www.qt.io/download-open-source/ -Choose one for your platform for android -For example QT 5.6 under Linux would be -http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run +- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only) +- [NDK](https://developer.android.com/ndk/downloads/index.html) +- [QT](https://www.qt.io/download-open-source/). Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run ) You also need Java JDK and Ant. @@ -29,17 +22,19 @@ Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt). Dependencies -------------- Take following pre-compiled binaries from PurpleI2P's repositories. +```bash git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git git clone https://github.com/PurpleI2P/android-ifaddrs.git +``` Building the app ---------------- -Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. -Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. -Select appropriate project (usually armeabi-v7a) and build. -You will find an .apk file in android-build/bin folder. +- Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator. +- Change line MAIN_PATH = /path/to/libraries to actual path where did you put the dependancies to. +- Select appropriate project (usually armeabi-v7a) and build. +- You will find an .apk file in android-build/bin folder. From 66dafca61adc04d560c8d9060ab16814ec4c67e1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jul 2016 22:34:24 -0400 Subject: [PATCH 09/11] select existing connection for first hop of a tunnel --- TunnelPool.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 515e0f5d..4bd116cb 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -330,8 +330,8 @@ namespace tunnel { if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound); int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; - if (numHops <= 0) return true; - auto prevHop = i2p::context.GetSharedRouterInfo(); + if (numHops <= 0) return true; // peers is empty + auto prevHop = i2p::context.GetSharedRouterInfo (); if(i2p::transport::transports.RoutesRestricted()) { /** if routes are restricted prepend trusted first hop */ @@ -340,6 +340,17 @@ namespace tunnel peers.push_back(hop->GetRouterIdentity()); prevHop = hop; } + else if (i2p::transport::transports.GetNumPeers () > 25) + { + auto r = i2p::transport::transports.GetRandomPeer (); + if (r && !r->GetProfile ()->IsBad ()) + { + prevHop = r; + peers.push_back (r->GetRouterIdentity ()); + numHops--; + } + } + for(int i = 0; i < numHops; i++ ) { auto hop = SelectNextHop (prevHop); From 1da5be28717f55a1c7f99bf0cc18f0dcfb20b031 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 7 Jul 2016 22:39:20 -0400 Subject: [PATCH 10/11] clean up unconfirmed tags faster --- Garlic.cpp | 42 +++++++++++++++++++++++++----------------- Garlic.h | 3 ++- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index 17740fae..dc29cc5b 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -38,9 +38,6 @@ namespace garlic GarlicRoutingSession::~GarlicRoutingSession () { - for (auto it: m_UnconfirmedTagsMsgs) - delete it.second; - m_UnconfirmedTagsMsgs.clear (); } std::shared_ptr GarlicRoutingSession::GetSharedRoutingPath () @@ -94,18 +91,27 @@ namespace garlic void GarlicRoutingSession::TagsConfirmed (uint32_t msgID) { - auto it = m_UnconfirmedTagsMsgs.find (msgID); - if (it != m_UnconfirmedTagsMsgs.end ()) + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - UnconfirmedTags * tags = it->second; - if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) - { - for (int i = 0; i < tags->numTags; i++) - m_SessionTags.push_back (tags->sessionTags[i]); + auto& tags = *it; + if (tags->msgID == msgID) + { + if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) + { + for (int i = 0; i < tags->numTags; i++) + m_SessionTags.push_back (tags->sessionTags[i]); + } + it = m_UnconfirmedTagsMsgs.erase (it); } - m_UnconfirmedTagsMsgs.erase (it); - delete tags; + else if (ts >= tags->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) + { + if (m_Owner) + m_Owner->RemoveDeliveryStatusSession (tags->msgID); + it = m_UnconfirmedTagsMsgs.erase (it); + } + else + it++; } } @@ -122,11 +128,10 @@ namespace garlic // delete expired unconfirmed tags for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) { - if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) + if (ts >= (*it)->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) { if (m_Owner) - m_Owner->RemoveDeliveryStatusSession (it->first); - delete it->second; + m_Owner->RemoveDeliveryStatusSession ((*it)->msgID); it = m_UnconfirmedTagsMsgs.erase (it); } else @@ -258,7 +263,10 @@ namespace garlic size += cloveSize; (*numCloves)++; if (newTags) // new tags created - m_UnconfirmedTagsMsgs[msgID] = newTags; + { + newTags->msgID = msgID; + m_UnconfirmedTagsMsgs.emplace_back (newTags); + } m_Owner->DeliveryStatusSent (shared_from_this (), msgID); } else diff --git a/Garlic.h b/Garlic.h index 6d25fd39..21acf561 100644 --- a/Garlic.h +++ b/Garlic.h @@ -83,6 +83,7 @@ namespace garlic { UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; }; ~UnconfirmedTags () { delete[] sessionTags; }; + uint32_t msgID; int numTags; SessionTag * sessionTags; uint32_t tagsCreationTime; @@ -123,7 +124,7 @@ namespace garlic i2p::crypto::AESKey m_SessionKey; std::list m_SessionTags; int m_NumTags; - std::map m_UnconfirmedTagsMsgs; + std::list > m_UnconfirmedTagsMsgs; LeaseSetUpdateStatus m_LeaseSetUpdateStatus; uint32_t m_LeaseSetUpdateMsgID; From 9b6c229b7138bf5bc1a0bf9c25f721bf1333d311 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 8 Jul 2016 14:17:41 -0400 Subject: [PATCH 11/11] remember tunnels selection for following messages --- Garlic.cpp | 15 ++++++++++++--- Garlic.h | 1 + I2CP.cpp | 44 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index dc29cc5b..d48e9d94 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -125,6 +125,14 @@ namespace garlic else it++; } + CleanupUnconfirmedTags (); + return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); + } + + bool GarlicRoutingSession::CleanupUnconfirmedTags () + { + bool ret = false; + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); // delete expired unconfirmed tags for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) { @@ -133,12 +141,13 @@ namespace garlic if (m_Owner) m_Owner->RemoveDeliveryStatusSession ((*it)->msgID); it = m_UnconfirmedTagsMsgs.erase (it); + ret = true; } else it++; } - return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); - } + return ret; + } std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) { @@ -625,7 +634,7 @@ namespace garlic it++; } } - + void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) { m_DeliveryStatusSessions.erase (msgID); diff --git a/Garlic.h b/Garlic.h index 21acf561..6a92b94a 100644 --- a/Garlic.h +++ b/Garlic.h @@ -98,6 +98,7 @@ namespace garlic std::shared_ptr WrapSingleMessage (std::shared_ptr msg); void MessageConfirmed (uint32_t msgID); bool CleanupExpiredTags (); // returns true if something left + bool CleanupUnconfirmedTags (); // returns true if something has been deleted void SetLeaseSetUpdated () { diff --git a/I2CP.cpp b/I2CP.cpp index 061f220c..0867d719 100644 --- a/I2CP.cpp +++ b/I2CP.cpp @@ -87,23 +87,51 @@ namespace client } bool I2CPDestination::SendMsg (std::shared_ptr msg, std::shared_ptr remote) - { - auto outboundTunnel = GetTunnelPool ()->GetNextOutboundTunnel (); - auto leases = remote->GetNonExpiredLeases (); - if (!leases.empty () && outboundTunnel) + { + auto remoteSession = GetRoutingSession (remote, true); + if (!remoteSession) + { + LogPrint (eLogError, "I2CP: Failed to create remote session"); + return false; + } + auto path = remoteSession->GetSharedRoutingPath (); + std::shared_ptr outboundTunnel; + std::shared_ptr remoteLease; + if (path) + { + if (!remoteSession->CleanupUnconfirmedTags ()) // no stuck tags + { + outboundTunnel = path->outboundTunnel; + remoteLease = path->remoteLease; + } + else + remoteSession->SetSharedRoutingPath (nullptr); + } + else + { + auto outboundTunnel = GetTunnelPool ()->GetNextOutboundTunnel (); + auto leases = remote->GetNonExpiredLeases (); + if (!leases.empty ()) + remoteLease = leases[rand () % leases.size ()]; + if (remoteLease && outboundTunnel) + remoteSession->SetSharedRoutingPath (std::make_shared ( + i2p::garlic::GarlicRoutingPath{outboundTunnel, remoteLease, 10000, 0, 0})); // 10 secs RTT + else + remoteSession->SetSharedRoutingPath (nullptr); + } + if (remoteLease && outboundTunnel) { std::vector msgs; - uint32_t i = rand () % leases.size (); - auto garlic = WrapMessage (remote, msg, true); + auto garlic = remoteSession->WrapSingleMessage (msg); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, - leases[i]->tunnelGateway, leases[i]->tunnelID, + remoteLease->tunnelGateway, remoteLease->tunnelID, garlic }); outboundTunnel->SendTunnelDataMsg (msgs); return true; - } + } else { if (outboundTunnel)