forked from Mirrors/openclonk
Implement TCP Simultaneous Open for IPv6
parent
9a5103d02c
commit
99ef4ce853
|
@ -1022,14 +1022,7 @@ void C4Network2::OnPuncherConnect(C4NetIO::addr_t addr)
|
|||
C4Network2Client *pLocal = Clients.GetLocal();
|
||||
if (pLocal)
|
||||
{
|
||||
pLocal->AddAddr(C4Network2Address(maybe_v4, P_UDP), true);
|
||||
// If the outside port matches the inside port, there is no port translation and the
|
||||
// TCP address will probably work as well.
|
||||
if (addr.GetPort() == Config.Network.PortUDP && Config.Network.PortTCP > 0)
|
||||
{
|
||||
maybe_v4.SetPort(Config.Network.PortTCP);
|
||||
pLocal->AddAddr(C4Network2Address(maybe_v4, P_TCP), true);
|
||||
}
|
||||
pLocal->AddAddrFromPuncher(maybe_v4);
|
||||
// Do not ::Network.InvalidateReference(); yet, we're expecting an ID from the netpuncher
|
||||
}
|
||||
auto family = maybe_v4.GetFamily();
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "network/C4Network2Stats.h"
|
||||
#include "player/C4PlayerList.h"
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
// *** C4Network2Client
|
||||
|
||||
C4Network2Client::C4Network2Client(C4Client *pClient)
|
||||
|
@ -135,6 +138,17 @@ bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO)
|
|||
// save attempt
|
||||
AddrAttempts[iBestAddress]++; iNextConnAttempt = time(nullptr) + C4NetClientConnectInterval;
|
||||
auto addr = Addr[iBestAddress].getAddr();
|
||||
|
||||
// try TCP simultaneous open if the stars align right
|
||||
if (addr.GetFamily() == C4NetIO::addr_t::IPv6 && // address needs to be IPv6...
|
||||
!addr.IsLocal() && !addr.IsPrivate() && // ...global unicast...
|
||||
Addr[iBestAddress].getProtocol() == P_TCP && // ...TCP,
|
||||
!TcpSimOpenSocket && // there is no previous request,
|
||||
pParent->GetLocal()->getID() < getID()) // and make sure that only one client per pair initiates a request.
|
||||
{
|
||||
DoTCPSimultaneousOpen(pIO, C4Network2Address());
|
||||
}
|
||||
|
||||
std::set<int> interfaceIDs;
|
||||
if (addr.IsLocal())
|
||||
interfaceIDs = Network.Clients.GetLocal()->getInterfaceIDs();
|
||||
|
@ -152,6 +166,45 @@ bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool C4Network2Client::DoTCPSimultaneousOpen(class C4Network2IO *pIO, const C4Network2Address &addr)
|
||||
{
|
||||
if (!pIO->getNetIO(P_TCP)) return false;
|
||||
|
||||
// Did we already bind a socket?
|
||||
if (TcpSimOpenSocket)
|
||||
{
|
||||
LogSilentF("Network: connecting client %s on %s with TCP simultaneous open...", getName(), addr.getAddr().ToString().getData());
|
||||
return pIO->ConnectWithSocket(addr.getAddr(), addr.getProtocol(), pClient->getCore(), std::move(TcpSimOpenSocket));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No - bind one, inform peer, and schedule a connection attempt.
|
||||
auto NetIOTCP = dynamic_cast<C4NetIOTCP*>(pIO->getNetIO(P_TCP));
|
||||
auto bindAddr = pParent->GetLocal()->IPv6AddrFromPuncher;
|
||||
// We need to know an address that works.
|
||||
if (bindAddr.IsNull()) return false;
|
||||
bindAddr.SetPort(0);
|
||||
TcpSimOpenSocket = NetIOTCP->Bind(bindAddr);
|
||||
auto boundAddr = TcpSimOpenSocket->GetAddress();
|
||||
LogSilentF("Network: %s TCP simultaneous open request for client %s from %s...", addr.isIPNull() ? "initiating" : "responding to",
|
||||
getName(), boundAddr.ToString().getData());
|
||||
// Send address we bound to to the client.
|
||||
if (!SendMsg(MkC4NetIOPacket(PID_TCPSimOpen, C4PacketTCPSimOpen(pParent->GetLocal()->getID(), C4Network2Address(boundAddr, P_TCP)))))
|
||||
return false;
|
||||
if (!addr.isIPNull())
|
||||
{
|
||||
// We need to delay the connection attempt a bit. Unfortunately,
|
||||
// waiting for the next tick would usually take way too much time.
|
||||
// Instead, we block the main thread for a very short time and hope
|
||||
// that noone notices...
|
||||
int ping = getMsgConn()->getLag();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(std::min(ping / 2, 10)));
|
||||
DoTCPSimultaneousOpen(pIO, addr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool C4Network2Client::hasAddr(const C4Network2Address &addr) const
|
||||
{
|
||||
// Note that the host only knows its own address as 0.0.0.0, so if the real address is being added, that can't be sorted out.
|
||||
|
@ -166,6 +219,22 @@ void C4Network2Client::ClearAddr()
|
|||
iAddrCnt = 0;
|
||||
}
|
||||
|
||||
void C4Network2Client::AddAddrFromPuncher(const C4NetIO::addr_t &addr)
|
||||
{
|
||||
AddAddr(C4Network2Address(addr, P_UDP), true);
|
||||
// If the outside port matches the inside port, there is no port translation and the
|
||||
// TCP address will probably work as well.
|
||||
if (addr.GetPort() == Config.Network.PortUDP && Config.Network.PortTCP > 0)
|
||||
{
|
||||
auto tcpAddr = addr;
|
||||
tcpAddr.SetPort(Config.Network.PortTCP);
|
||||
AddAddr(C4Network2Address(tcpAddr, P_TCP), true);
|
||||
}
|
||||
// Save IPv6 address for TCP simultaneous connect.
|
||||
if (addr.GetFamily() == C4NetIO::addr_t::IPv6)
|
||||
IPv6AddrFromPuncher = addr;
|
||||
}
|
||||
|
||||
bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce)
|
||||
{
|
||||
// checks
|
||||
|
@ -505,6 +574,18 @@ void C4Network2ClientList::HandlePacket(char cStatus, const C4PacketBase *pBaseP
|
|||
}
|
||||
break;
|
||||
|
||||
case PID_TCPSimOpen:
|
||||
{
|
||||
GETPKT(C4PacketTCPSimOpen, rPkt)
|
||||
pClient = GetClientByID(rPkt.getClientID());
|
||||
if (pClient)
|
||||
{
|
||||
C4Network2Address addr = rPkt.getAddr();
|
||||
pClient->DoTCPSimultaneousOpen(pIO, addr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
#undef GETPKT
|
||||
|
@ -522,9 +603,11 @@ void C4Network2ClientList::DoConnectAttempts()
|
|||
// check interval
|
||||
time_t t; time(&t);
|
||||
for (C4Network2Client *pClient = pFirst; pClient; pClient = pClient->getNext())
|
||||
{
|
||||
if (!pClient->isLocal() && !pClient->isRemoved() && pClient->getNextConnAttempt() && pClient->getNextConnAttempt() <= t)
|
||||
// attempt connect
|
||||
pClient->DoConnectAttempt(pIO);
|
||||
}
|
||||
}
|
||||
|
||||
void C4Network2ClientList::ResetReady()
|
||||
|
@ -558,3 +641,11 @@ void C4PacketAddr::CompileFunc(StdCompiler *pComp)
|
|||
pComp->Value(mkNamingAdapt(addr, "Addr"));
|
||||
}
|
||||
|
||||
// *** C4PacketTCPSimOpen
|
||||
|
||||
void C4PacketTCPSimOpen::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(mkIntPackAdapt(ClientID), "ClientID", C4ClientIDUnknown));
|
||||
pComp->Value(mkNamingAdapt(addr, "Addr"));
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ protected:
|
|||
C4Network2Address Addr[C4ClientMaxAddr];
|
||||
int32_t AddrAttempts[C4ClientMaxAddr];
|
||||
int32_t iAddrCnt;
|
||||
C4NetIO::addr_t IPv6AddrFromPuncher;
|
||||
|
||||
// interface ids
|
||||
std::set<int> InterfaceIDs;
|
||||
|
@ -69,6 +70,7 @@ protected:
|
|||
// connections
|
||||
C4Network2IOConnection *pMsgConn, *pDataConn;
|
||||
time_t iNextConnAttempt;
|
||||
std::unique_ptr<C4NetIOTCP::Socket> TcpSimOpenSocket;
|
||||
|
||||
// part of client list
|
||||
C4Network2Client *pNext;
|
||||
|
@ -122,10 +124,12 @@ public:
|
|||
bool SendData(C4NetIOPacket rPkt) const;
|
||||
|
||||
bool DoConnectAttempt(class C4Network2IO *pIO);
|
||||
bool DoTCPSimultaneousOpen(class C4Network2IO *pIO, const C4Network2Address &addr);
|
||||
|
||||
// addresses
|
||||
bool hasAddr(const C4Network2Address &addr) const;
|
||||
void ClearAddr();
|
||||
void AddAddrFromPuncher(const C4NetIO::addr_t &addr);
|
||||
bool AddAddr(const C4Network2Address &addr, bool fAnnounce);
|
||||
void AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP);
|
||||
|
||||
|
@ -209,4 +213,23 @@ public:
|
|||
void CompileFunc(StdCompiler *pComp) override;
|
||||
};
|
||||
|
||||
class C4PacketTCPSimOpen : public C4PacketBase
|
||||
{
|
||||
public:
|
||||
C4PacketTCPSimOpen() = default;
|
||||
C4PacketTCPSimOpen(int32_t ClientID, const C4Network2Address &addr)
|
||||
: ClientID(ClientID), addr(addr)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
int32_t ClientID;
|
||||
C4Network2Address addr;
|
||||
|
||||
public:
|
||||
int32_t getClientID() const { return ClientID; }
|
||||
const C4Network2Address &getAddr() const { return addr; }
|
||||
|
||||
void CompileFunc(StdCompiler *pComp) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -231,6 +231,12 @@ C4NetIO *C4Network2IO::DataIO() // by both
|
|||
}
|
||||
|
||||
bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, const char *szPassword) // by main thread
|
||||
{
|
||||
return ConnectWithSocket(addr, eProt, nCCore, nullptr, szPassword);
|
||||
}
|
||||
|
||||
|
||||
bool C4Network2IO::ConnectWithSocket(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, std::unique_ptr<C4NetIOTCP::Socket> socket, const char *szPassword) // by main thread
|
||||
{
|
||||
// get network class
|
||||
C4NetIO *pNetIO = getNetIO(eProt);
|
||||
|
@ -244,6 +250,8 @@ bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol ePr
|
|||
C4Network2IOConnection *pConn = new C4Network2IOConnection();
|
||||
pConn->Set(pNetIO, eProt, paddr, addr, CS_Connect, szPassword, iConnID);
|
||||
pConn->SetCCore(nCCore);
|
||||
if (socket)
|
||||
pConn->SetSocket(std::move(socket));
|
||||
AddConnection(pConn);
|
||||
// connect
|
||||
if (!pConn->Connect())
|
||||
|
@ -1328,6 +1336,11 @@ void C4Network2IOConnection::Set(C4NetIO *pnNetClass, C4Network2IOProtocol enPro
|
|||
iTimestamp = time(nullptr); iPingTime = -1;
|
||||
}
|
||||
|
||||
void C4Network2IOConnection::SetSocket(std::unique_ptr<C4NetIOTCP::Socket> socket)
|
||||
{
|
||||
TcpSimOpenSocket = std::move(socket);
|
||||
}
|
||||
|
||||
void C4Network2IOConnection::SetRemoteID(uint32_t inRemoteID)
|
||||
{
|
||||
iRemoteID = inRemoteID;
|
||||
|
@ -1433,6 +1446,11 @@ void C4Network2IOConnection::SetCCore(const C4ClientCore &nCCore)
|
|||
bool C4Network2IOConnection::Connect()
|
||||
{
|
||||
if (!pNetClass) return false;
|
||||
if (TcpSimOpenSocket)
|
||||
{
|
||||
auto pNetTCP = dynamic_cast<C4NetIOTCP*>(pNetClass);
|
||||
return pNetTCP->Connect(ConnectAddr, std::move(TcpSimOpenSocket));
|
||||
}
|
||||
// try connect
|
||||
return pNetClass->Connect(ConnectAddr);
|
||||
}
|
||||
|
|
|
@ -118,6 +118,7 @@ public:
|
|||
|
||||
// connections
|
||||
bool Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, const char *szPassword = nullptr); // by main thread
|
||||
bool ConnectWithSocket(const C4NetIO::addr_t &addr, C4Network2IOProtocol eProt, const C4ClientCore &nCCore, std::unique_ptr<C4NetIOTCP::Socket> socket, const char *szPassword = nullptr); // by main thread
|
||||
void SetAcceptMode(bool fAcceptAll); // by main thread
|
||||
void SetExclusiveConnMode(bool fExclusiveConn); // by main thread
|
||||
int getConnectionCount(); // by main thread
|
||||
|
@ -223,6 +224,7 @@ protected:
|
|||
class C4NetIO *pNetClass{nullptr};
|
||||
C4Network2IOProtocol eProt;
|
||||
C4NetIO::addr_t PeerAddr, ConnectAddr;
|
||||
std::unique_ptr<C4NetIOTCP::Socket> TcpSimOpenSocket;
|
||||
|
||||
// status data
|
||||
C4Network2IOConnStatus Status;
|
||||
|
@ -293,6 +295,7 @@ public:
|
|||
protected:
|
||||
// called by C4Network2IO only
|
||||
void Set(C4NetIO *pnNetClass, C4Network2IOProtocol eProt, const C4NetIO::addr_t &nPeerAddr, const C4NetIO::addr_t &nConnectAddr, C4Network2IOConnStatus nStatus, const char *szPassword, uint32_t iID);
|
||||
void SetSocket(std::unique_ptr<C4NetIOTCP::Socket> socket);
|
||||
void SetRemoteID(uint32_t iRemoteID);
|
||||
void SetPeerAddr(const C4NetIO::addr_t &nPeerAddr);
|
||||
void OnPing();
|
||||
|
|
|
@ -84,6 +84,7 @@ const C4PktHandlingData PktHandlingData[] =
|
|||
|
||||
// C4Network2ClientList (main thread)
|
||||
{ PID_Addr, PC_Network, "Client Address", false, false, PH_C4Network2ClientList, PKT_UNPACK(C4PacketAddr) },
|
||||
{ PID_TCPSimOpen, PC_Network, "TCP simultaneous open req", false, false, PH_C4Network2ClientList, PKT_UNPACK(C4PacketTCPSimOpen) },
|
||||
|
||||
|
||||
// C4Network2ResList (network thread)
|
||||
|
|
|
@ -109,6 +109,9 @@ enum C4PacketType
|
|||
// activation request
|
||||
PID_ClientActReq = 0x13,
|
||||
|
||||
// request to perform TCP simultaneous open
|
||||
PID_TCPSimOpen = 0x14,
|
||||
|
||||
// all data a client needs to get started
|
||||
PID_JoinData = 0x15,
|
||||
|
||||
|
|
Loading…
Reference in New Issue