forked from Mirrors/openclonk
Merge branch 'ipv6'
commit
ef4f1d9231
|
@ -1254,6 +1254,7 @@ target_link_libraries(netpuncher
|
|||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(libmisc iphlpapi)
|
||||
target_link_libraries(openclonk ws2_32)
|
||||
target_link_libraries(openclonk-server ws2_32)
|
||||
target_link_libraries(c4group ws2_32)
|
||||
|
|
|
@ -743,8 +743,8 @@ IDS_NET_CLIENT_IGNORE=Ignorieren
|
|||
IDS_NET_CLIENT_IGNORE_DESC=%s ignorieren. Du kannst Nachrichten von diesem Client dann in der Lobby nicht mehr lesen.
|
||||
IDS_NET_CLIENT_INFO=Client-Informationen
|
||||
IDS_NET_CLIENT_INFO_ADDRESSES=Adressen:
|
||||
IDS_NET_CLIENT_INFO_CONNDATA= Daten: %s (%s:%d, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNECTIONS=Verbindungen: %s: %s (%s:%d, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNDATA= Daten: %s (%s, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNECTIONS=Verbindungen: %s: %s (%s, %d ms)
|
||||
IDS_NET_CLIENT_INFO_NOADDRESSES=Addressen: Keine
|
||||
IDS_NET_CLIENT_INFO_NOCONNECTIONS=Verbindungen: Nicht verbunden
|
||||
IDS_NET_CLIENT_INFO_UNKNOWNID=Unbekannte client ID #%d.
|
||||
|
@ -816,7 +816,7 @@ IDS_NET_NEWGAME=&Neues Spiel
|
|||
IDS_NET_NEWGAME_DESC=Startet ein neues Netzwerk- oder Internetspiel.
|
||||
IDS_NET_NODIRECTSTART=Netzwerkspieldaten können nicht direkt gestartet werden.
|
||||
IDS_NET_NODISCOVERY=Fehler bei der Suche nach Spielen
|
||||
IDS_NET_NODISCOVERY_DESC=Suche nach Spielen fehlgeschlagen: %s
|
||||
IDS_NET_NODISCOVERY_DESC=Suche nach Spielen im lokalen Netzwerk fehlgeschlagen: %s
|
||||
IDS_NET_NOFILEPUBLISH=Datei %s kann nicht ans Netzwerk übertragen werden!
|
||||
IDS_NET_NOHOSTCON=Konnte nicht mit Host %s verbinden.
|
||||
IDS_NET_NOJOIN=Beitritt nicht möglich
|
||||
|
|
|
@ -743,8 +743,8 @@ IDS_NET_CLIENT_IGNORE=Ignore
|
|||
IDS_NET_CLIENT_IGNORE_DESC=Ignores %s. You will not be able to see messages from this client.
|
||||
IDS_NET_CLIENT_INFO=Client info
|
||||
IDS_NET_CLIENT_INFO_ADDRESSES=Addresses:
|
||||
IDS_NET_CLIENT_INFO_CONNDATA= Data: %s (%s:%d, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNECTIONS=Connections: %s: %s (%s:%d, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNDATA= Data: %s (%s, %d ms)
|
||||
IDS_NET_CLIENT_INFO_CONNECTIONS=Connections: %s: %s (%s, %d ms)
|
||||
IDS_NET_CLIENT_INFO_NOADDRESSES=Addresses: none
|
||||
IDS_NET_CLIENT_INFO_NOCONNECTIONS=Connections: Not connected
|
||||
IDS_NET_CLIENT_INFO_UNKNOWNID=Unknown client ID #%d.
|
||||
|
@ -815,8 +815,8 @@ IDS_NET_MSSEARCH_DESC=Search masterserver games for keywords.
|
|||
IDS_NET_NEWGAME=&New game
|
||||
IDS_NET_NEWGAME_DESC=Create a new network or internet game.
|
||||
IDS_NET_NODIRECTSTART=Cannot start network game data directly.
|
||||
IDS_NET_NODISCOVERY=Search Error
|
||||
IDS_NET_NODISCOVERY_DESC=Search failed: %s
|
||||
IDS_NET_NODISCOVERY=Game Search Error
|
||||
IDS_NET_NODISCOVERY_DESC=Game search in local network failed: %s
|
||||
IDS_NET_NOFILEPUBLISH=File %s cannot be published on network!
|
||||
IDS_NET_NOHOSTCON=Could not connect to host %s.
|
||||
IDS_NET_NOJOIN=Cannot join game
|
||||
|
|
|
@ -920,8 +920,7 @@ void C4StartupNetDlg::UpdateList(bool fGotReference)
|
|||
C4NetIO::addr_t Discover;
|
||||
while (DiscoverClient.PopDiscover(Discover))
|
||||
{
|
||||
StdStrBuf Address;
|
||||
Address.Format("%s:%d", inet_ntoa(Discover.sin_addr), htons(Discover.sin_port));
|
||||
StdStrBuf Address(Discover.ToString());
|
||||
AddReferenceQuery(Address.getData(), C4StartupNetListEntry::NRQT_GameDiscovery);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,10 +60,26 @@ namespace std {
|
|||
};
|
||||
|
||||
template<>
|
||||
struct hash<::sockaddr_in> {
|
||||
size_t operator()(const ::sockaddr_in& addr) const {
|
||||
auto unpack = make_tuple(addr.sin_family, addr.sin_addr.s_addr, addr.sin_port);
|
||||
return hash<decltype(unpack)>()(unpack);
|
||||
struct hash<C4NetIO::addr_t> {
|
||||
size_t operator()(const C4NetIO::addr_t& addr) const {
|
||||
switch (addr.GetFamily())
|
||||
{
|
||||
case C4NetIO::HostAddress::IPv4:
|
||||
{
|
||||
sockaddr_in v4 = addr;
|
||||
auto unpack = make_tuple(v4.sin_family, v4.sin_addr.s_addr, v4.sin_port);
|
||||
return hash<decltype(unpack)>()(unpack);
|
||||
}
|
||||
case C4NetIO::HostAddress::IPv6:
|
||||
{
|
||||
sockaddr_in6 v6 = addr;
|
||||
auto unpack = make_tuple(v6.sin6_family, v6.sin6_port, v6.sin6_flowinfo, std::string((char*) v6.sin6_addr.s6_addr, 16), v6.sin6_scope_id);
|
||||
return hash<decltype(unpack)>()(unpack);
|
||||
}
|
||||
case C4NetIO::HostAddress::UnknownFamily:
|
||||
assert(!"Unexpected address family");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
#include "network/C4Network2Address.h"
|
||||
#include <sstream>
|
||||
|
||||
void C4NetpuncherID::CompileFunc(StdCompiler *pComp) {
|
||||
pComp->Value(mkNamingAdapt(v4, "IPv4", 0u));
|
||||
pComp->Value(mkNamingAdapt(v6, "IPv6", 0u));
|
||||
}
|
||||
|
||||
std::unique_ptr<C4NetpuncherPacket> C4NetpuncherPacket::Construct(const C4NetIOPacket& rpack) {
|
||||
if (!rpack.getPData()) return nullptr;
|
||||
try {
|
||||
|
@ -47,9 +52,7 @@ C4NetpuncherPacketCReq::C4NetpuncherPacketCReq(const C4NetIOPacket& rpack) {
|
|||
C4Network2Address parse_addr;
|
||||
CompileFromBuf<StdCompilerBinRead>(parse_addr, rpack.getPBuf());
|
||||
if (parse_addr.getProtocol() != P_UDP) throw P_UDP;
|
||||
addr.sin_addr.s_addr = parse_addr.getAddr().sin_addr.s_addr,
|
||||
addr.sin_family = parse_addr.getAddr().sin_family,
|
||||
addr.sin_port = parse_addr.getAddr().sin_port;
|
||||
addr = parse_addr.getAddr();
|
||||
}
|
||||
|
||||
StdBuf C4NetpuncherPacketCReq::PackInto() const {
|
||||
|
|
|
@ -27,7 +27,14 @@ enum C4NetpuncherPacketType {
|
|||
// extend this with exchanging ICE parameters, some day?
|
||||
};
|
||||
|
||||
typedef uint32_t C4NetpuncherID_t;
|
||||
struct C4NetpuncherID {
|
||||
typedef uint32_t value;
|
||||
|
||||
value v4 = 0, v6 = 0;
|
||||
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
bool operator==(const C4NetpuncherID& other) const { return v4 == other.v4 && v6 == other.v6; }
|
||||
};
|
||||
|
||||
class C4NetpuncherPacket {
|
||||
public:
|
||||
|
@ -38,7 +45,7 @@ public:
|
|||
C4NetIOPacket PackTo(const C4NetIO::addr_t&) const;
|
||||
protected:
|
||||
virtual StdBuf PackInto() const = 0;
|
||||
typedef C4NetpuncherID_t CID;
|
||||
typedef C4NetpuncherID::value CID;
|
||||
};
|
||||
|
||||
template<C4NetpuncherPacketType TYPE>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
class C4PuncherServer : public C4NetIOUDP, private C4NetIO::CBClass
|
||||
{
|
||||
public:
|
||||
typedef C4NetpuncherID_t CID;
|
||||
typedef C4NetpuncherID::value CID;
|
||||
C4PuncherServer() {
|
||||
C4NetIOUDP::SetCallback(this);
|
||||
rng = std::bind(std::uniform_int_distribution<CID>(1/*, max*/), std::ref(random_device));
|
||||
|
@ -48,7 +48,7 @@ private:
|
|||
peer_ids.emplace(AddrPeer, nid);
|
||||
peer_addrs.emplace(nid, AddrPeer);
|
||||
Send(C4NetpuncherPacketAssID(nid).PackTo(AddrPeer));
|
||||
printf("Punched %s:%d... #%u\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), nid);
|
||||
printf("Punched %s... #%u\n", AddrPeer.ToString().getData(), nid);
|
||||
return true;
|
||||
}
|
||||
virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO) {
|
||||
|
@ -63,12 +63,12 @@ private:
|
|||
virtual void OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason) {
|
||||
auto it = peer_ids.find(AddrPeer);
|
||||
if (it == peer_ids.end()) {
|
||||
printf("ERROR: closing connection for %s:%d: (%s) but no connection is known\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), szReason);
|
||||
printf("ERROR: closing connection for %s: (%s) but no connection is known\n", AddrPeer.ToString().getData(), szReason);
|
||||
return;
|
||||
}
|
||||
peer_addrs.erase(it->second);
|
||||
peer_ids.erase(it);
|
||||
printf("Stopped punching %s:%d: %s...\n", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port), szReason);
|
||||
printf("Stopped punching %s: %s...\n", AddrPeer.ToString().getData(), szReason);
|
||||
};
|
||||
} Puncher;
|
||||
|
||||
|
@ -96,7 +96,11 @@ int main(int argc, char * argv[])
|
|||
printf("Listening on port %d...\n", iPort);
|
||||
|
||||
// Execute forever
|
||||
Puncher.ExecuteUntil(-1);
|
||||
for (;;)
|
||||
{
|
||||
Puncher.ExecuteUntil(-1);
|
||||
fprintf(stderr, "ERROR: %s\n", Puncher.GetError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -65,9 +65,152 @@ public:
|
|||
|
||||
// *** constants / types
|
||||
static const int TO_INF; // = -1;
|
||||
static const uint16_t P_NONE; // = -1
|
||||
|
||||
typedef sockaddr_in addr_t;
|
||||
struct HostAddress
|
||||
{
|
||||
enum AddressFamily
|
||||
{
|
||||
IPv6 = AF_INET6,
|
||||
IPv4 = AF_INET,
|
||||
UnknownFamily = 0
|
||||
};
|
||||
enum SpecialAddress
|
||||
{
|
||||
Loopback, // IPv6 localhost (::1)
|
||||
Any, // IPv6 any-address (::)
|
||||
AnyIPv4 // IPv4 any-address (0.0.0.0)
|
||||
};
|
||||
|
||||
enum ToStringFlags
|
||||
{
|
||||
TSF_SkipZoneId = 1,
|
||||
TSF_SkipPort = 2
|
||||
};
|
||||
|
||||
HostAddress() { Clear(); }
|
||||
HostAddress(const HostAddress &other) { SetHost(other); }
|
||||
HostAddress(SpecialAddress addr) { SetHost(addr); }
|
||||
explicit HostAddress(uint32_t addr) { SetHost(addr); }
|
||||
HostAddress(const StdStrBuf &addr) { SetHost(addr); }
|
||||
HostAddress(const sockaddr *addr) { SetHost(addr); }
|
||||
|
||||
AddressFamily GetFamily() const;
|
||||
|
||||
void SetScopeId(int scopeId);
|
||||
int GetScopeId() const;
|
||||
|
||||
void Clear();
|
||||
void SetHost(const sockaddr *addr);
|
||||
void SetHost(const HostAddress &host);
|
||||
void SetHost(SpecialAddress host);
|
||||
void SetHost(const StdStrBuf &host, AddressFamily family = UnknownFamily);
|
||||
void SetHost(uint32_t host);
|
||||
|
||||
C4NetIO::HostAddress AsIPv6() const; // convert an IPv4 address to an IPv6-mapped IPv4 address
|
||||
C4NetIO::HostAddress AsIPv4() const; // try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible)
|
||||
|
||||
// General categories
|
||||
bool IsNull() const;
|
||||
bool IsMulticast() const;
|
||||
bool IsLoopback() const;
|
||||
bool IsLocal() const;
|
||||
// bool IsBroadcast() const;
|
||||
|
||||
StdStrBuf ToString(int flags = 0) const;
|
||||
|
||||
bool operator ==(const HostAddress &rhs) const;
|
||||
bool operator !=(const HostAddress &rhs) const { return !(*this == rhs); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
union
|
||||
{
|
||||
sockaddr gen;
|
||||
sockaddr_in v4;
|
||||
sockaddr_in6 v6;
|
||||
};
|
||||
};
|
||||
|
||||
struct EndpointAddress : public HostAddress // Host and port
|
||||
{
|
||||
static const uint16_t IPPORT_NONE = 0;
|
||||
|
||||
EndpointAddress() { Clear(); }
|
||||
EndpointAddress(const EndpointAddress &other) : HostAddress() { SetAddress(other); }
|
||||
EndpointAddress(const HostAddress &host, uint16_t port = IPPORT_NONE) : HostAddress(host) { SetPort(port); }
|
||||
EndpointAddress(HostAddress::SpecialAddress addr, uint16_t port = IPPORT_NONE) : HostAddress(addr) { SetPort(port); }
|
||||
explicit EndpointAddress(const StdStrBuf &addr) { SetAddress(addr); }
|
||||
|
||||
StdStrBuf ToString(int flags = 0) const;
|
||||
|
||||
void Clear();
|
||||
|
||||
void SetAddress(const sockaddr *addr);
|
||||
void SetAddress(const EndpointAddress &other);
|
||||
void SetAddress(HostAddress::SpecialAddress addr, uint16_t port = IPPORT_NONE);
|
||||
void SetAddress(const HostAddress &host, uint16_t port = IPPORT_NONE);
|
||||
void SetAddress(const StdStrBuf &addr, AddressFamily family = UnknownFamily);
|
||||
|
||||
HostAddress GetHost() const { return *this; } // HostAddress copy ctor slices off port information
|
||||
EndpointAddress AsIPv6() const; // convert an IPv4 address to an IPv6-mapped IPv4 address
|
||||
EndpointAddress AsIPv4() const; // try to convert an IPv6-mapped IPv4 address to an IPv4 address (returns unchanged address if not possible)
|
||||
|
||||
void SetPort(uint16_t port);
|
||||
void SetDefaultPort(uint16_t port); // set a port only if there is none
|
||||
uint16_t GetPort() const;
|
||||
|
||||
bool IsNull() const;
|
||||
bool IsNullHost() const { return HostAddress::IsNull(); }
|
||||
|
||||
// Pointer wrapper to be able to implicitly convert to sockaddr*
|
||||
class EndpointAddressPtr;
|
||||
const EndpointAddressPtr operator &() const;
|
||||
EndpointAddressPtr operator &();
|
||||
class EndpointAddressPtr
|
||||
{
|
||||
EndpointAddress * const p;
|
||||
friend EndpointAddressPtr EndpointAddress::operator &();
|
||||
friend const EndpointAddressPtr EndpointAddress::operator &() const;
|
||||
EndpointAddressPtr(EndpointAddress *p) : p(p) {}
|
||||
public:
|
||||
const EndpointAddress &operator *() const { return *p; }
|
||||
EndpointAddress &operator *() { return *p; }
|
||||
|
||||
const EndpointAddress &operator ->() const { return *p; }
|
||||
EndpointAddress &operator ->() { return *p; }
|
||||
|
||||
operator const EndpointAddress*() const { return p; }
|
||||
operator EndpointAddress*() { return p; }
|
||||
|
||||
operator const sockaddr*() const { return &p->gen; }
|
||||
operator sockaddr*() { return &p->gen; }
|
||||
|
||||
operator const sockaddr_in*() const { return &p->v4; }
|
||||
operator sockaddr_in*() { return &p->v4; }
|
||||
|
||||
operator const sockaddr_in6*() const { return &p->v6; }
|
||||
operator sockaddr_in6*() { return &p->v6; }
|
||||
};
|
||||
|
||||
bool operator ==(const EndpointAddress &rhs) const;
|
||||
bool operator !=(const EndpointAddress &rhs) const { return !(*this == rhs); }
|
||||
|
||||
// conversions
|
||||
operator sockaddr() const { return gen; }
|
||||
operator sockaddr_in() const { assert(gen.sa_family == AF_INET); return v4; }
|
||||
operator sockaddr_in6() const { assert(gen.sa_family == AF_INET6); return v6; }
|
||||
|
||||
// StdCompiler
|
||||
void CompileFunc(StdCompiler *comp);
|
||||
|
||||
private:
|
||||
bool SetAddressByString(const StdStrBuf &address, short family);
|
||||
|
||||
friend class EndpointAddressPtr;
|
||||
};
|
||||
typedef EndpointAddress addr_t;
|
||||
|
||||
static std::vector<HostAddress> GetLocalAddresses();
|
||||
|
||||
// callback class
|
||||
class CBClass
|
||||
|
@ -108,10 +251,8 @@ public:
|
|||
// *** interface
|
||||
|
||||
// * not multithreading safe
|
||||
virtual bool Init(uint16_t iPort = P_NONE) = 0;
|
||||
virtual bool InitBroadcast(addr_t *pBroadcastAddr) = 0;
|
||||
virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE) = 0;
|
||||
virtual bool Close() = 0;
|
||||
virtual bool CloseBroadcast() = 0;
|
||||
|
||||
virtual bool Execute(int iTimeout = -1, pollfd * = 0) = 0; // (for StdSchedulerProc)
|
||||
virtual bool IsNotify() { return true; }
|
||||
|
@ -129,6 +270,12 @@ public:
|
|||
virtual bool GetConnStatistic(const addr_t &addr, int *pIRate, int *pORate, int *pLoss) = 0;
|
||||
virtual void ClearStatistic() = 0;
|
||||
|
||||
protected:
|
||||
// virtual SOCKET CreateSocket() = 0;
|
||||
|
||||
// Makes IPv4 connections from an IPv6 socket work.
|
||||
bool EnableDualStack(SOCKET socket);
|
||||
|
||||
// *** errors
|
||||
protected:
|
||||
StdCopyStrBuf Error;
|
||||
|
@ -193,7 +340,7 @@ public:
|
|||
// *** interface
|
||||
|
||||
// * not multithreading safe
|
||||
virtual bool Init(uint16_t iPort = P_NONE);
|
||||
virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE);
|
||||
virtual bool InitBroadcast(addr_t *pBroadcastAddr);
|
||||
virtual bool Close();
|
||||
virtual bool CloseBroadcast();
|
||||
|
@ -352,7 +499,7 @@ public:
|
|||
C4NetIOSimpleUDP();
|
||||
virtual ~C4NetIOSimpleUDP();
|
||||
|
||||
virtual bool Init(uint16_t iPort = P_NONE);
|
||||
virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE);
|
||||
virtual bool InitBroadcast(addr_t *pBroadcastAddr);
|
||||
virtual bool Close();
|
||||
virtual bool CloseBroadcast();
|
||||
|
@ -395,7 +542,7 @@ private:
|
|||
#endif
|
||||
|
||||
// multicast
|
||||
addr_t MCAddr; ip_mreq MCGrpInfo;
|
||||
addr_t MCAddr; ipv6_mreq MCGrpInfo;
|
||||
bool fMCLoopback;
|
||||
|
||||
// multibind
|
||||
|
@ -440,7 +587,7 @@ public:
|
|||
|
||||
// *** interface
|
||||
|
||||
virtual bool Init(uint16_t iPort = P_NONE);
|
||||
virtual bool Init(uint16_t iPort = addr_t::IPPORT_NONE);
|
||||
virtual bool InitBroadcast(addr_t *pBroadcastAddr);
|
||||
virtual bool Close();
|
||||
virtual bool CloseBroadcast();
|
||||
|
@ -479,6 +626,7 @@ protected:
|
|||
};
|
||||
|
||||
// packet structures
|
||||
struct BinAddr;
|
||||
struct PacketHdr; struct TestPacket; struct ConnPacket; struct ConnOKPacket; struct AddAddrPacket;
|
||||
struct DataPacketHdr; struct CheckPacketHdr; struct ClosePacket;
|
||||
|
||||
|
@ -806,48 +954,9 @@ private:
|
|||
void EnlargeIO(int iBy);
|
||||
};
|
||||
|
||||
// helpers
|
||||
inline bool AddrEqual(const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2)
|
||||
{
|
||||
return addr1.sin_addr.s_addr == addr2.sin_addr.s_addr &&
|
||||
addr1.sin_family == addr2.sin_family &&
|
||||
addr1.sin_port == addr2.sin_port;
|
||||
}
|
||||
inline bool operator == (const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2) { return AddrEqual(addr1, addr2); }
|
||||
inline bool operator != (const C4NetIO::addr_t addr1, const C4NetIO::addr_t addr2) { return !AddrEqual(addr1, addr2); }
|
||||
|
||||
// there seems to be no standard way to get these numbers, so let's do it the dirty way...
|
||||
inline uint8_t &in_addr_b(in_addr &addr, int i)
|
||||
{
|
||||
assert(0 <= i && i < 4);
|
||||
return *(reinterpret_cast<uint8_t *>(&addr.s_addr) + i);
|
||||
}
|
||||
|
||||
inline void CompileFunc(in_addr &ip, StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(in_addr_b(ip, 0)); pComp->Separator(StdCompiler::SEP_PART);
|
||||
pComp->Value(in_addr_b(ip, 1)); pComp->Separator(StdCompiler::SEP_PART);
|
||||
pComp->Value(in_addr_b(ip, 2)); pComp->Separator(StdCompiler::SEP_PART);
|
||||
pComp->Value(in_addr_b(ip, 3));
|
||||
}
|
||||
|
||||
inline void CompileFunc(C4NetIO::addr_t &addr, StdCompiler *pComp)
|
||||
{
|
||||
pComp->Value(addr.sin_addr); pComp->Separator(StdCompiler::SEP_PART2);
|
||||
uint16_t iPort = htons(addr.sin_port);
|
||||
pComp->Value(iPort);
|
||||
addr.sin_port = htons(iPort);
|
||||
if (pComp->isCompiler())
|
||||
{
|
||||
addr.sin_family = AF_INET;
|
||||
ZeroMem(addr.sin_zero, sizeof(addr.sin_zero));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
bool AcquireWinSock();
|
||||
void ReleaseWinSock();
|
||||
#endif
|
||||
bool ResolveAddress(const char *szAddress, C4NetIO::addr_t *paddr, uint16_t iPort);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -148,7 +148,7 @@ C4Network2::C4Network2()
|
|||
fPausedForVote(false),
|
||||
iLastOwnVoting(0),
|
||||
fStreaming(false),
|
||||
NetpuncherGameID(0)
|
||||
NetpuncherGameID(C4NetpuncherID())
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ bool C4Network2::InitHost(bool fLobby)
|
|||
fChasing = false;
|
||||
fAllowJoin = false;
|
||||
iNextClientID = C4ClientIDStart;
|
||||
NetpuncherGameID = 0;
|
||||
NetpuncherGameID = C4NetpuncherID();
|
||||
NetpuncherAddr = ::Config.Network.PuncherAddress;
|
||||
// initialize client list
|
||||
Clients.Init(&Game.Clients, true);
|
||||
|
@ -247,7 +247,10 @@ C4Network2::InitResult C4Network2::InitClient(const C4Network2Reference &Ref, bo
|
|||
// copy addresses
|
||||
C4Network2Address Addrs[C4ClientMaxAddr];
|
||||
for (int i = 0; i < Ref.getAddrCnt(); i++)
|
||||
{
|
||||
Addrs[i] = Ref.getAddr(i);
|
||||
Addrs[i].getAddr().SetScopeId(Ref.GetSourceAddress().GetScopeId());
|
||||
}
|
||||
// Try to connect to host
|
||||
if (InitClient(Addrs, Ref.getAddrCnt(), HostCore, Password.getData()) == IR_Fatal)
|
||||
return IR_Fatal;
|
||||
|
@ -307,9 +310,25 @@ C4Network2::InitResult C4Network2::InitClient(const class C4Network2Address *pAd
|
|||
for (int i = 0; i < iAddrCount; i++)
|
||||
if (!pAddrs[i].isIPNull())
|
||||
{
|
||||
auto addr = pAddrs[i].getAddr();
|
||||
std::vector<C4NetIO::addr_t> addrs;
|
||||
if (addr.IsLocal())
|
||||
{
|
||||
// Local IPv6 addresses need a scope id.
|
||||
for (auto& id : Clients.GetLocal()->getInterfaceIDs())
|
||||
{
|
||||
addr.SetScopeId(id);
|
||||
addrs.push_back(addr);
|
||||
}
|
||||
}
|
||||
else
|
||||
addrs.push_back(addr);
|
||||
// connection
|
||||
if (!NetIO.Connect(pAddrs[i].getAddr(), pAddrs[i].getProtocol(), HostCore, szPassword))
|
||||
continue;
|
||||
int cnt = 0;
|
||||
for (auto& a : addrs)
|
||||
if (NetIO.Connect(a, pAddrs[i].getProtocol(), HostCore, szPassword))
|
||||
cnt++;
|
||||
if (cnt == 0) continue;
|
||||
// format for message
|
||||
if (strAddresses.getLength())
|
||||
strAddresses.Append(", ");
|
||||
|
@ -670,7 +689,7 @@ void C4Network2::Clear()
|
|||
delete pVoteDialog; pVoteDialog = nullptr;
|
||||
fPausedForVote = false;
|
||||
iLastOwnVoting = 0;
|
||||
NetpuncherGameID = 0;
|
||||
NetpuncherGameID = C4NetpuncherID();
|
||||
Votes.Clear();
|
||||
// don't clear fPasswordNeeded here, it's needed by InitClient
|
||||
}
|
||||
|
@ -888,7 +907,7 @@ void C4Network2::HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C
|
|||
if (pLobby) pLobby->HandlePacket(cStatus, pBasePkt, pClient);
|
||||
}
|
||||
|
||||
bool C4Network2::HandlePuncherPacket(C4NetpuncherPacket::uptr pkt)
|
||||
bool C4Network2::HandlePuncherPacket(C4NetpuncherPacket::uptr pkt, C4NetIO::HostAddress::AddressFamily family)
|
||||
{
|
||||
// TODO: is this all thread-safe?
|
||||
assert(pkt);
|
||||
|
@ -909,26 +928,48 @@ bool C4Network2::HandlePuncherPacket(C4NetpuncherPacket::uptr pkt)
|
|||
case PID_Puncher_AssID:
|
||||
if (isHost())
|
||||
{
|
||||
NetpuncherGameID = GETPKT(AssID)->GetID();
|
||||
getNetpuncherGameID(family) = GETPKT(AssID)->GetID();
|
||||
InvalidateReference();
|
||||
}
|
||||
else
|
||||
{
|
||||
// While we don't need the ID as a client, this nicely serves as the signal that we can start using the netpuncher
|
||||
if (Status.getState() == GS_Init && getNetpuncherGameID())
|
||||
NetIO.SendPuncherPacket(C4NetpuncherPacketSReq(getNetpuncherGameID()));
|
||||
if (Status.getState() == GS_Init && getNetpuncherGameID(family))
|
||||
NetIO.SendPuncherPacket(C4NetpuncherPacketSReq(getNetpuncherGameID(family)), family);
|
||||
}
|
||||
return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
C4NetpuncherID::value& C4Network2::getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family)
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case C4NetIO::HostAddress::IPv4: return NetpuncherGameID.v4;
|
||||
case C4NetIO::HostAddress::IPv6: return NetpuncherGameID.v6;
|
||||
case C4NetIO::HostAddress::UnknownFamily: assert(!"Unexpected address family");
|
||||
}
|
||||
// We need to return a valid reference to satisfy the compiler, even though the code here is unreachable.
|
||||
return NetpuncherGameID.v4;
|
||||
}
|
||||
|
||||
void C4Network2::InitPuncher()
|
||||
{
|
||||
// We have an internet connection, so let's punch the puncher server here in order to open an udp port
|
||||
C4NetIO::addr_t PuncherAddr;
|
||||
if (ResolveAddress(getNetpuncherAddr().getData(), &PuncherAddr, C4NetStdPortPuncher))
|
||||
NetIO.InitPuncher(PuncherAddr);
|
||||
PuncherAddr.SetAddress(getNetpuncherAddr(), C4NetIO::HostAddress::IPv4);
|
||||
if (!PuncherAddr.IsNull())
|
||||
{
|
||||
PuncherAddr.SetDefaultPort(C4NetStdPortPuncher);
|
||||
NetIO.InitPuncher(PuncherAddr);
|
||||
}
|
||||
PuncherAddr.SetAddress(getNetpuncherAddr(), C4NetIO::HostAddress::IPv6);
|
||||
if (!PuncherAddr.IsNull())
|
||||
{
|
||||
PuncherAddr.SetDefaultPort(C4NetStdPortPuncher);
|
||||
NetIO.InitPuncher(PuncherAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void C4Network2::OnGameSynchronized()
|
||||
|
@ -1043,18 +1084,16 @@ void C4Network2::DrawStatus(C4TargetFacet &cgo)
|
|||
// connections
|
||||
if (pClient->isConnected())
|
||||
{
|
||||
Stat.AppendFormat( "| Connections: %s: %s (%s:%d p%d l%d)",
|
||||
Stat.AppendFormat( "| Connections: %s: %s (%s p%d l%d)",
|
||||
pClient->getMsgConn() == pClient->getDataConn() ? "Msg/Data" : "Msg",
|
||||
NetIO.getNetIOName(pClient->getMsgConn()->getNetClass()),
|
||||
inet_ntoa(pClient->getMsgConn()->getPeerAddr().sin_addr),
|
||||
htons(pClient->getMsgConn()->getPeerAddr().sin_port),
|
||||
pClient->getMsgConn()->getPeerAddr().ToString().getData(),
|
||||
pClient->getMsgConn()->getPingTime(),
|
||||
pClient->getMsgConn()->getPacketLoss());
|
||||
if (pClient->getMsgConn() != pClient->getDataConn())
|
||||
Stat.AppendFormat( ", Data: %s (%s:%d p%d l%d)",
|
||||
NetIO.getNetIOName(pClient->getDataConn()->getNetClass()),
|
||||
inet_ntoa(pClient->getDataConn()->getPeerAddr().sin_addr),
|
||||
htons(pClient->getDataConn()->getPeerAddr().sin_port),
|
||||
pClient->getDataConn()->getPeerAddr().ToString().getData(),
|
||||
pClient->getDataConn()->getPingTime(),
|
||||
pClient->getDataConn()->getPacketLoss());
|
||||
}
|
||||
|
@ -1183,7 +1222,7 @@ void C4Network2::HandleConn(const C4PacketConn &Pkt, C4Network2IOConnection *pCo
|
|||
else
|
||||
{
|
||||
// log & close
|
||||
LogSilentF("Network: connection by %s (%s:%d) blocked: %s", CCore.getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), reply.getData());
|
||||
LogSilentF("Network: connection by %s (%s) blocked: %s", CCore.getName(), pConn->getPeerAddr().ToString().getData(), reply.getData());
|
||||
pConn->Close();
|
||||
}
|
||||
}
|
||||
|
@ -1197,9 +1236,6 @@ bool C4Network2::CheckConn(const C4ClientCore &CCore, C4Network2IOConnection *pC
|
|||
// check core
|
||||
if (CCore.getDiffLevel(pClient->getCore()) > C4ClientCoreDL_IDMatch)
|
||||
{ *szReply = "wrong client core"; return false; }
|
||||
// check address
|
||||
if (pClient->isConnected() && pClient->getMsgConn()->getPeerAddr().sin_addr.s_addr != pConn->getPeerAddr().sin_addr.s_addr)
|
||||
{ *szReply = "wrong address"; return false; }
|
||||
// accept
|
||||
return true;
|
||||
}
|
||||
|
@ -1277,7 +1313,7 @@ void C4Network2::HandleConnRe(const C4PacketConnRe &Pkt, C4Network2IOConnection
|
|||
// wrong password?
|
||||
fWrongPassword = Pkt.isPasswordWrong();
|
||||
// show message
|
||||
LogSilentF("Network: connection to %s (%s:%d) refused: %s", pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), Pkt.getMsg());
|
||||
LogSilentF("Network: connection to %s (%s) refused: %s", pClient->getName(), pConn->getPeerAddr().ToString().getData(), Pkt.getMsg());
|
||||
// close connection
|
||||
pConn->Close();
|
||||
return;
|
||||
|
@ -1302,7 +1338,7 @@ void C4Network2::HandleConnRe(const C4PacketConnRe &Pkt, C4Network2IOConnection
|
|||
if (pConn->getNetClass() == NetIO.DataIO()) pClient->SetDataConn(pConn);
|
||||
|
||||
// add peer connect address to client address list
|
||||
if (pConn->getConnectAddr().sin_addr.s_addr)
|
||||
if (!pConn->getConnectAddr().IsNull())
|
||||
{
|
||||
C4Network2Address Addr(pConn->getConnectAddr(), pConn->getProtocol());
|
||||
pClient->AddAddr(Addr, Status.getState() != GS_Init);
|
||||
|
@ -1432,8 +1468,8 @@ void C4Network2::HandleJoinData(const C4PacketJoinData &rPkt)
|
|||
void C4Network2::OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pConn, const char *szMsg, bool fFirstConnection)
|
||||
{
|
||||
// log
|
||||
LogSilentF("Network: %s %s connected (%s:%d/%s) (%s)", pClient->isHost() ? "host" : "client",
|
||||
pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port),
|
||||
LogSilentF("Network: %s %s connected (%s/%s) (%s)", pClient->isHost() ? "host" : "client",
|
||||
pClient->getName(), pConn->getPeerAddr().ToString().getData(),
|
||||
NetIO.getNetIOName(pConn->getNetClass()), szMsg ? szMsg : "");
|
||||
|
||||
// first connection for this peer? call special handler
|
||||
|
@ -1442,8 +1478,8 @@ void C4Network2::OnConnect(C4Network2Client *pClient, C4Network2IOConnection *pC
|
|||
|
||||
void C4Network2::OnConnectFail(C4Network2IOConnection *pConn)
|
||||
{
|
||||
LogSilentF("Network: %s connection to %s:%d failed!", NetIO.getNetIOName(pConn->getNetClass()),
|
||||
inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port));
|
||||
LogSilentF("Network: %s connection to %s failed!", NetIO.getNetIOName(pConn->getNetClass()),
|
||||
pConn->getPeerAddr().ToString().getData());
|
||||
|
||||
// maybe client connection failure
|
||||
// (happens if the connection is not fully accepted and the client disconnects.
|
||||
|
@ -1455,8 +1491,8 @@ void C4Network2::OnConnectFail(C4Network2IOConnection *pConn)
|
|||
|
||||
void C4Network2::OnDisconnect(C4Network2Client *pClient, C4Network2IOConnection *pConn)
|
||||
{
|
||||
LogSilentF("Network: %s connection to %s (%s:%d) lost!", NetIO.getNetIOName(pConn->getNetClass()),
|
||||
pClient->getName(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port));
|
||||
LogSilentF("Network: %s connection to %s (%s) lost!", NetIO.getNetIOName(pConn->getNetClass()),
|
||||
pClient->getName(), pConn->getPeerAddr().ToString().getData());
|
||||
|
||||
// connection lost?
|
||||
if (!pClient->isConnected())
|
||||
|
|
|
@ -194,7 +194,7 @@ protected:
|
|||
unsigned int iCurrentStreamAmount, iCurrentStreamPosition;
|
||||
|
||||
// puncher
|
||||
C4NetpuncherID_t NetpuncherGameID;
|
||||
C4NetpuncherID NetpuncherGameID;
|
||||
StdCopyStrBuf NetpuncherAddr;
|
||||
|
||||
public:
|
||||
|
@ -257,7 +257,7 @@ public:
|
|||
void OnDisconn(C4Network2IOConnection *pConn);
|
||||
void HandlePacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
|
||||
void HandleLobbyPacket(char cStatus, const C4PacketBase *pBasePkt, C4Network2IOConnection *pConn);
|
||||
bool HandlePuncherPacket(C4NetpuncherPacket::uptr);
|
||||
bool HandlePuncherPacket(C4NetpuncherPacket::uptr, C4NetIO::HostAddress::AddressFamily family);
|
||||
|
||||
// runtime join stuff
|
||||
void OnGameSynchronized();
|
||||
|
@ -303,7 +303,8 @@ public:
|
|||
bool StopStreaming();
|
||||
|
||||
// netpuncher
|
||||
C4NetpuncherID_t getNetpuncherGameID() const { return NetpuncherGameID; }
|
||||
C4NetpuncherID::value& getNetpuncherGameID(C4NetIO::HostAddress::AddressFamily family);
|
||||
C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; };
|
||||
StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -31,8 +31,7 @@ void C4Network2Address::CompileFunc(StdCompiler *pComp)
|
|||
// Clear
|
||||
if (pComp->isCompiler())
|
||||
{
|
||||
ZeroMem(&addr, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.Clear();
|
||||
}
|
||||
|
||||
// Write protocol
|
||||
|
@ -41,34 +40,27 @@ void C4Network2Address::CompileFunc(StdCompiler *pComp)
|
|||
{ "UDP", P_UDP },
|
||||
{ "TCP", P_TCP },
|
||||
|
||||
{ nullptr, P_NONE },
|
||||
{ nullptr, P_NONE },
|
||||
};
|
||||
pComp->Value(mkEnumAdaptT<uint8_t>(eProtocol, Protocols));
|
||||
pComp->Separator(StdCompiler::SEP_PART2); // ':'
|
||||
|
||||
// Write IP (no IP = 0.0.0.0)
|
||||
in_addr zero; zero.s_addr = INADDR_ANY;
|
||||
pComp->Value(mkDefaultAdapt(addr.sin_addr, zero));
|
||||
pComp->Separator(StdCompiler::SEP_PART2); // ':'
|
||||
|
||||
// Write port
|
||||
uint16_t iPort = htons(addr.sin_port);
|
||||
pComp->Value(iPort);
|
||||
addr.sin_port = htons(iPort);
|
||||
pComp->Value(mkDefaultAdapt(addr, C4NetIO::addr_t()));
|
||||
}
|
||||
|
||||
StdStrBuf C4Network2Address::toString() const
|
||||
{
|
||||
switch (eProtocol)
|
||||
{
|
||||
case P_UDP: return FormatString("UDP:%s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port));
|
||||
case P_TCP: return FormatString("TCP:%s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port));
|
||||
case P_UDP: return FormatString("UDP:%s", addr.ToString().getData());
|
||||
case P_TCP: return FormatString("TCP:%s", addr.ToString().getData());
|
||||
default: return StdStrBuf("INVALID");
|
||||
}
|
||||
}
|
||||
|
||||
bool C4Network2Address::operator == (const C4Network2Address &addr2) const
|
||||
{
|
||||
return eProtocol == addr2.getProtocol() && AddrEqual(addr, addr2.getAddr());
|
||||
return eProtocol == addr2.getProtocol() && addr == addr2.getAddr();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class C4Network2Address
|
|||
public:
|
||||
C4Network2Address()
|
||||
: eProtocol(P_NONE)
|
||||
{ ZeroMem(&addr, sizeof(addr)); }
|
||||
{ }
|
||||
|
||||
C4Network2Address(C4NetIO::addr_t addr, C4Network2IOProtocol eProtocol)
|
||||
: addr(addr), eProtocol(eProtocol)
|
||||
|
@ -45,16 +45,18 @@ protected:
|
|||
|
||||
public:
|
||||
const C4NetIO::addr_t &getAddr() const { return addr; }
|
||||
in_addr getIPAddr() const { return addr.sin_addr; }
|
||||
bool isIPNull() const { return !addr.sin_addr.s_addr; }
|
||||
uint16_t getPort() const { return htons(addr.sin_port); }
|
||||
C4NetIO::addr_t &getAddr() { return addr; }
|
||||
//in_addr getIPAddr() const { return addr.sin_addr; }
|
||||
bool isIPNull() const { return addr.IsNull(); }
|
||||
uint16_t getPort() const { return addr.GetPort(); }
|
||||
C4Network2IOProtocol getProtocol() const { return eProtocol; }
|
||||
|
||||
StdStrBuf toString() const;
|
||||
|
||||
void SetAddr(C4NetIO::addr_t naddr) { addr = naddr; }
|
||||
void SetIP(in_addr ip) { addr.sin_addr = ip; }
|
||||
void SetPort(uint16_t iPort) { addr.sin_port = htons(iPort); }
|
||||
//void SetIP(in_addr ip) { addr.SetAddress(ip); }
|
||||
void SetIP(C4NetIO::addr_t ip) { addr.SetAddress(ip); }
|
||||
void SetPort(uint16_t iPort) { addr.SetPort(iPort); }
|
||||
void SetProtocol(C4Network2IOProtocol enProtocol) { eProtocol = enProtocol; }
|
||||
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
|
|
|
@ -25,13 +25,6 @@
|
|||
#include "game/C4Game.h"
|
||||
#include "player/C4PlayerList.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
// *** C4Network2Client
|
||||
|
||||
C4Network2Client::C4Network2Client(C4Client *pClient)
|
||||
|
@ -144,10 +137,22 @@ bool C4Network2Client::DoConnectAttempt(C4Network2IO *pIO)
|
|||
{ iNextConnAttempt = time(nullptr) + 10; return true; }
|
||||
// save attempt
|
||||
AddrAttempts[iBestAddress]++; iNextConnAttempt = time(nullptr) + C4NetClientConnectInterval;
|
||||
// log
|
||||
LogSilentF("Network: connecting client %s on %s...", getName(), Addr[iBestAddress].toString().getData());
|
||||
// connect
|
||||
return pIO->Connect(Addr[iBestAddress].getAddr(), Addr[iBestAddress].getProtocol(), pClient->getCore());
|
||||
auto addr = Addr[iBestAddress].getAddr();
|
||||
std::set<int> interfaceIDs;
|
||||
if (addr.IsLocal())
|
||||
interfaceIDs = Network.Clients.GetLocal()->getInterfaceIDs();
|
||||
else
|
||||
interfaceIDs = {0};
|
||||
for (auto id : interfaceIDs)
|
||||
{
|
||||
addr.SetScopeId(id);
|
||||
// log
|
||||
LogSilentF("Network: connecting client %s on %s...", getName(), addr.ToString().getData());
|
||||
// connect
|
||||
if (pIO->Connect(addr, Addr[iBestAddress].getProtocol(), pClient->getCore()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool C4Network2Client::hasAddr(const C4Network2Address &addr) const
|
||||
|
@ -184,70 +189,24 @@ bool C4Network2Client::AddAddr(const C4Network2Address &addr, bool fAnnounce)
|
|||
|
||||
void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP)
|
||||
{
|
||||
// set up address struct
|
||||
sockaddr_in addr; ZeroMem(&addr, sizeof addr);
|
||||
addr.sin_family = AF_INET;
|
||||
C4NetIO::addr_t addr;
|
||||
|
||||
// get local address(es)
|
||||
in_addr **ppAddr = nullptr;
|
||||
#ifdef HAVE_WINSOCK
|
||||
bool fGotWinSock = AcquireWinSock();
|
||||
if (fGotWinSock)
|
||||
for (auto& ha : C4NetIO::GetLocalAddresses())
|
||||
{
|
||||
// get local host name
|
||||
char szLocalHostName[128+1]; *szLocalHostName = '\0';
|
||||
::gethostname(szLocalHostName, 128);
|
||||
// get hostent-struct
|
||||
hostent *ph = ::gethostbyname(szLocalHostName);
|
||||
// check type, get addr list
|
||||
if (ph)
|
||||
addr.SetAddress(ha);
|
||||
if (iPortTCP)
|
||||
{
|
||||
if (ph->h_addrtype != AF_INET)
|
||||
ph = nullptr;
|
||||
else
|
||||
ppAddr = reinterpret_cast<in_addr **>(ph->h_addr_list);
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::vector<in_addr*> addr_vec;
|
||||
struct ifaddrs* addrs;
|
||||
getifaddrs(&addrs);
|
||||
for(struct ifaddrs* addr = addrs; addr != nullptr; addr = addr->ifa_next)
|
||||
{
|
||||
struct sockaddr* ad = addr->ifa_addr;
|
||||
if(ad == nullptr) continue;
|
||||
|
||||
if(ad->sa_family == AF_INET && (~addr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4 devices
|
||||
addr_vec.push_back(&reinterpret_cast<sockaddr_in*>(ad)->sin_addr);
|
||||
}
|
||||
|
||||
addr_vec.push_back(nullptr);
|
||||
ppAddr = &addr_vec[0];
|
||||
#endif
|
||||
|
||||
// add address(es)
|
||||
for (;;)
|
||||
{
|
||||
if (iPortTCP >= 0)
|
||||
{
|
||||
addr.sin_port = htons(iPortTCP);
|
||||
addr.SetPort(iPortTCP);
|
||||
AddAddr(C4Network2Address(addr, P_TCP), false);
|
||||
}
|
||||
if (iPortUDP >= 0)
|
||||
if (iPortUDP)
|
||||
{
|
||||
addr.sin_port = htons(iPortUDP);
|
||||
addr.SetPort(iPortUDP);
|
||||
AddAddr(C4Network2Address(addr, P_UDP), false);
|
||||
}
|
||||
// get next
|
||||
if (!ppAddr || !*ppAddr) break;
|
||||
addr.sin_addr = **ppAddr++;
|
||||
if (addr.GetScopeId())
|
||||
InterfaceIDs.insert(addr.GetScopeId());
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
if (fGotWinSock) ReleaseWinSock();
|
||||
#else
|
||||
if(addrs) freeifaddrs(addrs);
|
||||
#endif
|
||||
}
|
||||
|
||||
void C4Network2Client::SendAddresses(C4Network2IOConnection *pConn)
|
||||
|
@ -255,7 +214,11 @@ void C4Network2Client::SendAddresses(C4Network2IOConnection *pConn)
|
|||
// send all addresses
|
||||
for (int32_t i = 0; i < iAddrCnt; i++)
|
||||
{
|
||||
C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), Addr[i]));
|
||||
if (Addr[i].getAddr().GetScopeId() && (!pConn || pConn->getPeerAddr().GetScopeId() != Addr[i].getAddr().GetScopeId()))
|
||||
continue;
|
||||
C4Network2Address addr(Addr[i]);
|
||||
addr.getAddr().SetScopeId(0);
|
||||
C4NetIOPacket Pkt = MkC4NetIOPacket(PID_Addr, C4PacketAddr(getID(), addr));
|
||||
if (pConn)
|
||||
pConn->Send(Pkt);
|
||||
else
|
||||
|
@ -534,7 +497,9 @@ void C4Network2ClientList::HandlePacket(char cStatus, const C4PacketBase *pBaseP
|
|||
C4Network2Address addr = rPkt.getAddr();
|
||||
// IP zero? Set to IP from where the packet came
|
||||
if (addr.isIPNull())
|
||||
addr.SetIP(pConn->getPeerAddr().sin_addr);
|
||||
{
|
||||
addr.SetIP(pConn->getPeerAddr());
|
||||
}
|
||||
// add (no announce)
|
||||
if (pClient->AddAddr(addr, true))
|
||||
// new address? Try to connect
|
||||
|
|
|
@ -57,6 +57,9 @@ protected:
|
|||
int32_t AddrAttempts[C4ClientMaxAddr];
|
||||
int32_t iAddrCnt;
|
||||
|
||||
// interface ids
|
||||
std::set<int> InterfaceIDs;
|
||||
|
||||
// status
|
||||
C4Network2ClientStatus eStatus;
|
||||
|
||||
|
@ -88,6 +91,8 @@ public:
|
|||
int32_t getAddrCnt() const { return iAddrCnt; }
|
||||
const C4Network2Address &getAddr(int32_t i) const { return Addr[i]; }
|
||||
|
||||
const std::set<int> &getInterfaceIDs() const { return InterfaceIDs; }
|
||||
|
||||
C4Network2ClientStatus getStatus() const { return eStatus; }
|
||||
bool hasJoinData() const { return getStatus() != NCS_Joining; }
|
||||
bool isChasing() const { return getStatus() == NCS_Chasing; }
|
||||
|
|
|
@ -96,14 +96,12 @@ void C4Network2ClientDlg::UpdateText()
|
|||
AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNECTIONS"),
|
||||
pNetClient->getMsgConn() == pNetClient->getDataConn() ? "Msg/Data" : "Msg",
|
||||
::Network.NetIO.getNetIOName(pNetClient->getMsgConn()->getNetClass()),
|
||||
inet_ntoa(pNetClient->getMsgConn()->getPeerAddr().sin_addr),
|
||||
htons(pNetClient->getMsgConn()->getPeerAddr().sin_port),
|
||||
pNetClient->getMsgConn()->getPeerAddr().ToString().getData(),
|
||||
pNetClient->getMsgConn()->getPingTime());
|
||||
if (pNetClient->getMsgConn() != pNetClient->getDataConn())
|
||||
AddLineFmt(LoadResStr("IDS_NET_CLIENT_INFO_CONNDATA"),
|
||||
::Network.NetIO.getNetIOName(pNetClient->getDataConn()->getNetClass()),
|
||||
inet_ntoa(pNetClient->getDataConn()->getPeerAddr().sin_addr),
|
||||
htons(pNetClient->getDataConn()->getPeerAddr().sin_port),
|
||||
pNetClient->getDataConn()->getPeerAddr().ToString().getData(),
|
||||
pNetClient->getDataConn()->getPingTime());
|
||||
}
|
||||
else
|
||||
|
@ -386,11 +384,10 @@ void C4Network2ClientListBox::ConnectionListItem::Update()
|
|||
else
|
||||
szConnType = "Data";
|
||||
// display info
|
||||
pDesc->SetText(FormatString("%s: %s (%s:%d l%d)",
|
||||
pDesc->SetText(FormatString("%s: %s (%s l%d)",
|
||||
szConnType,
|
||||
::Network.NetIO.getNetIOName(pConn->getNetClass()),
|
||||
inet_ntoa(pConn->getPeerAddr().sin_addr),
|
||||
htons(pConn->getPeerAddr().sin_port),
|
||||
pConn->getPeerAddr().ToString().getData(),
|
||||
pConn->getPacketLoss()).getData());
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,17 @@
|
|||
#include "network/C4Network2Discover.h"
|
||||
|
||||
// *** C4Network2IODiscover
|
||||
//
|
||||
// Quick multicast discovery guide by Luchs:
|
||||
//
|
||||
// All engines in network mode join a multicast group (defined by C4NetDiscoveryAddress).
|
||||
//
|
||||
// Engines searching for a game ("client") send a single byte c = 3 to that multicast group. This
|
||||
// happens while on the network list on each refresh.
|
||||
//
|
||||
// Engines hosting a game (when going into the lobby) send a byte c = 4 plus their reference server
|
||||
// port to the multicast group. Additionally, they listen for the c = 3 bytes and will reply with
|
||||
// another multicast answer.
|
||||
|
||||
struct C4Network2IODiscoverReply
|
||||
{
|
||||
|
@ -41,10 +52,8 @@ bool C4Network2IODiscover::Init(uint16_t iPort)
|
|||
// Set callback
|
||||
C4NetIOSimpleUDP::SetCallback(this);
|
||||
// Build broadcast address
|
||||
DiscoveryAddr.sin_addr.s_addr = C4NetDiscoveryAddress;
|
||||
DiscoveryAddr.sin_port = htons(iPort);
|
||||
DiscoveryAddr.sin_family = AF_INET;
|
||||
ZeroMem(DiscoveryAddr.sin_zero, sizeof(DiscoveryAddr.sin_zero));
|
||||
DiscoveryAddr.SetAddress(C4NetDiscoveryAddress);
|
||||
DiscoveryAddr.SetPort(iPort);
|
||||
// Initialize broadcast
|
||||
if (!C4NetIOSimpleUDP::InitBroadcast(&DiscoveryAddr))
|
||||
return false;
|
||||
|
@ -55,7 +64,7 @@ bool C4Network2IODiscover::Init(uint16_t iPort)
|
|||
bool C4Network2IODiscover::Announce()
|
||||
{
|
||||
// Announce our presence
|
||||
C4Network2IODiscoverReply Reply = { 4, htons(iRefServerPort) };
|
||||
C4Network2IODiscoverReply Reply = { 4, iRefServerPort };
|
||||
return Send(C4NetIOPacket(&Reply, sizeof(Reply), false, DiscoveryAddr));
|
||||
}
|
||||
|
||||
|
@ -71,7 +80,7 @@ void C4Network2IODiscoverClient::OnPacket(const class C4NetIOPacket &rPacket, C4
|
|||
{
|
||||
const C4Network2IODiscoverReply *pReply = reinterpret_cast<const C4Network2IODiscoverReply *>(rPacket.getData());
|
||||
Discovers[iDiscoverCount] = rPacket.getAddr();
|
||||
Discovers[iDiscoverCount].sin_port = pReply->Port;
|
||||
Discovers[iDiscoverCount].SetPort(pReply->Port);
|
||||
iDiscoverCount++;
|
||||
}
|
||||
}
|
||||
|
@ -87,10 +96,8 @@ bool C4Network2IODiscoverClient::Init(uint16_t iPort)
|
|||
// Set callback
|
||||
C4NetIOSimpleUDP::SetCallback(this);
|
||||
// Build broadcast address
|
||||
DiscoveryAddr.sin_addr.s_addr = C4NetDiscoveryAddress;
|
||||
DiscoveryAddr.sin_port = htons(iPort);
|
||||
DiscoveryAddr.sin_family = AF_INET;
|
||||
ZeroMem(DiscoveryAddr.sin_zero, sizeof(DiscoveryAddr.sin_zero));
|
||||
DiscoveryAddr.SetAddress(C4NetDiscoveryAddress);
|
||||
DiscoveryAddr.SetPort(iPort);
|
||||
// Initialize broadcast
|
||||
if (!C4NetIOSimpleUDP::InitBroadcast(&DiscoveryAddr))
|
||||
return false;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
const int C4NetMaxDiscover = 64;
|
||||
|
||||
const unsigned long C4NetDiscoveryAddress = 0xef; // 239.0.0.0
|
||||
const C4NetIO::HostAddress C4NetDiscoveryAddress = C4NetIO::HostAddress(StdStrBuf("ff02::1"));
|
||||
|
||||
class C4Network2IODiscover : public C4NetIOSimpleUDP, private C4NetIO::CBClass
|
||||
{
|
||||
|
@ -34,12 +34,12 @@ protected:
|
|||
virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO);
|
||||
|
||||
public:
|
||||
bool Init(uint16_t iPort = P_NONE);
|
||||
bool Init(uint16_t iPort = C4NetIO::addr_t::IPPORT_NONE);
|
||||
void SetDiscoverable(bool fnEnabled) { fEnabled = fnEnabled; }
|
||||
bool Announce();
|
||||
|
||||
private:
|
||||
sockaddr_in DiscoveryAddr;
|
||||
C4NetIO::addr_t DiscoveryAddr;
|
||||
|
||||
uint16_t iRefServerPort;
|
||||
bool fEnabled;
|
||||
|
@ -61,7 +61,7 @@ public:
|
|||
const C4NetIO::addr_t &getDiscover(int i) { return Discovers[i]; }
|
||||
|
||||
void Clear() { iDiscoverCount = 0; }
|
||||
bool Init(uint16_t iPort = P_NONE);
|
||||
bool Init(uint16_t iPort = C4NetIO::addr_t::IPPORT_NONE);
|
||||
bool StartDiscovery();
|
||||
bool PopDiscover(C4NetIO::addr_t &Discover);
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ C4Network2IO::C4Network2IO()
|
|||
iTCPIRate(0), iTCPORate(0), iTCPBCRate(0),
|
||||
iUDPIRate(0), iUDPORate(0), iUDPBCRate(0)
|
||||
{
|
||||
ZeroMem(&PuncherAddr, sizeof(PuncherAddr));
|
||||
}
|
||||
|
||||
C4Network2IO::~C4Network2IO()
|
||||
|
@ -253,7 +252,7 @@ bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol ePr
|
|||
if (GetConnectionByConnAddr(addr, pNetIO)) return true;
|
||||
// assign new connection ID, peer address isn't known yet
|
||||
uint32_t iConnID = iNextConnID++;
|
||||
C4NetIO::addr_t paddr; ZeroMem(&paddr, sizeof paddr);
|
||||
C4NetIO::addr_t paddr;
|
||||
// create connection object and add to list
|
||||
C4Network2IOConnection *pConn = new C4Network2IOConnection();
|
||||
pConn->Set(pNetIO, eProt, paddr, addr, CS_Connect, szPassword, iConnID);
|
||||
|
@ -263,7 +262,7 @@ bool C4Network2IO::Connect(const C4NetIO::addr_t &addr, C4Network2IOProtocol ePr
|
|||
if (!pConn->Connect())
|
||||
{
|
||||
// show error
|
||||
LogF("Network: could not connect to %s:%d using %s: %s", inet_ntoa(addr.sin_addr), htons(addr.sin_port),
|
||||
LogF("Network: could not connect to %s using %s: %s", addr.ToString().getData(),
|
||||
getNetIOName(pNetIO), pNetIO->GetError() ? pNetIO->GetError() : "");
|
||||
pNetIO->ResetError();
|
||||
// remove class
|
||||
|
@ -461,28 +460,49 @@ bool C4Network2IO::InitPuncher(C4NetIO::addr_t nPuncherAddr)
|
|||
if (!pNetIO_UDP)
|
||||
return false;
|
||||
// save address
|
||||
PuncherAddr = nPuncherAddr;
|
||||
switch (nPuncherAddr.GetFamily())
|
||||
{
|
||||
case C4NetIO::HostAddress::IPv4:
|
||||
PuncherAddrIPv4 = nPuncherAddr;
|
||||
break;
|
||||
case C4NetIO::HostAddress::IPv6:
|
||||
PuncherAddrIPv6 = nPuncherAddr;
|
||||
break;
|
||||
case C4NetIO::HostAddress::UnknownFamily:
|
||||
assert(!"Unexpected address family");
|
||||
}
|
||||
// let's punch
|
||||
return pNetIO_UDP->Connect(PuncherAddr);
|
||||
return pNetIO_UDP->Connect(nPuncherAddr);
|
||||
}
|
||||
|
||||
void C4Network2IO::Punch(const C4NetIO::addr_t &punchee_addr) {
|
||||
void C4Network2IO::Punch(const C4NetIO::addr_t &punchee_addr)
|
||||
{
|
||||
if (!pNetIO_UDP)
|
||||
return;
|
||||
C4PacketPing PktPeng;
|
||||
dynamic_cast<C4NetIOUDP*>(pNetIO_UDP)->SendDirect(MkC4NetIOPacket(PID_Pong, PktPeng, punchee_addr));
|
||||
}
|
||||
|
||||
void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket& p) {
|
||||
if (!pNetIO_UDP || !PuncherAddr.sin_addr.s_addr) return;
|
||||
pNetIO_UDP->Send(p.PackTo(PuncherAddr));
|
||||
void C4Network2IO::SendPuncherPacket(const C4NetpuncherPacket& p, C4NetIO::HostAddress::AddressFamily family)
|
||||
{
|
||||
if (!pNetIO_UDP) return;
|
||||
if (family == C4NetIO::HostAddress::IPv4 && !PuncherAddrIPv4.IsNull())
|
||||
pNetIO_UDP->Send(p.PackTo(PuncherAddrIPv4));
|
||||
else if (family == C4NetIO::HostAddress::IPv6 && !PuncherAddrIPv6.IsNull())
|
||||
pNetIO_UDP->Send(p.PackTo(PuncherAddrIPv6));
|
||||
}
|
||||
|
||||
bool C4Network2IO::IsPuncherAddr(const C4NetIO::addr_t& addr) const
|
||||
{
|
||||
return (!PuncherAddrIPv4.IsNull() && PuncherAddrIPv4 == addr)
|
||||
|| (!PuncherAddrIPv6.IsNull() && PuncherAddrIPv6 == addr);
|
||||
}
|
||||
|
||||
// C4NetIO interface
|
||||
bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t &ConnectAddr, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO)
|
||||
{
|
||||
// puncher answer?
|
||||
if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, ConnectAddr))
|
||||
if (pNetIO == pNetIO_UDP && IsPuncherAddr(ConnectAddr))
|
||||
{
|
||||
// got an address?
|
||||
if (pOwnAddr)
|
||||
|
@ -497,7 +517,7 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t
|
|||
#endif
|
||||
// search connection
|
||||
C4Network2IOConnection *pConn = nullptr;
|
||||
if (ConnectAddr.sin_addr.s_addr)
|
||||
if (!ConnectAddr.IsNull())
|
||||
pConn = GetConnectionByConnAddr(ConnectAddr, pNetIO);
|
||||
// not found?
|
||||
if (!pConn)
|
||||
|
@ -527,7 +547,7 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t
|
|||
SendConnPackets();
|
||||
#if(C4NET2IO_DUMP_LEVEL > 0)
|
||||
// log
|
||||
Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s:%d", getNetIOName(pNetIO), inet_ntoa(PeerAddr.sin_addr), htons(PeerAddr.sin_port));
|
||||
Application.InteractiveThread.ThreadLogS("Network: got %s connection from %s", getNetIOName(pNetIO), PeerAddr.ToString().getData());
|
||||
#endif
|
||||
// do event (disabled - unused)
|
||||
// pConn->AddRef(); PushNetEv(NE_Conn, pConn);
|
||||
|
@ -538,9 +558,12 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t
|
|||
void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const char *szReason)
|
||||
{
|
||||
// punch?
|
||||
if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, addr))
|
||||
if (pNetIO == pNetIO_UDP && IsPuncherAddr(addr))
|
||||
{
|
||||
ZeroMem(&PuncherAddr, sizeof(PuncherAddr));
|
||||
if (PuncherAddrIPv4 == addr)
|
||||
PuncherAddrIPv4.Clear();
|
||||
else
|
||||
PuncherAddrIPv6.Clear();
|
||||
return;
|
||||
}
|
||||
#if(C4NET2IO_DUMP_LEVEL > 1)
|
||||
|
@ -554,8 +577,8 @@ void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const
|
|||
if (!pConn) return;
|
||||
#if(C4NET2IO_DUMP_LEVEL > 0)
|
||||
// log
|
||||
Application.InteractiveThread.ThreadLogS("Network: %s connection to %s:%d %s (%s)",
|
||||
getNetIOName(pNetIO), inet_ntoa(addr.sin_addr), htons(addr.sin_port), pConn->isConnecting() ? "failed" : "closed" , szReason);
|
||||
Application.InteractiveThread.ThreadLogS("Network: %s connection to %s %s (%s)",
|
||||
getNetIOName(pNetIO), addr.ToString().getData(), pConn->isConnecting() ? "failed" : "closed" , szReason);
|
||||
#endif
|
||||
// already closed? ignore
|
||||
if (!pConn->isClosed())
|
||||
|
@ -580,7 +603,7 @@ void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
|
|||
C4TimeMilliseconds::Now().AsString().getData(),
|
||||
rPacket.getStatus(), getNetIOName(pNetIO));
|
||||
#endif
|
||||
if (pNetIO == pNetIO_UDP && PuncherAddr.sin_addr.s_addr && AddrEqual(PuncherAddr, rPacket.getAddr()))
|
||||
if (pNetIO == pNetIO_UDP && IsPuncherAddr(rPacket.getAddr()))
|
||||
{
|
||||
HandlePuncherPacket(rPacket);
|
||||
return;
|
||||
|
@ -588,7 +611,11 @@ void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
|
|||
if (!rPacket.getSize()) return;
|
||||
// find connection
|
||||
C4Network2IOConnection *pConn = GetConnection(rPacket.getAddr(), pNetIO);
|
||||
if (!pConn) { Application.InteractiveThread.ThreadLog("Network: could not find connection for packet from %s:%d!", inet_ntoa(rPacket.getAddr().sin_addr), htons(rPacket.getAddr().sin_port)); return; }
|
||||
if (!pConn)
|
||||
{
|
||||
Application.InteractiveThread.ThreadLog("Network: could not find connection for %s packet (status %02x) from %s!", getNetIOName(pNetIO), rPacket.getStatus(), rPacket.getAddr().ToString().getData());
|
||||
return;
|
||||
}
|
||||
#if(C4NET2IO_DUMP_LEVEL > 2)
|
||||
uint32_t iFindConnectionBlocked = C4TimeMilliseconds::Now() - tTime;
|
||||
if (iFindConnectionBlocked > 100)
|
||||
|
@ -748,7 +775,7 @@ C4Network2IOConnection *C4Network2IO::GetConnection(const C4NetIO::addr_t &addr,
|
|||
CStdLock ConnListLock(&ConnListCSec);
|
||||
// search
|
||||
for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
|
||||
if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getPeerAddr(), addr))
|
||||
if (pConn->getNetClass() == pNetIO && pConn->getPeerAddr() == addr)
|
||||
return pConn;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -758,7 +785,7 @@ C4Network2IOConnection *C4Network2IO::GetConnectionByConnAddr(const C4NetIO::add
|
|||
CStdLock ConnListLock(&ConnListCSec);
|
||||
// search
|
||||
for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
|
||||
if (pConn->getNetClass() == pNetIO && AddrEqual(pConn->getConnectAddr(), addr))
|
||||
if (pConn->getNetClass() == pNetIO && pConn->getConnectAddr() == addr)
|
||||
return pConn;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -798,7 +825,7 @@ bool C4Network2IO::doAutoAccept(const C4ClientCore &CCore, const C4Network2IOCon
|
|||
for (C4Network2IOConnection *pConn = pConnList; pConn; pConn = pConn->pNext)
|
||||
if (pConn->isAccepted() &&
|
||||
pConn->getCCore().getDiffLevel(CCore) <= C4ClientCoreDL_IDMatch &&
|
||||
pConn->getPeerAddr().sin_addr.s_addr != Conn.getPeerAddr().sin_addr.s_addr)
|
||||
pConn->getPeerAddr().GetHost() != Conn.getPeerAddr().GetHost())
|
||||
return false;
|
||||
// not found or IP matches? Let pass
|
||||
return true;
|
||||
|
@ -837,9 +864,9 @@ bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnec
|
|||
if (Config.Network.PacketLogging && fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData)
|
||||
{
|
||||
// StdStrBuf PacketDump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdaptrPacket);
|
||||
StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s:%d (%lu bytes, counter %d)",
|
||||
StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s (%lu bytes, counter %d)",
|
||||
C4TimeMilliseconds::Now().AsString().getData(),
|
||||
inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port),
|
||||
pConn->getPeerAddr().ToString().getData(),
|
||||
static_cast<unsigned long>(rPacket.getSize()), pConn->getInPacketCounter());
|
||||
StdStrBuf Dump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(Pkt, PacketHeader.getData()));
|
||||
// Put it directly. The standard functions behind StdBuf.Format seem to choke when you pass them too much data.
|
||||
|
@ -1138,7 +1165,7 @@ void C4Network2IO::HandleFwdReq(const C4PacketFwd &rFwd, C4Network2IOConnection
|
|||
void C4Network2IO::HandlePuncherPacket(const C4NetIOPacket& rPacket)
|
||||
{
|
||||
auto pkt = C4NetpuncherPacket::Construct(rPacket);
|
||||
if (pkt && ::Network.HandlePuncherPacket(move(pkt)));
|
||||
if (pkt && ::Network.HandlePuncherPacket(move(pkt), rPacket.getAddr().GetFamily()));
|
||||
else
|
||||
{
|
||||
assert(pNetIO_UDP);
|
||||
|
@ -1172,7 +1199,7 @@ void C4Network2IO::CheckTimeout()
|
|||
if (!pConn->isClosed() && !pConn->isAccepted())
|
||||
if (difftime(time(nullptr), pConn->getTimestamp()) > C4NetAcceptTimeout)
|
||||
{
|
||||
Application.InteractiveThread.ThreadLogS("Network: connection accept timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port));
|
||||
Application.InteractiveThread.ThreadLogS("Network: connection accept timeout to %s", pConn->getPeerAddr().ToString().getData());
|
||||
pConn->Close();
|
||||
}
|
||||
// ping timeout
|
||||
|
@ -1181,7 +1208,7 @@ void C4Network2IO::CheckTimeout()
|
|||
> C4NetPingTimeout)
|
||||
{
|
||||
Application.InteractiveThread.ThreadLogS("%d %d %d", (int)pConn->getLag(), (int)time(nullptr), (int)pConn->getTimestamp());
|
||||
Application.InteractiveThread.ThreadLogS("Network: ping timeout to %s:%d", inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port));
|
||||
Application.InteractiveThread.ThreadLogS("Network: ping timeout to %s", pConn->getPeerAddr().ToString().getData());
|
||||
pConn->Close();
|
||||
}
|
||||
// delayed connection removal
|
||||
|
@ -1265,19 +1292,23 @@ void C4Network2IO::SendConnPackets()
|
|||
|
||||
void C4Network2IO::OnPuncherConnect(C4NetIO::addr_t addr)
|
||||
{
|
||||
// Sanity check
|
||||
assert (addr.sin_family == AF_INET);
|
||||
if (addr.sin_family != AF_INET)
|
||||
return;
|
||||
|
||||
Application.InteractiveThread.ThreadLogS("Adding address from puncher: %s:%d", inet_ntoa(addr.sin_addr), htons(addr.sin_port));
|
||||
|
||||
ZeroMem(addr.sin_zero, sizeof(addr.sin_zero));
|
||||
// NAT punching is only relevant for IPv4, so convert here to show a proper address.
|
||||
auto maybe_v4 = addr.AsIPv4();
|
||||
Application.InteractiveThread.ThreadLogS("Adding address from puncher: %s", maybe_v4.ToString().getData());
|
||||
// Add for local client
|
||||
C4Network2Client *pLocal = ::Network.Clients.GetLocal();
|
||||
if (pLocal)
|
||||
pLocal->AddAddr(C4Network2Address(addr, P_UDP), true);
|
||||
{
|
||||
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);
|
||||
}
|
||||
// Do not ::Network.InvalidateReference(); yet, we're expecting an ID from the netpuncher
|
||||
}
|
||||
}
|
||||
|
||||
// *** C4Network2IOConnection
|
||||
|
|
|
@ -97,7 +97,8 @@ protected:
|
|||
iUDPIRate, iUDPORate, iUDPBCRate;
|
||||
|
||||
// punching
|
||||
C4NetIO::addr_t PuncherAddr;
|
||||
C4NetIO::addr_t PuncherAddrIPv4, PuncherAddrIPv6;
|
||||
bool IsPuncherAddr(const C4NetIO::addr_t& addr) const;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -137,7 +138,7 @@ public:
|
|||
|
||||
// punch
|
||||
bool InitPuncher(C4NetIO::addr_t PuncherAddr); // by main thread
|
||||
void SendPuncherPacket(const C4NetpuncherPacket&);
|
||||
void SendPuncherPacket(const C4NetpuncherPacket&, C4NetIO::HostAddress::AddressFamily family);
|
||||
void Punch(const C4NetIO::addr_t&); // sends a ping packet
|
||||
|
||||
// stuff
|
||||
|
@ -261,7 +262,7 @@ protected:
|
|||
public:
|
||||
C4NetIO *getNetClass() const { return pNetClass; }
|
||||
C4Network2IOProtocol getProtocol() const { return eProt; }
|
||||
const C4NetIO::addr_t &getPeerAddr() const { return PeerAddr.sin_port ? PeerAddr : ConnectAddr; }
|
||||
const C4NetIO::addr_t &getPeerAddr() const { return PeerAddr.GetPort() ? PeerAddr : ConnectAddr; }
|
||||
const C4NetIO::addr_t &getConnectAddr() const { return ConnectAddr; }
|
||||
uint32_t getID() const { return iID; }
|
||||
uint32_t getRemoteID() const { return iRemoteID; }
|
||||
|
|
|
@ -246,7 +246,7 @@ size_t C4Network2IRCClient::UnpackPacket(const StdBuf &rInBuf, const C4NetIO::ad
|
|||
bool C4Network2IRCClient::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO)
|
||||
{
|
||||
// Security checks
|
||||
if (!fConnecting || fConnected || !AddrEqual(AddrConnect, ServerAddr)) return false;
|
||||
if (!fConnecting || fConnected || AddrConnect != ServerAddr) return false;
|
||||
CStdLock Lock(&CSec);
|
||||
// Save connection data
|
||||
fConnected = true;
|
||||
|
@ -318,8 +318,10 @@ bool C4Network2IRCClient::Connect(const char *szServer, const char *szNick, cons
|
|||
if (!Init())
|
||||
return false;
|
||||
// Resolve address
|
||||
if (!ResolveAddress(szServer, &ServerAddr, 6666))
|
||||
ServerAddr.SetAddress(StdStrBuf(szServer));
|
||||
if (ServerAddr.IsNull())
|
||||
{ SetError("Could no resolve server address!"); return false; }
|
||||
ServerAddr.SetDefaultPort(6666);
|
||||
// Set connection data
|
||||
Nick = szNick; RealName = szRealName;
|
||||
Password = szPassword; AutoJoin = szAutoJoin;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
C4Network2Reference::C4Network2Reference()
|
||||
: Icon(0), GameMode(), Time(0), Frame(0), StartTime(0), LeaguePerformance(0),
|
||||
JoinAllowed(true), ObservingAllowed(true), PasswordNeeded(false), OfficialServer(false),
|
||||
IsEditor(false), iAddrCnt(0), NetpuncherGameID(0)
|
||||
IsEditor(false), iAddrCnt(0), NetpuncherGameID(C4NetpuncherID())
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -40,11 +40,11 @@ C4Network2Reference::~C4Network2Reference()
|
|||
|
||||
}
|
||||
|
||||
void C4Network2Reference::SetSourceIP(in_addr ip)
|
||||
void C4Network2Reference::SetSourceAddress(const C4NetIO::EndpointAddress &ip)
|
||||
{
|
||||
for (int i = 0; i < iAddrCnt; i++)
|
||||
if (Addrs[i].isIPNull())
|
||||
Addrs[i].SetIP(ip);
|
||||
source = ip;
|
||||
if (iAddrCnt < C4ClientMaxAddr)
|
||||
Addrs[++iAddrCnt].SetAddr(ip);
|
||||
}
|
||||
|
||||
void C4Network2Reference::InitLocal()
|
||||
|
@ -127,7 +127,7 @@ void C4Network2Reference::CompileFunc(StdCompiler *pComp)
|
|||
pComp->Value(mkNamingAdapt(Game.sEngineName, "Game", "None"));
|
||||
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(Game.iVer,0),"Version" ));
|
||||
pComp->Value(mkNamingAdapt(OfficialServer, "OfficialServer", false));
|
||||
pComp->Value(mkNamingAdapt(NetpuncherGameID, "NetpuncherID", 0, false, false));
|
||||
pComp->Value(mkNamingAdapt(NetpuncherGameID, "NetpuncherID", C4NetpuncherID(), false, false));
|
||||
pComp->Value(mkNamingAdapt(NetpuncherAddr, "NetpuncherAddr", "", false, false));
|
||||
|
||||
pComp->Value(Parameters);
|
||||
|
@ -407,12 +407,15 @@ bool C4Network2HTTPClient::Decompress(StdBuf *pData)
|
|||
bool C4Network2HTTPClient::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &AddrConnect, const C4NetIO::addr_t *pOwnAddr, C4NetIO *pNetIO)
|
||||
{
|
||||
// Make sure we're actually waiting for this connection
|
||||
if (!AddrEqual(AddrConnect, ServerAddr))
|
||||
if (fConnected || (AddrConnect != ServerAddr && AddrConnect != ServerAddrFallback))
|
||||
return false;
|
||||
// Save pack peer address
|
||||
PeerAddr = AddrPeer;
|
||||
// Send the request
|
||||
Send(C4NetIOPacket(Request, AddrPeer));
|
||||
if (!Send(C4NetIOPacket(Request, AddrPeer)))
|
||||
{
|
||||
Error.Format("Unable to send HTTP request: %s", Error.getData());
|
||||
}
|
||||
Request.Clear();
|
||||
fConnected = true;
|
||||
return true;
|
||||
|
@ -442,10 +445,19 @@ void C4Network2HTTPClient::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO
|
|||
bool C4Network2HTTPClient::Execute(int iMaxTime)
|
||||
{
|
||||
// Check timeout
|
||||
if (fBusy && time(nullptr) > iRequestTimeout)
|
||||
if (fBusy)
|
||||
{
|
||||
Cancel("Request timeout");
|
||||
return true;
|
||||
if (C4TimeMilliseconds::Now() > HappyEyeballsTimeout)
|
||||
{
|
||||
HappyEyeballsTimeout = C4TimeMilliseconds::PositiveInfinity;
|
||||
Application.InteractiveThread.ThreadLogS("HTTP: Starting fallback connection to %s (%s)", Server.getData(), ServerAddrFallback.ToString().getData());
|
||||
Connect(ServerAddrFallback);
|
||||
}
|
||||
if (time(nullptr) > iRequestTimeout)
|
||||
{
|
||||
Cancel("Request timeout");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Execute normally
|
||||
return C4NetIOTCP::Execute(iMaxTime);
|
||||
|
@ -459,7 +471,9 @@ C4TimeMilliseconds C4Network2HTTPClient::GetNextTick(C4TimeMilliseconds tNow)
|
|||
|
||||
C4TimeMilliseconds tHTTPClientTick = tNow + 1000 * std::max<time_t>(iRequestTimeout - time(nullptr), 0);
|
||||
|
||||
return std::max(tNetIOTCPTick, tHTTPClientTick);
|
||||
C4TimeMilliseconds HappyEyeballsTick = tNow + std::max(HappyEyeballsTimeout - C4TimeMilliseconds::Now(), 0);
|
||||
|
||||
return std::min({tNetIOTCPTick, tHTTPClientTick, HappyEyeballsTick});
|
||||
}
|
||||
|
||||
bool C4Network2HTTPClient::Query(const StdBuf &Data, bool fBinary)
|
||||
|
@ -509,6 +523,11 @@ bool C4Network2HTTPClient::Query(const StdBuf &Data, bool fBinary)
|
|||
// Start connecting
|
||||
if (!Connect(ServerAddr))
|
||||
return false;
|
||||
// Also try the fallback address after some time (if there is one)
|
||||
if (!ServerAddrFallback.IsNull())
|
||||
HappyEyeballsTimeout = C4TimeMilliseconds::Now() + C4Network2HTTPHappyEyeballsTimeout;
|
||||
else
|
||||
HappyEyeballsTimeout = C4TimeMilliseconds::PositiveInfinity;
|
||||
// Okay, request will be performed when connection is complete
|
||||
fBusy = true;
|
||||
iDataOffset = 0;
|
||||
|
@ -526,7 +545,7 @@ void C4Network2HTTPClient::ResetRequestTimeout()
|
|||
void C4Network2HTTPClient::Cancel(const char *szReason)
|
||||
{
|
||||
// Close connection - and connection attempt
|
||||
Close(ServerAddr); Close(PeerAddr);
|
||||
Close(ServerAddr); Close(ServerAddrFallback); Close(PeerAddr);
|
||||
// Reset flags
|
||||
fBusy = fSuccess = fConnected = fBinary = false;
|
||||
iDownloadedSize = iTotalSize = iDataOffset = 0;
|
||||
|
@ -557,15 +576,29 @@ bool C4Network2HTTPClient::SetServer(const char *szServerAddress)
|
|||
RequestPath = "/";
|
||||
}
|
||||
// Resolve address
|
||||
if (!ResolveAddress(Server.getData(), &ServerAddr, GetDefaultPort()))
|
||||
ServerAddr.SetAddress(Server);
|
||||
if (ServerAddr.IsNull())
|
||||
{
|
||||
SetError(FormatString("Could not resolve server address %s!", Server.getData()).getData());
|
||||
return false;
|
||||
}
|
||||
ServerAddr.SetDefaultPort(GetDefaultPort());
|
||||
if (ServerAddr.GetFamily() == C4NetIO::HostAddress::IPv6)
|
||||
{
|
||||
// Try to find a fallback IPv4 address for Happy Eyeballs.
|
||||
ServerAddrFallback.SetAddress(Server, C4NetIO::HostAddress::IPv4);
|
||||
ServerAddrFallback.SetDefaultPort(GetDefaultPort());
|
||||
}
|
||||
else
|
||||
ServerAddrFallback.Clear();
|
||||
// Remove port
|
||||
const char *pColon = strchr(Server.getData(), ':');
|
||||
if (pColon)
|
||||
Server.SetLength(pColon - Server.getData());
|
||||
const char *firstColon = strchr(Server.getData(), ':');
|
||||
const char *lastColon = strrchr(Server.getData(), ':');
|
||||
if (firstColon)
|
||||
// hostname/IPv4 address or IPv6 address with port (e.g. [::1]:1234)
|
||||
if (firstColon == lastColon || (Server[0] == '[' && *(lastColon - 1) == ']'))
|
||||
Server.SetLength(lastColon - Server.getData());
|
||||
|
||||
// Done
|
||||
ResetError();
|
||||
return true;
|
||||
|
@ -657,7 +690,7 @@ bool C4Network2RefClient::GetReferences(C4Network2Reference **&rpReferences, int
|
|||
}
|
||||
// Set source ip
|
||||
for (int i = 0; i < rRefCount; i++)
|
||||
rpReferences[i]->SetSourceIP(getServerAddress().sin_addr);
|
||||
rpReferences[i]->SetSourceAddress(getServerAddress());
|
||||
// Done
|
||||
ResetError();
|
||||
return true;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "lib/C4InputValidation.h"
|
||||
|
||||
const int C4Network2HTTPQueryTimeout = 10; // (s)
|
||||
const uint32_t C4Network2HTTPHappyEyeballsTimeout = 300; // (ms)
|
||||
|
||||
// Session data
|
||||
class C4Network2Reference
|
||||
|
@ -51,7 +52,7 @@ private:
|
|||
bool PasswordNeeded;
|
||||
bool OfficialServer;
|
||||
bool IsEditor;
|
||||
C4NetpuncherID_t NetpuncherGameID;
|
||||
C4NetpuncherID NetpuncherGameID;
|
||||
StdCopyStrBuf NetpuncherAddr;
|
||||
|
||||
// Engine information
|
||||
|
@ -60,9 +61,11 @@ private:
|
|||
// Network addresses
|
||||
uint8_t iAddrCnt;
|
||||
C4Network2Address Addrs[C4ClientMaxAddr];
|
||||
C4NetIO::EndpointAddress source;
|
||||
|
||||
public:
|
||||
const C4Network2Address &getAddr(int i) const { return Addrs[i]; }
|
||||
C4Network2Address &getAddr(int i) { return Addrs[i]; }
|
||||
int getAddrCnt() const { return iAddrCnt; }
|
||||
const char *getTitle() const { return Title.getData(); }
|
||||
int32_t getIcon() const { return Icon; }
|
||||
|
@ -77,10 +80,11 @@ public:
|
|||
int32_t getStartTime() const { return StartTime; }
|
||||
StdStrBuf getGameGoalString() const;
|
||||
bool isEditor() const { return IsEditor; }
|
||||
C4NetpuncherID_t getNetpuncherGameID() const { return NetpuncherGameID; }
|
||||
C4NetpuncherID getNetpuncherGameID() const { return NetpuncherGameID; }
|
||||
StdStrBuf getNetpuncherAddr() const { return NetpuncherAddr; }
|
||||
|
||||
void SetSourceIP(in_addr ip);
|
||||
void SetSourceAddress(const C4NetIO::EndpointAddress &ip);
|
||||
const C4NetIO::EndpointAddress &GetSourceAddress() const { return source; }
|
||||
|
||||
void InitLocal();
|
||||
|
||||
|
@ -126,7 +130,7 @@ public:
|
|||
private:
|
||||
|
||||
// Address information
|
||||
C4NetIO::addr_t ServerAddr, PeerAddr;
|
||||
C4NetIO::addr_t ServerAddr, ServerAddrFallback, PeerAddr;
|
||||
StdCopyStrBuf Server, RequestPath;
|
||||
|
||||
bool fBinary;
|
||||
|
@ -134,6 +138,7 @@ private:
|
|||
size_t iDataOffset;
|
||||
StdCopyBuf Request;
|
||||
time_t iRequestTimeout;
|
||||
C4TimeMilliseconds HappyEyeballsTimeout;
|
||||
|
||||
// Response header data
|
||||
size_t iDownloadedSize, iTotalSize;
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
C4AulDebug::C4AulDebug()
|
||||
: fInit(false), fConnected(false)
|
||||
{
|
||||
ZeroMem(&PeerAddr, sizeof PeerAddr);
|
||||
}
|
||||
|
||||
C4AulDebug::~C4AulDebug()
|
||||
|
@ -125,15 +124,15 @@ bool C4AulDebug::OnConn(const C4NetIO::addr_t &AddrPeer, const C4NetIO::addr_t &
|
|||
// Already have a connection?
|
||||
if (fConnected) return false;
|
||||
// Check address
|
||||
if (AllowedAddr.sin_addr.s_addr)
|
||||
if (AllowedAddr.sin_addr.s_addr != AddrPeer.sin_addr.s_addr ||
|
||||
(AllowedAddr.sin_port && AllowedAddr.sin_port != AddrPeer.sin_port))
|
||||
if (!AllowedAddr.IsNull())
|
||||
if (AllowedAddr.GetHost() != AddrPeer.GetHost() ||
|
||||
(AllowedAddr.GetPort() && AllowedAddr.GetPort() != AddrPeer.GetPort()))
|
||||
{
|
||||
LogF("C4AulDebug blocked connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port));
|
||||
LogF("C4AulDebug blocked connection from %s", AddrPeer.ToString().getData());
|
||||
return false;
|
||||
}
|
||||
// Log
|
||||
LogF("C4AulDebug got connection from %s:%d", inet_ntoa(AddrPeer.sin_addr), htons(AddrPeer.sin_port));
|
||||
LogF("C4AulDebug got connection from %s", AddrPeer.ToString().getData());
|
||||
// Accept connection
|
||||
PeerAddr = AddrPeer;
|
||||
return true;
|
||||
|
@ -144,7 +143,7 @@ void C4AulDebug::OnDisconn(const C4NetIO::addr_t &AddrPeer, C4NetIO *pNetIO, con
|
|||
LogF("C4AulDebug lost connection (%s)", szReason);
|
||||
fConnected = false;
|
||||
eState = DS_Go;
|
||||
ZeroMem(&PeerAddr, sizeof PeerAddr);
|
||||
PeerAddr.Clear();
|
||||
}
|
||||
|
||||
void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
|
||||
|
@ -155,17 +154,18 @@ void C4AulDebug::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
|
|||
bool C4AulDebug::SetAllowed(const char *szHost)
|
||||
{
|
||||
// Clear
|
||||
ZeroMem(&AllowedAddr, sizeof(AllowedAddr));
|
||||
AllowedAddr.Clear();
|
||||
// No host?
|
||||
if (!szHost || !*szHost) return true;
|
||||
// Resolve the address
|
||||
return ResolveAddress(szHost, &AllowedAddr, 0);
|
||||
AllowedAddr.SetAddress(StdStrBuf(szHost));
|
||||
return !AllowedAddr.IsNull();
|
||||
}
|
||||
|
||||
bool C4AulDebug::Init(uint16_t iPort)
|
||||
{
|
||||
if (fInit) Close();
|
||||
if (iPort == P_NONE) return false;
|
||||
if (iPort == EndpointAddress::IPPORT_NONE) return false;
|
||||
|
||||
// Register self as callback for network events
|
||||
C4NetIOTCP::SetCallback(this);
|
||||
|
|
Loading…
Reference in New Issue