diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index e7197f27..b57cf4cd 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -262,6 +262,10 @@ namespace client ReadSocksProxy (); // handle tunnels + // take the acceptors off first, a tunnel still in the config sets its own back + // while it is read, incoming streams wait in the queue meanwhile + for (auto& it: m_ServerTunnels) + it.second->DetachAcceptor (); // reset isUpdated for each tunnel VisitTunnels (false); // reload tunnels @@ -980,6 +984,8 @@ namespace client ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); ins.first->second->Start (); } + else + ins.first->second->Accept (); // still in the config, take the acceptor back ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); } diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 7ed7528e..b8fd4604 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -803,7 +803,7 @@ namespace client I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, uint16_t port, std::shared_ptr localDestination, uint16_t inport, bool gzip): - I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) + I2PService (localDestination), m_IsUniqueLocal(true), m_IsDefaultAcceptor (false), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) { m_PortDestination = localDestination->GetStreamingDestination (inport); if (!m_PortDestination) // default destination @@ -822,13 +822,22 @@ namespace client Accept (); } - void I2PServerTunnel::Stop () + void I2PServerTunnel::DetachAcceptor () { if (m_PortDestination) m_PortDestination->ResetAcceptor (); auto localDestination = GetLocalDestination (); - if (localDestination) + // the default acceptor may belong to another tunnel on the same destination + if (localDestination && m_IsDefaultAcceptor) + { localDestination->StopAcceptingStreams (); + m_IsDefaultAcceptor = false; + } + } + + void I2PServerTunnel::Stop () + { + DetachAcceptor (); if (m_Resolver) m_Resolver->cancel (); @@ -935,7 +944,10 @@ namespace client if (localDestination) { if (!localDestination->IsAcceptingStreams ()) // set it as default if not set yet + { localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1)); + m_IsDefaultAcceptor = true; + } } else LogPrint (eLogError, "I2PTunnel: Local destination not set for server tunnel"); diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 626fc0f2..c6aa3083 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -213,13 +213,15 @@ namespace client const char* GetName() const override { return m_Name.c_str (); } + void Accept (); + void DetachAcceptor (); // called before the tunnels are read again on reload + private: bool Resolve (std::shared_ptr stream); void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::results_type endpoints, std::shared_ptr stream); - void Accept (); void HandleAccept (std::shared_ptr stream); void Connect (std::shared_ptr stream); virtual std::shared_ptr CreateI2PConnection (std::shared_ptr stream); @@ -227,6 +229,7 @@ namespace client private: bool m_IsUniqueLocal; + bool m_IsDefaultAcceptor; // this tunnel is the one accepting on the destination std::string m_Name, m_Address; uint16_t m_Port; boost::asio::ip::tcp::endpoint m_Endpoint;