#include "core/Network.h" #define ENET_IMPLEMENTATION #include #include #include #include #include #include "ErrorSimulator.h" typedef CoreOutPacket OutPacket; void coreInitInPacket(CoreInPacket* in, const void* data, size_t n) { in->data = data; in->size = n; in->index = 0; } bool coreInPacketReadU8(CoreInPacket* in, u8* u) { return coreInPacketRead(in, u, sizeof(*u)); } bool coreInPacketReadU16(CoreInPacket* in, u16* u) { if(coreInPacketRead(in, u, sizeof(*u))) { return true; } *u = ntohs(*u); return false; } bool coreInPacketReadU32(CoreInPacket* in, u32* u) { if(coreInPacketRead(in, u, sizeof(*u))) { return true; } *u = ntohl(*u); return false; } bool coreInPacketReadI8(CoreInPacket* in, i8* i) { u8 u; if(coreInPacketReadU8(in, &u)) { return true; } *i = (i8)((i32)u - (i32)128); return false; } bool coreInPacketReadI16(CoreInPacket* in, i16* i) { u16 u; if(coreInPacketReadU16(in, &u)) { return true; } *i = (i16)((i32)u - (i32)32768); return false; } bool coreInPacketReadI32(CoreInPacket* in, i32* i) { u32 u; if(coreInPacketReadU32(in, &u)) { return true; } if(u < 2147483648) { *i = (i32)((i32)u - (i32)2147483648); } else { *i = (i32)(u - (u32)2147483648); } return false; } bool coreInPacketReadFloat(CoreInPacket* in, float* f) { u32 u; static_assert(sizeof(u) == sizeof(*f), "float and u32 size do not match"); if(coreInPacketReadU32(in, &u)) { return true; } memcpy(f, &u, sizeof(float)); return false; } size_t coreInPacketReadString(CoreInPacket* in, char* buffer, size_t n) { if(n == 0) { return 0; } u16 size; if(coreInPacketReadU16(in, &size)) { return 0; } size_t end = size; char* bufferStart = buffer; n--; while(n-- > 0 && end > 0) { end--; u8 u; if(coreInPacketReadU8(in, &u)) { *bufferStart = '\0'; break; } *(buffer++) = (char)u; } while(end-- > 0 && !coreInPacketReadU8(in, &(u8){0})) {} *buffer = '\0'; return size; } bool coreInPacketRead(CoreInPacket* in, void* buffer, size_t n) { if(in->index + n > in->size) { return true; } memcpy(buffer, in->data + in->index, n); in->index += n; return false; } void coreInitOutPacket(OutPacket* out) { coreInitBuffer(&out->data); } void coreDestroyOutPacket(OutPacket* out) { coreDestroyBuffer(&out->data); } OutPacket* coreOutPacketWriteU8(OutPacket* out, u8 u) { coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteU16(OutPacket* out, u16 u) { u = htons(u); coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteU32(OutPacket* out, u32 u) { u = htonl(u); coreAddSizedBufferData(&out->data, &u, sizeof(u)); return out; } OutPacket* coreOutPacketWriteI8(OutPacket* out, i8 i) { if(i < 0) { return coreOutPacketWriteU8(out, (u8)((i32)i + (i32)128)); } return coreOutPacketWriteU8(out, (u8)((u32)i + (u32)128)); } OutPacket* coreOutPacketWriteI16(OutPacket* out, i16 i) { if(i < 0) { return coreOutPacketWriteU16(out, (u16)((i32)i + (i32)32768)); } return coreOutPacketWriteU16(out, (u16)((u32)i + (u32)32768)); } OutPacket* coreOutPacketWriteI32(OutPacket* out, i32 i) { if(i < 0) { return coreOutPacketWriteU32(out, (u32)(i + (i32)2147483648)); } return coreOutPacketWriteU32(out, (u32)((u32)i + (u32)2147483648)); } OutPacket* coreOutPacketWriteFloat(OutPacket* out, float f) { u32 u; static_assert(sizeof(u) == sizeof(f), "float and u32 size do not match"); memcpy(&u, &f, sizeof(float)); return coreOutPacketWriteU32(out, u); } OutPacket* coreOutPacketWriteString(OutPacket* out, const char* s) { size_t marker = out->data.size; coreOutPacketWriteU16(out, 0); size_t end = 0; while(end < 65534 && *s != '\0') { coreOutPacketWriteU8(out, (u8)(*(s++))); end++; } coreOutPacketWriteU8(out, 0); end++; size_t endMarker = out->data.size; out->data.size = marker; coreOutPacketWriteU16(out, (u16)end); out->data.size = endMarker; return out; } OutPacket* coreOutPacketWrite(OutPacket* out, const void* buffer, size_t n) { coreAddSizedBufferData(&out->data, buffer, n); return out; } static int enetCounter = 0; static bool addENet(void) { if(enetCounter == 0 && CORE_FAIL(enet_initialize() != 0, true)) { return true; } enetCounter++; return false; } static void removeENet(void) { if(enetCounter > 0 && --enetCounter == 0) { enet_deinitialize(); } } static_assert(sizeof(enet_uint16) == sizeof(CorePort), "port has wrong type"); static void voidVoidDummy(void) { } static void voidInPacketDummy(CoreInPacket*) { } typedef struct { ENetHost* client; ENetPeer* connection; CoreClientOnConnect onConnect; CoreClientOnDisconnect onDisconnect; CoreClientOnPacket onPacket; int connectTicks; int connectTimeoutTicks; int disconnectTicks; int disconnectTimeoutTicks; } Client; static Client client = { nullptr, nullptr, voidVoidDummy, voidVoidDummy, voidInPacketDummy, 0, 0, 0, 0}; bool coreClientStart(void) { if(client.client != nullptr) { CORE_LOG_WARNING("Client already started"); return true; } else if(addENet()) { CORE_LOG_ERROR("Client cannot initialize enet"); return true; } client.client = CORE_FAIL(enet_host_create(nullptr, 1, 2, 0, 0), nullptr); if(client.client == nullptr) { coreClientStop(); CORE_LOG_ERROR("Cannot create enet client host"); return true; } return false; } void coreClientStop(void) { if(client.connection != nullptr) { client.onDisconnect(); enet_peer_disconnect_now(client.connection, 0); client.connection = nullptr; } if(client.client != nullptr) { enet_host_destroy(client.client); client.client = nullptr; } removeENet(); client.connectTicks = 0; client.disconnectTicks = 0; } bool coreClientConnect(const char* server, CorePort port, int timeoutTicks) { if(client.client == nullptr) { CORE_LOG_WARNING("Client not started"); return true; } else if(client.connection != nullptr) { CORE_LOG_WARNING("Connection already exists"); return true; } ENetAddress address = {0}; enet_address_set_host(&address, server); address.port = port; client.connection = CORE_FAIL(enet_host_connect(client.client, &address, 3, 0), nullptr); if(client.connection == nullptr) { CORE_LOG_ERROR("Cannot create connection"); return true; } client.connectTicks = 1; client.connectTimeoutTicks = timeoutTicks; return false; } void coreClientTimeout(u32 timeout, u32 timeoutMin, u32 timeoutMax) { if(client.connection != nullptr) { enet_peer_timeout(client.connection, timeout, timeoutMin, timeoutMax); } } void coreClientDisconnect(int timeoutTicks) { if(client.connection == nullptr) { return; } client.connectTicks = 0; enet_peer_disconnect(client.connection, 0); client.disconnectTicks = 1; client.disconnectTimeoutTicks = timeoutTicks; } void coreClientSend(const OutPacket* p, CorePacketSendMode mode) { if(client.client == nullptr || client.connection == nullptr || client.connectTicks >= 0) { return; } static const enet_uint32 flags[] = {ENET_PACKET_FLAG_RELIABLE, 0, ENET_PACKET_FLAG_UNSEQUENCED}; enet_uint8 i = (enet_uint8)mode; enet_peer_send(client.connection, i, enet_packet_create(p->data.buffer, p->data.size, flags[i])); } static void tickClientEvents(void) { ENetEvent e; while(enet_host_service(client.client, &e, 0) >= 0) { switch(e.type) { case ENET_EVENT_TYPE_CONNECT: client.connectTicks = -1; client.onConnect(); break; case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT: client.disconnectTicks = 0; client.connectTicks = 0; client.onDisconnect(); client.connection = nullptr; break; case ENET_EVENT_TYPE_RECEIVE: { CoreInPacket in; coreInitInPacket(&in, e.packet->data, e.packet->dataLength); client.onPacket(&in); enet_packet_destroy(e.packet); break; } case ENET_EVENT_TYPE_NONE: return; } } } void coreClientTick(void) { if(client.client == nullptr) { return; } tickClientEvents(); if(client.connectTicks >= 1 && ++client.connectTicks > client.connectTimeoutTicks) { client.connectTicks = 0; coreClientDisconnect(client.connectTimeoutTicks); } if(client.disconnectTicks >= 1 && ++client.disconnectTicks > client.disconnectTimeoutTicks) { client.disconnectTicks = 0; client.onDisconnect(); if(client.connection != nullptr) { enet_peer_reset(client.connection); client.connection = nullptr; } } } void coreClientSetConnectHandler(CoreClientOnConnect oc) { client.onConnect = oc == nullptr ? voidVoidDummy : oc; } void coreClientSetDisconnectHandler(CoreClientOnDisconnect od) { client.onDisconnect = od == nullptr ? voidVoidDummy : od; } void coreClientSetPacketHandler(CoreClientOnPacket op) { client.onPacket = op == nullptr ? voidInPacketDummy : op; } void coreClientResetHandler(void) { client.onConnect = voidVoidDummy; client.onDisconnect = voidVoidDummy; client.onPacket = voidInPacketDummy; } bool coreClientIsConnecting(void) { return client.connectTicks >= 1; } bool coreClientIsConnected(void) { return client.connectTicks < 0; } static void voidClientDummy(CoreClient) { } static void voidClientInPacketDummy(CoreClient, CoreInPacket*) { } typedef struct { ENetHost* server; CoreHashMap clients; // CoreClient -> ENetPeer* CoreClient idCounter; CoreServerOnConnect onConnect; CoreServerOnDisconnect onDisconnect; CoreServerOnPacket onPacket; } Server; static Server server = { nullptr, {0}, 1, voidClientDummy, voidClientDummy, voidClientInPacketDummy}; bool coreServerStart(CorePort port, size_t maxClients) { if(maxClients <= 0) { CORE_LOG_ERROR("Invalid max client amount"); return true; } else if(server.server != nullptr) { CORE_LOG_WARNING("Server already started"); return true; } else if(addENet()) { CORE_LOG_ERROR("Server cannot initialize enet"); return true; } ENetAddress address = {.host = ENET_HOST_ANY, .port = port}; server.server = CORE_FAIL(enet_host_create(&address, maxClients, 3, 0, 0), nullptr); if(server.server == nullptr) { coreServerStop(); CORE_LOG_ERROR("Cannot create enet server host"); return true; } coreInitHashMap(&server.clients, sizeof(CoreClient), sizeof(ENetPeer*)); return false; } void coreServerStop(void) { if(server.server != nullptr) { CoreHashMapIterator i; coreInitHashMapIterator(&i, &server.clients); while(coreHashMapHasNext(&i)) { CoreHashMapNode* n = coreHashMapNext(&i); enet_peer_reset(coreHashMapValue(n, ENetPeer*)); } enet_host_destroy(server.server); server.server = nullptr; coreDestroyHashMap(&server.clients); } removeENet(); } static void writeId(ENetPeer* peer, CoreClient id) { static_assert(sizeof(peer->data) >= sizeof(id), "private data not big enough for id"); memcpy(&(peer->data), &id, sizeof(id)); } static CoreClient getId(ENetPeer* peer) { CoreClient id = -1; memcpy(&id, &(peer->data), sizeof(id)); return id; } static void handleConnect(ENetEvent* e) { CoreClient id = server.idCounter++; if(coreHashMapContains(&server.clients, CoreClient, id)) { CORE_LOG_WARNING("Id is connected twice"); return; } coreHashMapPut(&server.clients, CoreClient, id, ENetPeer*, e->peer); writeId(e->peer, id); server.onConnect(id); } static void handlePacket(ENetEvent* e) { if(e->peer->data == nullptr) { CORE_LOG_WARNING("Client without data sent package"); return; } CoreClient id = getId(e->peer); CoreInPacket in; coreInitInPacket(&in, e->packet->data, e->packet->dataLength); server.onPacket(id, &in); } static void handleDisconnect(ENetEvent* e) { if(e->peer->data == nullptr) { CORE_LOG_WARNING("Client without data disconnected"); return; } CoreClient id = getId(e->peer); server.onDisconnect(id); if(!coreHashMapRemove(&server.clients, CoreClient, id)) { CORE_LOG_WARNING("Removed non existing client"); } } void coreServerTick(void) { if(server.server == nullptr) { return; } ENetEvent e; while(enet_host_service(server.server, &e, 0) > 0) { switch(e.type) { case ENET_EVENT_TYPE_CONNECT: handleConnect(&e); break; case ENET_EVENT_TYPE_RECEIVE: handlePacket(&e); enet_packet_destroy(e.packet); break; case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: case ENET_EVENT_TYPE_DISCONNECT: handleDisconnect(&e); break; case ENET_EVENT_TYPE_NONE: return; } } } static ENetPacket* fromBuffer(const CoreBuffer* buffer, enet_uint8 index) { static const enet_uint32 flags[] = {ENET_PACKET_FLAG_RELIABLE, 0, ENET_PACKET_FLAG_UNSEQUENCED}; return enet_packet_create(buffer->buffer, buffer->size, flags[index]); } void coreServerSendAll(const CoreOutPacket* p, CorePacketSendMode mode) { if(server.server != nullptr) { enet_uint8 index = (enet_uint8)mode; enet_host_broadcast(server.server, index, fromBuffer(&p->data, index)); } } void coreServerSend(CoreClient clientId, const CoreOutPacket* p, CorePacketSendMode mode) { if(server.server == nullptr) { return; } ENetPeer** peer = coreHashMapSearchPointer(&server.clients, &clientId); if(peer != nullptr) { enet_uint8 index = (enet_uint8)mode; enet_peer_send(*peer, index, fromBuffer(&p->data, index)); } } void coreServerDisconnect(CoreClient clientId) { if(server.server == nullptr) { return; } ENetPeer** peer = coreHashMapSearchPointer(&server.clients, &clientId); if(peer != nullptr) { enet_peer_disconnect(*peer, 0); } } void coreServerSetConnectHandler(CoreServerOnConnect oc) { server.onConnect = oc == nullptr ? voidClientDummy : oc; } void coreServerSetDisconnectHandler(CoreServerOnDisconnect od) { server.onDisconnect = od == nullptr ? voidClientDummy : od; } void coreServerSetPacketHandler(CoreServerOnPacket op) { server.onPacket = op == nullptr ? voidClientInPacketDummy : op; } void coreServerResetHandler(void) { server.onConnect = voidClientDummy; server.onDisconnect = voidClientDummy; server.onPacket = voidClientInPacketDummy; }