[DHT] Integrate the protocol into the game's network infrastructure

This commit is contained in:
momo5502 2017-09-03 18:14:08 +02:00
parent 76b8e299a0
commit 5d4cd82ed1
6 changed files with 84 additions and 74 deletions

View File

@ -43,7 +43,6 @@ extern "C" int dht_gettimeofday(struct timeval *tp, struct timezone* /*tzp*/)
namespace Components
{
SOCKET DHT::Socket;
std::mutex DHT::Mutex;
std::vector<Network::Address> DHT::Nodes;
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;
}
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)
{
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;
sockaddr addr = address.getSockAddr();
dht_periodic(data.data(), data.size(), &addr, sizeof(addr), &tosleep, DHT::Callback, NULL);
dht_periodic(buf, len, from, fromlen, &tosleep, DHT::Callback, NULL);
}
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()
{
DHT::SocketFrame();
time_t tosleep = 0;
dht_periodic(NULL, 0, NULL, 0, &tosleep, DHT::Callback, NULL);
DHT::StoreNodes(false);
@ -256,36 +239,6 @@ namespace Components
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()
{
// #ifdef DEBUG
@ -314,23 +267,22 @@ namespace Components
Utils::IO::WriteFile(file, idData);
}
DHT::InitSocket();
dht_init(INT(DHT::Socket), -1, reinterpret_cast<unsigned char*>(idData.data()), reinterpret_cast<unsigned char*>("JC\0\0"));
dht_init(INT(*Game::ip_socket), -1, reinterpret_cast<unsigned char*>(idData.data()), reinterpret_cast<unsigned char*>("JC\0\0"));
DHT::LoadNodes();
Scheduler::OnFrame(DHT::RunFrame);
DHT::Bootstrap("router.bittorrent.com:6881");
DHT::Bootstrap("router.utorrent.com:6881");
DHT::Bootstrap("dht.transmissionbt.com:6881");
//DHT::Bootstrap("router.bitcomet.com:6881"); // Blacklisted
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);
DHT::BootstrapDone();
for (auto& address : addresses)
{
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());
}
});
};
DHT::Insert("xPROTO_IW4x", callback);
Command::Add("addnode", [](Command::Params* params)
{
@ -359,14 +313,11 @@ namespace Components
});
}
DHT::~DHT()
void DHT::preDestroy()
{
DHT::Handlers.clear();
DHT::StoreNodes(true);
dht_uninit();
closesocket(DHT::Socket);
WSACleanup();
}
}

View File

@ -11,9 +11,9 @@ namespace Components
typedef unsigned char Id[20];
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);
@ -28,8 +28,9 @@ namespace Components
static void Hash(std::string data, void* out, size_t size);
static void BootstrapDone();
private:
static SOCKET Socket;
static std::mutex Mutex;
static std::vector<Network::Address> Nodes;
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 LoadNodes();
static void InitSocket();
static void SocketFrame();
static void Bootstrap(Network::Address node);
};
}

View File

@ -287,6 +287,8 @@ namespace Components
}
});
Localization::Set("PLATFORM_POPUP_CONNECTION", "Connecting to the DHT network");
// #ifndef DISABLE_ANTICHEAT
// if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests())
// {

View File

@ -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()
{
AssertSize(Game::netadr_t, 20);
@ -372,6 +418,10 @@ namespace Components
// Install packet deploy hook
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::SendRaw(address, address.getString());

View File

@ -89,6 +89,9 @@ namespace Components
static void NetworkStartStub();
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);
};
}

View File

@ -259,7 +259,7 @@ namespace Components
Utils::Hook::Nop(0x684080, 5); // Don't spam the console
// spawn upnp thread when UPNP_init returns
Utils::Hook::Hook(0x47982B, []()
/*Utils::Hook::Hook(0x47982B, []()
{
std::thread([]()
{
@ -271,10 +271,16 @@ namespace Components
std::this_thread::sleep_for(500ms);
}
}).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)
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
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);