#include "libs/enet/include/enet.h" #include "data/HashMap.h" #include "network/ENet.h" #include "network/Server.h" #include "utils/Logger.h" static_assert(sizeof(enet_uint16) == sizeof(Server::Port), "client port has wrong type"); static ENetHost* server; static HashMap clients; static Server::Client idCounter = 1; static Server::OnConnect onConnect = [](Server::Client) {}; static Server::OnDisconnect onDisconnect = [](Server::Client) {}; static Server::OnPacket onPacket = [](Server::Client, InPacket&) {}; Error Server::start(Port port, int maxClients) { if(server != nullptr) { return {"already started"}; } else if(ENet::add()) { return {"cannot initialize enet"}; } ENetAddress address; memset(&address, 0, sizeof(ENetAddress)); address.host = ENET_HOST_ANY; address.port = port; server = enet_host_create(&address, maxClients, 3, 0, 0); if(server == nullptr) { ENet::remove(); return {"cannot create enet server host"}; } return {}; } void Server::stop() { if(server == nullptr) { return; } for(ENetPeer* peer : clients.values()) { enet_peer_reset(peer); } enet_host_destroy(server); server = nullptr; ENet::remove(); } void writeId(ENetPeer* peer, Server::Client id) { static_assert(sizeof(peer->data) >= sizeof(id), "private data not big enough for id"); memcpy(&(peer->data), &id, sizeof(id)); } Server::Client getId(ENetPeer* peer) { Server::Client id = -1; memcpy(&id, &(peer->data), sizeof(id)); return id; } static void handleConnect(ENetEvent& e) { Server::Client id = idCounter++; if(clients.tryEmplace(id, e.peer)) { LOG_WARNING("id is connected twice"); return; } writeId(e.peer, id); onConnect(id); } static void handlePacket(ENetEvent& e) { if(e.peer->data == nullptr) { LOG_WARNING("client without data sent package"); return; } Server::Client id = getId(e.peer); InPacket in(e.packet->data, e.packet->dataLength); onPacket(id, in); } static void handleDisconnect(ENetEvent& e) { if(e.peer->data == nullptr) { LOG_WARNING("client without data disconnected"); return; } Server::Client id = getId(e.peer); onDisconnect(id); if(clients.remove(id)) { LOG_WARNING("removed non existing client"); } } void Server::tick() { if(server == nullptr) { return; } ENetEvent e; while(enet_host_service(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 Buffer& buffer, int index) { constexpr enet_uint32 flags[] = {ENET_PACKET_FLAG_RELIABLE, 0, ENET_PACKET_FLAG_UNSEQUENCED}; return enet_packet_create(buffer, buffer.getLength(), flags[index]); } void Server::send(const OutPacket& p, PacketSendMode mode) { if(server != nullptr) { int index = static_cast(mode); enet_host_broadcast(server, index, fromBuffer(p.buffer, index)); } } void Server::send(Server::Client client, const OutPacket& p, PacketSendMode mode) { if(server == nullptr) { return; } ENetPeer** peer = clients.search(client); if(peer != nullptr) { int index = static_cast(mode); enet_peer_send(*peer, index, fromBuffer(p.buffer, index)); } } void Server::disconnect(Client client) { ENetPeer** peer = clients.search(client); if(peer != nullptr) { enet_peer_disconnect(*peer, 0); } } void Server::setConnectHandler(OnConnect oc) { onConnect = oc; } void Server::setDisconnectHandler(OnDisconnect od) { onDisconnect = od; } void Server::setPacketHandler(OnPacket op) { onPacket = op; } void Server::resetHandler() { onConnect = [](Server::Client) {}; onDisconnect = [](Server::Client) {}; onPacket = [](Server::Client, InPacket&) {}; }