t7x/src/client/component/network.cpp

172 lines
4.3 KiB
C++
Raw Normal View History

2022-10-19 15:07:07 -04:00
#include <std_include.hpp>
2022-10-24 15:00:22 -04:00
#include "network.hpp"
2022-10-19 15:07:07 -04:00
#include "loader/component_loader.hpp"
2022-10-24 13:57:33 -04:00
#include "scheduler.hpp"
2022-10-19 15:07:07 -04:00
#include "game/game.hpp"
#include <utils/hook.hpp>
2022-10-24 13:57:33 -04:00
#include <utils/string.hpp>
2022-10-23 13:56:03 -04:00
2022-10-19 15:07:07 -04:00
namespace network
{
namespace
{
2022-10-23 13:56:03 -04:00
std::unordered_map<std::string, callback>& get_callbacks()
2022-10-19 15:07:07 -04:00
{
2022-10-23 13:56:03 -04:00
static std::unordered_map<std::string, callback> callbacks{};
return callbacks;
}
2022-10-24 13:57:33 -04:00
bool handle_command(const game::netadr_t* address, const char* command, const game::msg_t* message)
2022-10-23 13:56:03 -04:00
{
2022-10-24 13:57:33 -04:00
const auto cmd_string = utils::string::to_lower(command);
2022-10-23 13:56:03 -04:00
auto& callbacks = get_callbacks();
const auto handler = callbacks.find(cmd_string);
const auto offset = cmd_string.size() + 5;
2022-10-24 13:57:33 -04:00
if (message->cursize < 0 || static_cast<size_t>(message->cursize) < offset || handler == callbacks.end())
2022-10-19 15:07:07 -04:00
{
2022-10-24 13:57:33 -04:00
return false;
2022-10-19 15:07:07 -04:00
}
2022-10-23 13:56:03 -04:00
2022-10-24 13:57:33 -04:00
const std::basic_string_view data(message->data + offset, message->cursize - offset);
2022-10-19 15:07:07 -04:00
2022-10-24 13:57:33 -04:00
handler->second(*address, data);
return true;
2022-10-19 15:07:07 -04:00
}
2022-10-23 13:56:03 -04:00
void handle_command_stub(utils::hook::assembler& a)
2022-10-19 15:07:07 -04:00
{
2022-10-23 13:56:03 -04:00
a.pushad64();
2022-10-24 13:57:33 -04:00
a.mov(r8, r12); // msg
2022-10-23 13:56:03 -04:00
a.mov(rdx, rcx); // command
2022-10-24 13:57:33 -04:00
a.mov(rcx, r15); // address
2022-10-23 13:56:03 -04:00
a.call_aligned(handle_command);
a.movzx(rax, al);
a.mov(qword_ptr(rsp, 0x78), rax);
a.popad64();
a.jmp(0x14134D14B_g);
2022-10-19 15:07:07 -04:00
}
2022-10-23 14:57:44 -04:00
bool socket_set_blocking(const SOCKET s, const bool blocking)
{
unsigned long mode = blocking ? 0 : 1;
return ioctlsocket(s, FIONBIO, &mode) == 0;
}
void create_ip_socket()
{
auto& s = *game::ip_socket;
if (s)
{
return;
}
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2022-10-24 13:57:33 -04:00
if (s == INVALID_SOCKET)
{
throw std::runtime_error("Unable to create socket");
}
2022-10-23 14:57:44 -04:00
socket_set_blocking(s, false);
const auto address = htonl(INADDR_ANY);
const auto port = htons(28960);
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = address;
server_addr.sin_port = port;
if (bind(s, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)) ==
SOCKET_ERROR)
{
throw std::runtime_error("Failed to bind socket");
}
}
2022-10-24 15:00:22 -04:00
}
2022-10-24 13:57:33 -04:00
2022-10-24 15:00:22 -04:00
void on(const std::string& command, const callback& callback)
{
get_callbacks()[utils::string::to_lower(command)] = callback;
}
void send(const game::netadr_t& address, const std::string& command, const std::string& data, const char separator)
{
std::string packet = "\xFF\xFF\xFF\xFF";
packet.append(command);
packet.push_back(separator);
packet.append(data);
send_data(address, packet);
}
void send_data(const game::netadr_t& address, const void* data, const size_t size)
{
game::NET_SendPacket(game::NS_CLIENT1, static_cast<int>(size), data, &address);
}
void send_data(const game::netadr_t& address, const std::string& data)
{
send_data(address, data.data(), data.size());
2022-10-19 15:07:07 -04:00
}
class component final : public component_interface
{
public:
void post_unpack() override
{
// redirect dw_sendto to raw socket
2022-10-24 13:57:33 -04:00
//utils::hook::jump(0x14233307E_g, 0x1423330C7_g);
2022-10-19 15:07:07 -04:00
2022-10-23 13:56:03 -04:00
utils::hook::nop(0x142333056_g, 5); // don't add sock to packet
utils::hook::set<uint8_t>(0x14233305E_g, 0); // don't add checksum to packet
2022-10-19 15:07:07 -04:00
2022-10-23 14:57:44 -04:00
utils::hook::nop(0x142332E43_g, 5); // don't read local net id
2022-10-23 13:56:03 -04:00
utils::hook::set<uint8_t>(0x142332E55_g, 0); // clear local net id
utils::hook::jump(0x142332E72_g, 0x142332E8E_g); // skip checksum parsing
2022-10-19 15:07:07 -04:00
2022-10-23 14:57:44 -04:00
// Fix netadr types
utils::hook::set<uint32_t>(0x142332DE5_g, game::NA_RAWIP); // raw socket type
utils::hook::set<uint32_t>(0x142332E00_g, game::NA_IP); // dw socket type
2022-10-23 13:56:03 -04:00
// intercept command handling
utils::hook::jump(0x14134D146_g, utils::hook::assemble(handle_command_stub));
2022-10-19 15:07:07 -04:00
2022-10-24 13:57:33 -04:00
on("getServersResponse", [](const game::netadr_t& /*source*/, const data_view& data)
{
OutputDebugStringA(utils::string::va("%.*s", static_cast<int>(data.size()), data.data()));
});
// TODO: Fix that
scheduler::once([]
{
create_ip_socket();
}, scheduler::main);
2022-10-23 13:56:03 -04:00
/*std::thread([]
{
while (true)
{
2022-10-24 15:00:22 -04:00
MessageBoxA(0, 0, 0, 0);
game::netadr_t addr{};
addr.type = game::NA_RAWIP;
addr.port = 20810;
*reinterpret_cast<unsigned long*>(&addr.ipv4.a) = inet_addr("116.203.183.23");
addr.localNetID = game::NS_CLIENT1;
send(addr, "getservers", utils::string::va("T7 %i full empty", 1));
2022-10-23 13:56:03 -04:00
}
}).detach();*/
}
2022-10-19 15:07:07 -04:00
};
}
2022-10-23 13:56:03 -04:00
REGISTER_COMPONENT(network::component)