[DHT] Integrate the protocol into the game's network infrastructure
This commit is contained in:
parent
76b8e299a0
commit
5d4cd82ed1
@ -43,7 +43,6 @@ extern "C" int dht_gettimeofday(struct timeval *tp, struct timezone* /*tzp*/)
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
SOCKET DHT::Socket;
|
|
||||||
std::mutex DHT::Mutex;
|
std::mutex DHT::Mutex;
|
||||||
std::vector<Network::Address> DHT::Nodes;
|
std::vector<Network::Address> DHT::Nodes;
|
||||||
std::map<std::basic_string<uint8_t>, Utils::Slot<void(std::vector<Network::Address>)>> DHT::Handlers;
|
std::map<std::basic_string<uint8_t>, Utils::Slot<void(std::vector<Network::Address>)>> DHT::Handlers;
|
||||||
@ -66,6 +65,12 @@ namespace Components
|
|||||||
DHT::Handlers[hashStr] = callback;
|
DHT::Handlers[hashStr] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DHT::BootstrapDone()
|
||||||
|
{
|
||||||
|
// Tell the game we got our external ip
|
||||||
|
Utils::Hook::Set<BYTE>(0x649D6F0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
void DHT::Hash(std::string data, void* out, size_t size)
|
void DHT::Hash(std::string data, void* out, size_t size)
|
||||||
{
|
{
|
||||||
ZeroMemory(out, size);
|
ZeroMemory(out, size);
|
||||||
@ -115,11 +120,10 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHT::OnData(std::string data, Network::Address address)
|
void DHT::OnData(char* buf, int len, sockaddr* from, int fromlen)
|
||||||
{
|
{
|
||||||
time_t tosleep = 0;
|
time_t tosleep = 0;
|
||||||
sockaddr addr = address.getSockAddr();
|
dht_periodic(buf, len, from, fromlen, &tosleep, DHT::Callback, NULL);
|
||||||
dht_periodic(data.data(), data.size(), &addr, sizeof(addr), &tosleep, DHT::Callback, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHT::StoreNodes(bool force)
|
void DHT::StoreNodes(bool force)
|
||||||
@ -213,29 +217,8 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHT::SocketFrame()
|
|
||||||
{
|
|
||||||
static char buffer[0x2001];
|
|
||||||
|
|
||||||
sockaddr_in addr;
|
|
||||||
int addrLen = sizeof(addr);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int len = recvfrom(DHT::Socket, buffer, sizeof buffer, 0, reinterpret_cast<sockaddr*>(&addr), &addrLen);
|
|
||||||
if (len <= 0) break;
|
|
||||||
|
|
||||||
Network::Address address(&addr);
|
|
||||||
|
|
||||||
std::string data(buffer, len);
|
|
||||||
DHT::OnData(data, address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DHT::RunFrame()
|
void DHT::RunFrame()
|
||||||
{
|
{
|
||||||
DHT::SocketFrame();
|
|
||||||
|
|
||||||
time_t tosleep = 0;
|
time_t tosleep = 0;
|
||||||
dht_periodic(NULL, 0, NULL, 0, &tosleep, DHT::Callback, NULL);
|
dht_periodic(NULL, 0, NULL, 0, &tosleep, DHT::Callback, NULL);
|
||||||
DHT::StoreNodes(false);
|
DHT::StoreNodes(false);
|
||||||
@ -256,36 +239,6 @@ namespace Components
|
|||||||
dht_ping_node(&addr, sizeof(addr));
|
dht_ping_node(&addr, sizeof(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHT::InitSocket()
|
|
||||||
{
|
|
||||||
WSAData data;
|
|
||||||
WSAStartup(MAKEWORD(2, 2), &data);
|
|
||||||
|
|
||||||
DHT::Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
|
|
||||||
int broadcastOn = 1;
|
|
||||||
setsockopt(DHT::Socket, SOL_SOCKET, SO_BROADCAST, LPSTR(&broadcastOn), sizeof(broadcastOn));
|
|
||||||
|
|
||||||
unsigned long nonBlocking = 1;
|
|
||||||
ioctlsocket(DHT::Socket, FIONBIO, &nonBlocking);
|
|
||||||
|
|
||||||
sockaddr_in addr;
|
|
||||||
ZeroMemory(&addr, sizeof(addr));
|
|
||||||
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
|
|
||||||
unsigned short port = DHT_PORT;
|
|
||||||
while (port < DHT_PORT + DHT_RANGE)
|
|
||||||
{
|
|
||||||
addr.sin_port = htons(port++);
|
|
||||||
if (bind(DHT::Socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DHT::DHT()
|
DHT::DHT()
|
||||||
{
|
{
|
||||||
// #ifdef DEBUG
|
// #ifdef DEBUG
|
||||||
@ -314,23 +267,22 @@ namespace Components
|
|||||||
Utils::IO::WriteFile(file, idData);
|
Utils::IO::WriteFile(file, idData);
|
||||||
}
|
}
|
||||||
|
|
||||||
DHT::InitSocket();
|
dht_init(INT(*Game::ip_socket), -1, reinterpret_cast<unsigned char*>(idData.data()), reinterpret_cast<unsigned char*>("JC\0\0"));
|
||||||
dht_init(INT(DHT::Socket), -1, reinterpret_cast<unsigned char*>(idData.data()), reinterpret_cast<unsigned char*>("JC\0\0"));
|
|
||||||
|
|
||||||
DHT::LoadNodes();
|
DHT::LoadNodes();
|
||||||
Scheduler::OnFrame(DHT::RunFrame);
|
Scheduler::OnFrame(DHT::RunFrame);
|
||||||
|
|
||||||
DHT::Bootstrap("router.bittorrent.com:6881");
|
DHT::Bootstrap("router.bittorrent.com:6881");
|
||||||
DHT::Bootstrap("router.utorrent.com:6881");
|
|
||||||
DHT::Bootstrap("dht.transmissionbt.com:6881");
|
DHT::Bootstrap("dht.transmissionbt.com:6881");
|
||||||
//DHT::Bootstrap("router.bitcomet.com:6881"); // Blacklisted
|
|
||||||
DHT::Bootstrap("dht.aelitis.com:6881");
|
DHT::Bootstrap("dht.aelitis.com:6881");
|
||||||
});
|
});
|
||||||
|
|
||||||
DHT::Insert("IW4x", [](std::vector<Network::Address> addresses)
|
auto callback = [](std::vector<Network::Address> addresses)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> _(DHT::Mutex);
|
std::lock_guard<std::mutex> _(DHT::Mutex);
|
||||||
|
|
||||||
|
DHT::BootstrapDone();
|
||||||
|
|
||||||
for (auto& address : addresses)
|
for (auto& address : addresses)
|
||||||
{
|
{
|
||||||
if (std::find(DHT::Nodes.begin(), DHT::Nodes.end(), address) == DHT::Nodes.end())
|
if (std::find(DHT::Nodes.begin(), DHT::Nodes.end(), address) == DHT::Nodes.end())
|
||||||
@ -348,7 +300,9 @@ namespace Components
|
|||||||
|
|
||||||
Logger::Print("Received %s\n", address.getCString());
|
Logger::Print("Received %s\n", address.getCString());
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
DHT::Insert("xPROTO_IW4x", callback);
|
||||||
|
|
||||||
Command::Add("addnode", [](Command::Params* params)
|
Command::Add("addnode", [](Command::Params* params)
|
||||||
{
|
{
|
||||||
@ -359,14 +313,11 @@ namespace Components
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DHT::~DHT()
|
void DHT::preDestroy()
|
||||||
{
|
{
|
||||||
DHT::Handlers.clear();
|
DHT::Handlers.clear();
|
||||||
|
|
||||||
DHT::StoreNodes(true);
|
DHT::StoreNodes(true);
|
||||||
dht_uninit();
|
dht_uninit();
|
||||||
|
|
||||||
closesocket(DHT::Socket);
|
|
||||||
WSACleanup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace Components
|
|||||||
typedef unsigned char Id[20];
|
typedef unsigned char Id[20];
|
||||||
|
|
||||||
DHT();
|
DHT();
|
||||||
~DHT();
|
void preDestroy() override;
|
||||||
|
|
||||||
static void OnData(std::string data, Network::Address address);
|
static void OnData(char* buf, int len, sockaddr* from, int fromlen);
|
||||||
|
|
||||||
static void Insert(std::string data, Utils::Slot<void(std::vector<Network::Address>)> callback);
|
static void Insert(std::string data, Utils::Slot<void(std::vector<Network::Address>)> callback);
|
||||||
|
|
||||||
@ -28,8 +28,9 @@ namespace Components
|
|||||||
|
|
||||||
static void Hash(std::string data, void* out, size_t size);
|
static void Hash(std::string data, void* out, size_t size);
|
||||||
|
|
||||||
|
static void BootstrapDone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static SOCKET Socket;
|
|
||||||
static std::mutex Mutex;
|
static std::mutex Mutex;
|
||||||
static std::vector<Network::Address> Nodes;
|
static std::vector<Network::Address> Nodes;
|
||||||
static std::map<std::basic_string<uint8_t>, Utils::Slot<void(std::vector<Network::Address>)>> Handlers;
|
static std::map<std::basic_string<uint8_t>, Utils::Slot<void(std::vector<Network::Address>)>> Handlers;
|
||||||
@ -39,9 +40,6 @@ namespace Components
|
|||||||
static void StoreNodes(bool force);
|
static void StoreNodes(bool force);
|
||||||
static void LoadNodes();
|
static void LoadNodes();
|
||||||
|
|
||||||
static void InitSocket();
|
|
||||||
static void SocketFrame();
|
|
||||||
|
|
||||||
static void Bootstrap(Network::Address node);
|
static void Bootstrap(Network::Address node);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -287,6 +287,8 @@ namespace Components
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Localization::Set("PLATFORM_POPUP_CONNECTION", "Connecting to the DHT network");
|
||||||
|
|
||||||
// #ifndef DISABLE_ANTICHEAT
|
// #ifndef DISABLE_ANTICHEAT
|
||||||
// if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests())
|
// if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests())
|
||||||
// {
|
// {
|
||||||
|
@ -336,6 +336,52 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __stdcall Network::SendTo(SOCKET s, const char * buf, int len, int flags, const sockaddr* to, int tolen)
|
||||||
|
{
|
||||||
|
static char buffer[0x20000];
|
||||||
|
|
||||||
|
if (len <= 4 || *reinterpret_cast<const int*>(buf) != -1)
|
||||||
|
{
|
||||||
|
if (len + 4 > sizeof(buffer))
|
||||||
|
{
|
||||||
|
Logger::Error("Network layer 1: Packet exceeds buffer length!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memmove(buffer + 4, buf, len);
|
||||||
|
*reinterpret_cast<int*>(buffer) = -2;
|
||||||
|
|
||||||
|
len += 4;
|
||||||
|
buf = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendto(s, buf, len, flags, to, tolen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __stdcall Network::RecvFrom(SOCKET s, char* buf, int len, int flags, sockaddr* from, int * fromlen)
|
||||||
|
{
|
||||||
|
int size = recvfrom(s, buf, len, flags, from, fromlen);
|
||||||
|
if (size >= 4)
|
||||||
|
{
|
||||||
|
int magic = *reinterpret_cast<int*>(buf);
|
||||||
|
|
||||||
|
if (magic == -2)
|
||||||
|
{
|
||||||
|
size -= 4;
|
||||||
|
std::memmove(buf, buf + 4, size);
|
||||||
|
}
|
||||||
|
else if (magic != -1)
|
||||||
|
{
|
||||||
|
if (len > size) buf[size] = 0;
|
||||||
|
DHT::OnData(buf, size, from, *fromlen);
|
||||||
|
|
||||||
|
size = -1;
|
||||||
|
WSASetLastError(WSAEWOULDBLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
Network::Network()
|
Network::Network()
|
||||||
{
|
{
|
||||||
AssertSize(Game::netadr_t, 20);
|
AssertSize(Game::netadr_t, 20);
|
||||||
@ -372,6 +418,10 @@ namespace Components
|
|||||||
// Install packet deploy hook
|
// Install packet deploy hook
|
||||||
Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub);
|
Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub);
|
||||||
|
|
||||||
|
// Intercept the games native network IO interaction
|
||||||
|
Utils::Hook::Set(0x6D740C, Network::SendTo);
|
||||||
|
Utils::Hook::Set(0x6D7464, Network::RecvFrom);
|
||||||
|
|
||||||
Network::Handle("resolveAddress", [](Address address, std::string data)
|
Network::Handle("resolveAddress", [](Address address, std::string data)
|
||||||
{
|
{
|
||||||
Network::SendRaw(address, address.getString());
|
Network::SendRaw(address, address.getString());
|
||||||
|
@ -89,6 +89,9 @@ namespace Components
|
|||||||
static void NetworkStartStub();
|
static void NetworkStartStub();
|
||||||
|
|
||||||
static void PacketErrorCheck();
|
static void PacketErrorCheck();
|
||||||
|
|
||||||
|
static int __stdcall SendTo(SOCKET s, const char * buf, int len, int flags, const sockaddr* to, int tolen);
|
||||||
|
static int __stdcall RecvFrom(SOCKET s, char* buf, int len, int flags, sockaddr* from, int * fromlen);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ namespace Components
|
|||||||
Utils::Hook::Nop(0x684080, 5); // Don't spam the console
|
Utils::Hook::Nop(0x684080, 5); // Don't spam the console
|
||||||
|
|
||||||
// spawn upnp thread when UPNP_init returns
|
// spawn upnp thread when UPNP_init returns
|
||||||
Utils::Hook::Hook(0x47982B, []()
|
/*Utils::Hook::Hook(0x47982B, []()
|
||||||
{
|
{
|
||||||
std::thread([]()
|
std::thread([]()
|
||||||
{
|
{
|
||||||
@ -271,10 +271,16 @@ namespace Components
|
|||||||
std::this_thread::sleep_for(500ms);
|
std::this_thread::sleep_for(500ms);
|
||||||
}
|
}
|
||||||
}).detach();
|
}).detach();
|
||||||
}, HOOK_JUMP).install()->quick();
|
}, HOOK_JUMP).install()->quick();*/
|
||||||
|
|
||||||
|
// Completely disable UPNP, as it conflicts with our new network protocol
|
||||||
|
Utils::Hook::Set<BYTE>(0x4797F2, 0xC3);
|
||||||
|
|
||||||
// disable the IWNet IP detection (default 'got ipdetect' flag to 1)
|
// disable the IWNet IP detection (default 'got ipdetect' flag to 1)
|
||||||
Utils::Hook::Set<BYTE>(0x649D6F0, 1);
|
//Utils::Hook::Set<BYTE>(0x649D6F0, 1);
|
||||||
|
|
||||||
|
// Tell the game we're already trying to receive our IP
|
||||||
|
Utils::Hook(0x48C5C0, 0x4513B4, HOOK_JUMP).install()->quick();
|
||||||
|
|
||||||
// Fix stats sleeping
|
// Fix stats sleeping
|
||||||
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);
|
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);
|
||||||
|
Loading…
Reference in New Issue
Block a user