/* ZNetworkService.hpp Author: Patrick Baggett , James Russell Created: 12/03/2013 Purpose: Network functionality for ZSimulation. Operates a thread that handles sending and receiving of network data. Can be initialized as a server instance of a client instance, with the real difference being that client instances connect to a single server and servers listen for connections from multiple clients and other server instances. License: Copyright 2013, 762 Studios. */ #pragma once #ifndef __ZNETWORKSERVICE_HPP #define __ZNETWORKSERVICE_HPP #include #include #include "ZRemotePeer.hpp" #include "ZNetworkRequest.hpp" #include "ZNetworkUpdateStream.hpp" // forward decl class ZSimulation; // class decl class ZNetworkService { public: // c'tor ZNetworkService(ZSimulation& sim); /* Initializes the network system as client or server. The name is for display purposes for both client and server. If initialized as a server, the maximum number of simultaneous connections must be specified. */ bool InitAsClient(const char* name); bool InitAsServer(uint32_t maxConnections, uint16_t listenPort, const char* name); /* As a client, initializes a connection to the provided remote host. As a server, links to another server instance to share workload. Delete this when done. */ ZNetworkRequest* InitiateConnection(const char* remoteHost, uint16_t port); /* As a client, disconnects from the server (cID for server is always zero). As a server, disconnects the given connection. This is a soft disconnect that notifies the other side and waits for a response. Delete this when done. */ ZNetworkRequest* Disconnect(cID id); /* Generates the disconnection event immediately, but gives no notice to the other side. Delete this when done. */ ZNetworkRequest* ResetConnection(cID id); /* Given a connection id, gets the associated remote peer object. */ ZRemotePeer* GetPeer(cID id); /* Given the network name, gets the associated id. Returns cID(-1) if not connected to this simulation instance. */ cID GetId(const char* netname); /* Gets a list of node and host pairings on the network. If the pairing exists in both directions, then the connection is between two servers. */ void GetTopography(ZArray>& mappings); // thread control methods void SignalAndWaitShutdown(); void ThreadMain(); private: // spawns the network thread void SpawnThread(); // main thread = these four functions, in a loop void PollNetEvents(); void ProcessRequests(); void PushBufferUpdates(uint64_t dt); void PushNetworkEvents(uint64_t dt); // handlers for requests (return value indicates 'done') bool HandleRequest(ZNetworkRequest* req); bool HandleConnectRequest(ZNetworkRequest* req); bool HandleDisconnectRequest(ZNetworkRequest* req); bool HandleResetRequest(ZNetworkRequest* req); bool HandleStopNetworkRequest(ZNetworkRequest* req); // handlers for ENet Events void HandleEvent(ENetEvent* ev); // server side void ServerHandleConnectEvent(ENetEvent* ev); // initial connection event from ENet void ServerHandleDisconnectEvent(ENetEvent* ev); // disconnect event from ENet void ServerHandleReceiveEvent(ENetEvent* ev); // data received (any channel) void ServerReceiveJoinMessage(ZRemotePeer* client, const void* data, uint32_t len); // process client (or server) join message void ServerReceiveSystemChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received void ServerReceiveUpdateChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received on update channel void ServerReceiveEventChannel(ZRemotePeer* client, const void* data, uint32_t len); // data received on event channel // client side void ClientHandleConnectEvent(ENetEvent* ev); // initial connect event from ENet void ClientHandleDisconnectEvent(ENetEvent* ev); // disconnect event from ENet void ClientHandleReceiveEvent(ENetEvent* ev); // data received (any channel) void ClientRecieveJoinResponse(const void* data, uint32_t len); // process server response from join message void ClientReceiveSystemChannel(const void* data, uint32_t len); // data received on system channel void ClientReceiveUpdateChannel(const void* data, uint32_t len); // data received from server on update channel void ClientReceiveEventChannel(const void* data, uint32_t len); // data received from server on event channel // adds and removes a network node mapping void AddNode(const ZString& node, const ZString& host); void RemoveNode(const ZString& node); enum Netstate { UNINITIALIZED, // not yet initialized as client or server DISCONNECTED, // initialized as client and disconnected LISTEN, // initialized as server and listening for connections CONNECTING, // initiating low-level connection JOINING, // connected, but not yet ready to play CONNECTED // connected and ready to SIMULATE }; ZSimulation& Sim; // simulation reference ZString Name; // network name Netstate State; // state of this service SST_Thread Thread; // thread running this service bool bIsServer; // true if initialized as server bool bIsConnected; // true if connected volatile int iShouldShutdown; // shutdown flag ENetHost* Host; // enet host service (server and client) ENetPeer* RemoteServer; // as a client, this is the server (otherwise NULL) uint32_t NrConnectionsMax; // max number of connections ZRemotePeer* Connections; // all connections (as client, only a single remote peer, the server) ZMutex NodesMutex; // mutex for locking access to nodes listing ZArray> Nodes; // node name and host name pairing for all simulations on the network void* PacketBuffer; // packet data buffer, used as local copy size_t PacketBufferSize; // size of the buffer ZMutex QueueMutex; // mutex for locking access to request queue ZArray SharedRequestQueue; // network request queue ZNetworkRequest* CurrentRequest; // network request currently being processed uint32_t WaitTime; // value used to modify polling frequency ZArray PendingRequests; // queue used to process a single tick worth of requests NetworkUpdateQueue DelayedUpdates; // updates that are being delayed for artificial lag simulation NetworkEventQueue DelayedEvents; // events that are being delayed for artificial lag simulation }; #endif