1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-04 13:42:55 +01:00

endian-safe packet streams

This commit is contained in:
zsilencer
2015-07-14 22:40:22 -06:00
parent 149b3d86af
commit 71f20b44aa
2 changed files with 136 additions and 95 deletions

View File

@@ -55,6 +55,7 @@ enum {
NetworkPacket::NetworkPacket()
{
transferred = 0;
read = 0;
size = 0;
data = std::make_shared<std::vector<uint8>>();
@@ -77,15 +78,16 @@ uint8* NetworkPacket::GetData()
void NetworkPacket::Clear()
{
transferred = 0;
read = 0;
data->clear();
}
int NetworkConnection::ReadPacket()
{
if (inboundpacket.read < sizeof(inboundpacket.size)) {
if (inboundpacket.transferred < sizeof(inboundpacket.size)) {
// read packet size
int readBytes = recv(socket, &((char*)&inboundpacket.size)[inboundpacket.read], sizeof(inboundpacket.size) - inboundpacket.read, 0);
int readBytes = recv(socket, &((char*)&inboundpacket.size)[inboundpacket.transferred], sizeof(inboundpacket.size) - inboundpacket.transferred, 0);
if (readBytes == SOCKET_ERROR || readBytes == 0) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
return NETWORK_DISCONNECTED;
@@ -93,15 +95,15 @@ int NetworkConnection::ReadPacket()
return NETWORK_NO_DATA;
}
}
inboundpacket.read += readBytes;
if (inboundpacket.read == sizeof(inboundpacket.size)) {
inboundpacket.transferred += readBytes;
if (inboundpacket.transferred == sizeof(inboundpacket.size)) {
inboundpacket.size = ntohs(inboundpacket.size);
inboundpacket.data->resize(inboundpacket.size);
}
} else {
// read packet data
if (inboundpacket.data->capacity() > 0) {
int readBytes = recv(socket, (char*)&inboundpacket.GetData()[inboundpacket.read - sizeof(inboundpacket.size)], sizeof(inboundpacket.size) + inboundpacket.size - inboundpacket.read, 0);
int readBytes = recv(socket, (char*)&inboundpacket.GetData()[inboundpacket.transferred - sizeof(inboundpacket.size)], sizeof(inboundpacket.size) + inboundpacket.size - inboundpacket.transferred, 0);
if (readBytes == SOCKET_ERROR || readBytes == 0) {
if (WSAGetLastError() != WSAEWOULDBLOCK) {
return NETWORK_DISCONNECTED;
@@ -109,9 +111,9 @@ int NetworkConnection::ReadPacket()
return NETWORK_NO_DATA;
}
}
inboundpacket.read += readBytes;
inboundpacket.transferred += readBytes;
}
if (inboundpacket.read == sizeof(inboundpacket.size) + inboundpacket.size) {
if (inboundpacket.transferred == sizeof(inboundpacket.size) + inboundpacket.size) {
return NETWORK_SUCCESS;
}
}
@@ -121,22 +123,22 @@ int NetworkConnection::ReadPacket()
int NetworkConnection::SendPacket(NetworkPacket& packet)
{
while (1) {
if (packet.read < sizeof(packet.size)) {
if (packet.transferred < sizeof(packet.size)) {
// send packet size
uint16 size = htons(packet.size);
int sentBytes = send(socket, &((char*)&size)[packet.read], sizeof(size) - packet.read, 0);
int sentBytes = send(socket, &((char*)&size)[packet.transferred], sizeof(size) - packet.transferred, 0);
if (sentBytes == SOCKET_ERROR) {
return 0;
}
packet.read += sentBytes;
packet.transferred += sentBytes;
} else {
// send packet data
int sentBytes = send(socket, (const char*)&packet.GetData()[packet.read - sizeof(packet.size)], packet.data->size(), 0);
int sentBytes = send(socket, (const char*)&packet.GetData()[packet.transferred - sizeof(packet.size)], packet.data->size(), 0);
if (sentBytes == SOCKET_ERROR) {
return 0;
}
packet.read += sentBytes;
if (packet.read == sizeof(packet.size) + packet.data->size()) {
packet.transferred += sentBytes;
if (packet.transferred == sizeof(packet.size) + packet.data->size()) {
return 1;
}
}
@@ -162,6 +164,13 @@ Network::Network()
wsa_initialized = false;
mode = NETWORK_MODE_NONE;
last_tick_sent_time = 0;
command_handlers.resize(NETWORK_COMMAND_MAX, 0);
command_handlers[NETWORK_COMMAND_AUTH] = &Network::CommandHandler_AUTH;
command_handlers[NETWORK_COMMAND_MAP] = &Network::CommandHandler_MAP;
command_handlers[NETWORK_COMMAND_CHAT] = &Network::CommandHandler_CHAT;
command_handlers[NETWORK_COMMAND_GAMECMD] = &Network::CommandHandler_GAMECMD;
command_handlers[NETWORK_COMMAND_TICK] = &Network::CommandHandler_TICK;
command_handlers[NETWORK_COMMAND_PLAYER] = &Network::CommandHandler_PLAYER;
}
Network::~Network()
@@ -335,17 +344,6 @@ void Network::Update()
}
}
void Network::Send_TICK()
{
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_TICK);
packet->Write((uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32));
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
}
void Network::Send_MAP()
{
if (GetMode() == NETWORK_MODE_SERVER) {
@@ -358,9 +356,7 @@ void Network::Send_MAP()
for (int i = 0; i < size; i += chunksize) {
int datasize = min(chunksize, size - i);
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_MAP);
packet->Write((uint32)size);
packet->Write((uint32)i);
*packet << (uint32)NETWORK_COMMAND_MAP << (uint32)size << (uint32)i;
packet->Write(&buffer[i], datasize);
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
@@ -373,7 +369,7 @@ void Network::Send_MAP()
void Network::Send_CHAT(const char* text)
{
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_CHAT);
*packet << (uint32)NETWORK_COMMAND_CHAT;
packet->Write((uint8*)text, strlen(text) + 1);
if (GetMode() == NETWORK_MODE_SERVER) {
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
@@ -387,15 +383,7 @@ void Network::Send_CHAT(const char* text)
void Network::Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp)
{
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
packet->Write((uint32)NETWORK_COMMAND_GAMECMD);
packet->Write((uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32));
packet->Write((uint32)eax);
packet->Write((uint32)ebx | (1 << 31));
packet->Write((uint32)ecx);
packet->Write((uint32)edx);
packet->Write((uint32)esi);
packet->Write((uint32)edi);
packet->Write((uint32)ebp);
*packet << (uint32)NETWORK_COMMAND_GAMECMD << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) << eax << (ebx | (1 << 31)) << ecx << edx << esi << edi << ebp;
if (GetMode() == NETWORK_MODE_SERVER) {
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
@@ -405,6 +393,16 @@ void Network::Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint3
}
}
void Network::Send_TICK()
{
std::unique_ptr<NetworkPacket> packet = NetworkPacket::AllocatePacket();
*packet << (uint32)NETWORK_COMMAND_TICK << (uint32)RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32);
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
(*it)->QueuePacket(NetworkPacket::DuplicatePacket(*packet));
}
}
bool Network::ProcessConnection(NetworkConnection& connection)
{
int packetStatus;
@@ -441,60 +439,10 @@ bool Network::ProcessConnection(NetworkConnection& connection)
void Network::ProcessPacket(NetworkPacket& packet)
{
uint32 *args;
int command;
rct_news_item newsItem;
args = (uint32*)packet.GetData();
command = args[0];
switch (command) {
case NETWORK_COMMAND_AUTH:{
}break;
case NETWORK_COMMAND_MAP:{
uint32 size = args[1];
uint32 offset = args[2];
if (offset > 0x600000) {
// too big
} else {
int chunksize = packet.size - 4 - 4 - 4;
if (offset + chunksize > chunk_buffer.size()) {
chunk_buffer.resize(offset + chunksize);
}
memcpy(&chunk_buffer[offset], (void*)&packet.GetData()[4 + 4 + 4], chunksize);
if (offset + chunksize == size) {
printf("Loading new map from network...\n");
SDL_RWops* rw = SDL_RWFromMem(&chunk_buffer[0], size);
if (game_load_sv6(rw)) {
game_load_init();
}
SDL_RWclose(rw);
}
}
}break;
case NETWORK_COMMAND_CHAT:{
newsItem.type = NEWS_ITEM_BLANK;
newsItem.flags = 1;
newsItem.assoc = 0;
newsItem.ticks = 0;
newsItem.month_year = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16);
newsItem.day = ((days_in_month[(newsItem.month_year & 7)] * RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16)) >> 16) + 1;
newsItem.colour = FORMAT_TOPAZ;
strcpy(newsItem.text, (char*)&packet.GetData()[4]);
news_item_add_to_queue_custom(&newsItem);
}break;
case NETWORK_COMMAND_GAMECMD:{
if (GetMode() == NETWORK_MODE_SERVER) {
Send_GAMECMD(args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
game_do_command(args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
} else {
GameCommand gc = GameCommand(&args[1]);
game_command_queue.insert(gc);
}
}break;
case NETWORK_COMMAND_TICK:{
server_tick = args[1];
}break;
uint32 command;
packet >> command;
if (command < NETWORK_COMMAND_MAX && command_handlers[command]) {
(this->*command_handlers[command])(packet);
}
packet.Clear();
}
@@ -531,6 +479,77 @@ void Network::PrintError()
LocalFree(s);
}
int Network::CommandHandler_AUTH(NetworkPacket& packet)
{
return 1;
}
int Network::CommandHandler_MAP(NetworkPacket& packet)
{
uint32 size, offset;
packet >> size >> offset;
if (offset > 0x600000) {
// too big
return 0;
} else {
int chunksize = packet.size - packet.read;
if (offset + chunksize > chunk_buffer.size()) {
chunk_buffer.resize(offset + chunksize);
}
memcpy(&chunk_buffer[offset], (void*)packet.Read(chunksize), chunksize);
if (offset + chunksize == size) {
printf("Loading new map from network...\n");
SDL_RWops* rw = SDL_RWFromMem(&chunk_buffer[0], size);
if (game_load_sv6(rw)) {
game_load_init();
}
SDL_RWclose(rw);
}
}
return 1;
}
int Network::CommandHandler_CHAT(NetworkPacket& packet)
{
rct_news_item newsItem;
newsItem.type = NEWS_ITEM_BLANK;
newsItem.flags = 1;
newsItem.assoc = 0;
newsItem.ticks = 0;
newsItem.month_year = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16);
newsItem.day = ((days_in_month[(newsItem.month_year & 7)] * RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16)) >> 16) + 1;
newsItem.colour = FORMAT_TOPAZ;
strcpy(newsItem.text, (char*)packet.Read(packet.size - packet.read));
news_item_add_to_queue_custom(&newsItem);
return 1;
}
int Network::CommandHandler_GAMECMD(NetworkPacket& packet)
{
uint32 tick;
uint32 args[7];
packet >> tick >> args[0] >> args[1] >> args[2] >> args[3] >> args[4] >> args[5] >> args[6];
if (GetMode() == NETWORK_MODE_SERVER) {
Send_GAMECMD(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
game_do_command(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
} else {
GameCommand gc = GameCommand(tick, args);
game_command_queue.insert(gc);
}
return 1;
}
int Network::CommandHandler_TICK(NetworkPacket& packet)
{
packet >> server_tick;
return 1;
}
int Network::CommandHandler_PLAYER(NetworkPacket& packet)
{
return 1;
}
int network_init()
{
return gNetwork.Init();

View File

@@ -42,6 +42,15 @@ extern "C" {
#include "../platform/platform.h"
}
template <std::size_t size>
struct ByteSwapT { };
template <>
struct ByteSwapT<2> { static uint16 SwapBE(uint16 value) { return SDL_SwapBE16(value); } };
template <>
struct ByteSwapT<4> { static uint32 SwapBE(uint32 value) { return SDL_SwapBE32(value); } };
template <typename T>
T ByteSwapBE(const T& value) { return ByteSwapT<sizeof(T)>::SwapBE(value); }
class NetworkPacket
{
public:
@@ -49,13 +58,17 @@ public:
static std::unique_ptr<NetworkPacket> AllocatePacket();
static std::unique_ptr<NetworkPacket> DuplicatePacket(NetworkPacket& packet);
uint8* GetData();
template <class T>
void Write(T value) { uint8* bytes = (uint8*)&value; data->insert(data->end(), bytes, bytes + sizeof(value)); }
template <typename T>
NetworkPacket& operator<<(T value) { T swapped = ByteSwapBE(value); uint8* bytes = (uint8*)&swapped; data->insert(data->end(), bytes, bytes + sizeof(value)); return *this; }
void Write(uint8* bytes, unsigned int size) { data->insert(data->end(), bytes, bytes + size); }
template <typename T>
NetworkPacket& operator>>(T& value) { value = ByteSwapBE(*((T*)&GetData()[read])); read += sizeof(value); return *this; };
uint8* Read(unsigned int size) { uint8* data = &GetData()[read]; read += size; return data; };
void Clear();
uint16 size;
std::shared_ptr<std::vector<uint8>> data;
int transferred;
int read;
};
@@ -94,10 +107,10 @@ public:
uint32 GetServerTick();
void Update();
void Send_TICK();
void Send_MAP();
void Send_CHAT(const char* text);
void Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
void Send_TICK();
private:
bool ProcessConnection(NetworkConnection& connection);
@@ -109,7 +122,7 @@ private:
struct GameCommand
{
GameCommand(uint32 args[8]) { tick = args[0], eax = args[1], ebx = args[2], ecx = args[3], edx = args[4], esi = args[5], edi = args[6], ebp = args[7]; };
GameCommand(uint32 t, uint32* args) { tick = t, eax = args[0], ebx = args[1], ecx = args[2], edx = args[3], esi = args[4], edi = args[5], ebp = args[6]; };
uint32 tick;
uint32 eax, ebx, ecx, edx, esi, edi, ebp;
bool operator<(const GameCommand& comp) const {
@@ -127,6 +140,15 @@ private:
std::list<std::unique_ptr<NetworkConnection>> client_connection_list;
std::multiset<GameCommand> game_command_queue;
std::vector<uint8> chunk_buffer;
private:
std::vector<int (Network::*)(NetworkPacket& packet)> command_handlers;
int CommandHandler_AUTH(NetworkPacket& packet);
int CommandHandler_MAP(NetworkPacket& packet);
int CommandHandler_CHAT(NetworkPacket& packet);
int CommandHandler_GAMECMD(NetworkPacket& packet);
int CommandHandler_TICK(NetworkPacket& packet);
int CommandHandler_PLAYER(NetworkPacket& packet);
};
extern "C" {