Merge branch 'ipv6'

alut-include-path
Lukas Werling 2017-01-18 21:59:16 +01:00
commit ef4f1d9231
25 changed files with 1139 additions and 408 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
}
};
}

View File

@ -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 {

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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())

View File

@ -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:

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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; }

View File

@ -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());
}

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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; }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);