moved datagram destination and session to UDPConnection
Build Debian packages / bookworm (push) Failing after 13s
Build on FreeBSD / with UPnP (push) Failing after 3m28s
Build Debian packages / trixie (push) Failing after 9s
Build Debian packages / bullseye (push) Failing after 1m4s
Build containers / Building container for linux/386 (push) Failing after 30s
Build on Ubuntu / CMake with -DWITH_UPNP=ON (push) Failing after 3h11m1s
Build on Ubuntu / CMake with -DWITH_UPNP=OFF (push) Failing after 3h13m14s
Build containers / Building container for linux/amd64 (push) Failing after 4m29s
Build containers / Pushing merged manifest (push) Has been skipped
Build on Ubuntu / Make with USE_UPNP=no (push) Failing after 3h13m47s
Build on Windows / clang-x86_64 (push) Has been cancelled
Build on Windows / i686 (push) Has been cancelled
Build on Windows / ucrt-x86_64 (push) Has been cancelled
Build on Windows / x86_64 (push) Has been cancelled
Build on Windows / CMake i686 (push) Has been cancelled
Build on Windows / CMake ucrt-x86_64 (push) Has been cancelled
Build on Windows / CMake x86_64 (push) Has been cancelled
Build on Windows / XP (push) Has been cancelled
Build containers / Building container for linux/arm64 (push) Failing after 30s
Build containers / Building container for linux/arm/v7 (push) Failing after 29s
Build on Ubuntu / Make with USE_UPNP=yes (push) Failing after 3h11m2s
Build on OSX / Build on ARM64 (push) Has been cancelled
Build on OSX / Build on Intel x86_64 (push) Has been cancelled
Build on Windows / CMake clang-x86_64 (push) Has been cancelled

This commit is contained in:
orignal
2026-02-16 20:49:17 -05:00
parent 42f1396f23
commit 4ec9be557f
2 changed files with 54 additions and 62 deletions
+30 -34
View File
@@ -208,7 +208,7 @@ namespace client
options.Put (UDP_SESSION_FLAGS, UDP_SESSION_FLAG_RESET_PATH | UDP_SESSION_FLAG_ACK_REQUESTED);
auto session = GetDatagramSession ();
session->DropSharedRoutingPath ();
GetDatagramDestination ()->SendDatagram (session, nullptr, 0, 0, 0, &options);
m_Destination->SendDatagram (session, nullptr, 0, 0, 0, &options);
}
});
}
@@ -227,16 +227,27 @@ namespace client
m_UnackedDatagrams.erase (m_UnackedDatagrams.begin (), it);
}
std::shared_ptr<i2p::datagram::DatagramSession> UDPConnection::GetDatagramSession ()
{
auto session = m_LastDatagramSession.lock ();
if (!session && isIdentity)
{
session = m_Destination->GetSession (Identity);
m_LastDatagramSession = session;
}
return session;
}
UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
const boost::asio::ip::udp::endpoint& endpoint, const i2p::data::IdentHash& to,
uint16_t ourPort, uint16_t theirPort) :
UDPConnection (localDestination->GetService()),
m_Destination(localDestination->GetDatagramDestination()),
IPSocket(localDestination->GetService(), localEndpoint), Identity (to),
UDPConnection (localDestination->GetService(), localDestination->GetDatagramDestination()),
IPSocket(localDestination->GetService(), localEndpoint),
SendEndpoint(endpoint), LastActivity(i2p::util::GetMillisecondsSinceEpoch()),
LastRepliableDatagramTime (0), LocalPort(ourPort), RemotePort(theirPort)
{
SetIdentity (to);
Start ();
IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
IPSocket.non_blocking (true);
@@ -313,17 +324,6 @@ namespace client
LogPrint(eLogError, "UDPSession: ", ecode.message());
}
std::shared_ptr<i2p::datagram::DatagramSession> UDPSession::GetDatagramSession ()
{
auto session = m_LastDatagramSession.lock ();
if (!session)
{
session = m_Destination->GetSession (Identity);
m_LastDatagramSession = session;
}
return session;
}
I2PUDPServerTunnel::I2PUDPServerTunnel (const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
const boost::asio::ip::address& localAddress, const boost::asio::ip::udp::endpoint& forwardTo, uint16_t inPort, bool gzip) :
m_IsUniqueLocal (true), m_Name (name), m_LocalAddress (localAddress),
@@ -389,7 +389,7 @@ namespace client
const boost::asio::ip::udp::endpoint& localEndpoint,
std::shared_ptr<i2p::client::ClientDestination> localDestination,
uint16_t remotePort, bool gzip, i2p::datagram::DatagramVersion datagramVersion) :
UDPConnection (localDestination->GetService ()),
UDPConnection (localDestination->GetService (), localDestination->GetDatagramDestination ()),
m_Name (name), m_RemoteDest (remoteDest), m_LocalDest (localDestination), m_LocalEndpoint (localEndpoint),
m_ResolveThread (nullptr), m_LocalSocket (nullptr), RemotePort (remotePort),
m_LastPort (0), m_cancel_resolve (false), m_Gzip (gzip), m_DatagramVersion (datagramVersion),
@@ -414,6 +414,7 @@ namespace client
m_LocalSocket->non_blocking (true);
auto dgram = m_LocalDest->CreateDatagramDestination (m_Gzip, m_DatagramVersion);
m_Destination = dgram;
dgram->SetReceiver (std::bind (&I2PUDPClientTunnel::HandleRecvFromI2P, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4,
@@ -451,7 +452,6 @@ namespace client
delete m_ResolveThread;
m_ResolveThread = nullptr;
}
m_RemoteAddr = nullptr;
UDPConnection::Stop ();
}
@@ -472,7 +472,7 @@ namespace client
RecvFromLocal (); // Restart listener and continue work
return;
}
if (!m_RemoteAddr || !m_RemoteAddr->IsIdentHash ()) // TODO: handle B33
if (!isIdentity)
{
LogPrint (eLogWarning, "UDP Client: Remote endpoint not resolved yet");
RecvFromLocal ();
@@ -499,7 +499,7 @@ namespace client
}
// send off to remote i2p destination
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteAddr->identHash.ToBase32 (), ":", RemotePort);
LogPrint (eLogDebug, "UDP Client: Send ", transferred, " to ", Identity.ToBase32 (), ":", RemotePort);
auto session = GetDatagramSession ();
uint64_t repliableDatagramInterval = I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL;
if (m_RTT && m_RTT >= I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL && m_RTT < I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL*10) repliableDatagramInterval = m_RTT/10; // 10 - 100 ms
@@ -543,7 +543,7 @@ namespace client
numPackets++;
}
if (numPackets)
LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteAddr->identHash.ToBase32 ());
LogPrint (eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", Identity.ToBase32 ());
m_NextSendPacketNum += numPackets + 1;
m_LocalDest->GetDatagramDestination ()->FlushSendQueue (session);
@@ -565,7 +565,8 @@ namespace client
i2p::util::SetThreadName ("UDP Resolver");
LogPrint (eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest);
while (!(m_RemoteAddr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
std::shared_ptr<const Address> remoteAddr;
while (!(remoteAddr = context.GetAddressBook().GetAddress(m_RemoteDest)) && !m_cancel_resolve)
{
LogPrint (eLogWarning, "UDP Tunnel: Failed to lookup ", m_RemoteDest);
std::this_thread::sleep_for (std::chrono::seconds (1));
@@ -575,29 +576,24 @@ namespace client
LogPrint(eLogError, "UDP Tunnel: Lookup of ", m_RemoteDest, " was cancelled");
return;
}
if (!m_RemoteAddr)
if (!remoteAddr)
{
LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " not found");
return;
}
LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", m_RemoteAddr->identHash.ToBase32 ());
}
std::shared_ptr<i2p::datagram::DatagramSession> I2PUDPClientTunnel::GetDatagramSession ()
{
auto session = m_LastDatagramSession.lock ();
if (!session)
if (!remoteAddr->IsIdentHash ()) // TODO: handle B33
{
session = m_LocalDest->GetDatagramDestination ()->GetSession (m_RemoteAddr->identHash);
m_LastDatagramSession = session;
LogPrint (eLogError, "UDP Tunnel: ", m_RemoteDest, " resolved to invalid address type");
return;
}
return session;
LogPrint(eLogInfo, "UDP Tunnel: Resolved ", m_RemoteDest, " to ", remoteAddr->identHash.ToBase32 ());
SetIdentity (remoteAddr->identHash);
}
void I2PUDPClientTunnel::HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort,
const uint8_t * buf, size_t len, const i2p::util::Mapping * options)
{
if (m_RemoteAddr && from.GetIdentHash() == m_RemoteAddr->identHash)
if (isIdentity && from.GetIdentHash() == Identity)
{
if (options)
{
@@ -632,7 +628,7 @@ namespace client
// found convo
if (len > 0)
{
LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteAddr ? m_RemoteAddr->identHash.ToBase32 () : "");
LogPrint (eLogDebug, "UDP Client: Got ", len, "B from ", isIdentity ? Identity.ToBase32 () : "");
boost::system::error_code ec;
m_LocalSocket->send_to (boost::asio::buffer (buf, len), itr->second->first, 0, ec);
if (!ec)
+24 -28
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2025, The PurpleI2P Project
* Copyright (c) 2013-2026, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -32,40 +32,43 @@ namespace client
const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds
const uint64_t I2P_UDP_MAX_UNACKED_DATAGRAM_TIME = 8000; // in milliseconds
const size_t I2P_UDP_MAX_NUM_UNACKED_DATAGRAMS = 500;
/** max size for i2p udp */
const size_t I2P_UDP_MAX_MTU = 64*1024;
struct UDPConnection
struct UDPConnection
{
i2p::datagram::DatagramDestination * m_Destination;
std::weak_ptr<i2p::datagram::DatagramSession> m_LastDatagramSession;
i2p::data::IdentHash Identity;
bool isIdentity = false;
uint32_t m_NextSendPacketNum = 1, m_LastReceivedPacketNum = 0;
std::list<std::pair<uint32_t, uint64_t> > m_UnackedDatagrams; // list of sent but not acked repliable datagrams(seqn, timestamp) in ascending order
uint64_t m_RTT = 0; // milliseconds
boost::asio::deadline_timer m_AckTimer;
uint32_t m_AckTimerSeqn = 0;
bool m_IsSendingAllowed = true;
bool m_IsFirstPacket = true;
UDPConnection (boost::asio::io_context& service): m_AckTimer (service) {};
UDPConnection (boost::asio::io_context& service, i2p::datagram::DatagramDestination * destination):
m_Destination (destination), m_AckTimer (service) {};
void SetIdentity (const i2p::data::IdentHash& ident) { Identity = ident; isIdentity = true; };
virtual ~UDPConnection () { Stop (); };
virtual void Start () {};
virtual void Stop ();
void Acked (uint32_t seqn);
void ScheduleAckTimer (uint32_t seqn);
void DeleteExpiredUnackedDatagrams ();
virtual std::shared_ptr<i2p::datagram::DatagramSession> GetDatagramSession () = 0;
virtual i2p::datagram::DatagramDestination * GetDatagramDestination () const = 0;
std::shared_ptr<i2p::datagram::DatagramSession> GetDatagramSession ();
};
struct UDPSession: public UDPConnection // for server side
{
i2p::datagram::DatagramDestination * m_Destination;
std::weak_ptr<i2p::datagram::DatagramSession> m_LastDatagramSession;
boost::asio::ip::udp::socket IPSocket;
i2p::data::IdentHash Identity;
boost::asio::ip::udp::endpoint FromEndpoint;
boost::asio::ip::udp::endpoint SendEndpoint;
uint64_t LastActivity, LastRepliableDatagramTime; // milliseconds
@@ -74,15 +77,13 @@ namespace client
uint16_t RemotePort;
uint8_t m_Buffer[I2P_UDP_MAX_MTU];
UDPSession(boost::asio::ip::udp::endpoint localEndpoint,
const std::shared_ptr<i2p::client::ClientDestination> & localDestination,
const boost::asio::ip::udp::endpoint& remote, const i2p::data::IdentHash& ident,
uint16_t ourPort, uint16_t theirPort);
void HandleReceived(const boost::system::error_code & ecode, std::size_t len);
void Receive();
std::shared_ptr<i2p::datagram::DatagramSession> GetDatagramSession () override;
i2p::datagram::DatagramDestination * GetDatagramDestination () const override { return m_Destination; }
};
@@ -132,12 +133,12 @@ namespace client
private:
void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort,
void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort,
const uint8_t * buf, size_t len, const i2p::util::Mapping * options);
void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
UDPSessionPtr ObtainUDPSession (const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort);
uint32_t GetSessionIndex (uint16_t fromPort, uint16_t toPort) const { return ((uint32_t)fromPort << 16) + toPort; }
private:
bool m_IsUniqueLocal;
@@ -179,7 +180,7 @@ namespace client
m_LocalDest = dest;
}
const boost::asio::ip::udp::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; };
void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
private:
@@ -187,14 +188,11 @@ namespace client
typedef std::pair<boost::asio::ip::udp::endpoint, uint64_t> UDPConvo;
void RecvFromLocal ();
void HandleRecvFromLocal (const boost::system::error_code & e, std::size_t transferred);
void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort,
void HandleRecvFromI2P (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort,
const uint8_t * buf, size_t len, const i2p::util::Mapping * options);
void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void TryResolving ();
std::shared_ptr<i2p::datagram::DatagramSession> GetDatagramSession () override;
i2p::datagram::DatagramDestination * GetDatagramDestination () const override
{ return m_LocalDest ? m_LocalDest->GetDatagramDestination () : nullptr; }
private:
const std::string m_Name;
@@ -203,7 +201,6 @@ namespace client
const std::string m_RemoteDest;
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
const boost::asio::ip::udp::endpoint m_LocalEndpoint;
std::shared_ptr<const Address> m_RemoteAddr;
std::thread * m_ResolveThread;
std::unique_ptr<boost::asio::ip::udp::socket> m_LocalSocket;
boost::asio::ip::udp::endpoint m_RecvEndpoint;
@@ -213,9 +210,8 @@ namespace client
bool m_Gzip;
i2p::datagram::DatagramVersion m_DatagramVersion;
std::shared_ptr<UDPConvo> m_LastSession;
std::weak_ptr<i2p::datagram::DatagramSession> m_LastDatagramSession;
uint64_t m_LastRepliableDatagramTime; // millseconds
public:
bool isUpdated; // transient, used during reload only