diff --git a/Garlic.cpp b/Garlic.cpp index 17740fae..d48e9d94 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); + } + else if (ts >= tags->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) + { + if (m_Owner) + m_Owner->RemoveDeliveryStatusSession (tags->msgID); + it = m_UnconfirmedTagsMsgs.erase (it); } - m_UnconfirmedTagsMsgs.erase (it); - delete tags; + else + it++; } } @@ -119,21 +125,29 @@ 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 ();) { - 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); + ret = true; } else it++; } - return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); - } + return ret; + } std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) { @@ -258,7 +272,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 @@ -617,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 6d25fd39..6a92b94a 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; @@ -97,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 () { @@ -123,7 +125,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; 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) diff --git a/Streaming.cpp b/Streaming.cpp index 2d3c92ce..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 (); @@ -66,6 +65,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 +220,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) @@ -294,8 +301,10 @@ namespace stream m_NumResendAttempts = 0; SendBuffer (); } - if (m_Status == eStreamStatusClosing) - Close (); // all outgoing messages have been sent + if (m_Status == eStreamStatusClosed) + Terminate (); + else if (m_Status == eStreamStatusClosing) + 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 +504,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 +583,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 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); diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md new file mode 100644 index 00000000..71f0b2bc --- /dev/null +++ b/docs/build_notes_android.md @@ -0,0 +1,40 @@ +Building on Android +=================== + +Pre-requesties +-------------- + +You need to install Android SDK, NDK and QT with android support. + +- [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. + +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. +```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. + + 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