terom@185: #ifndef NETWORK_OBJECT_HH terom@185: #define NETWORK_OBJECT_HH terom@185: terom@400: /** terom@400: * @file terom@400: * terom@400: * Object-based network protocol for use with NetworkSession terom@400: */ terom@400: terom@186: #include "Session.hh" terom@186: #include "Node.hh" terom@186: #include "../Logger.hh" terom@185: terom@185: #include terom@185: terom@290: /** terom@290: * A NetworkObject's ID is a 32-bit integer terom@290: */ terom@185: typedef uint32_t NetworkObjectID; terom@290: terom@290: /** terom@290: * A NetworkObject's message type is a 16-bit integer terom@290: */ terom@185: typedef uint16_t NetworkMessageID; terom@185: terom@185: // forward-declare terom@185: class NetworkObject; terom@185: class NetworkObject_Client; terom@185: class NetworkObject_Server; terom@185: terom@290: /** terom@290: * A NetworkObjectController contains a mapping of NetworkObjectID -> NetworkObject, and handles the terom@290: * messages received on our channel from the NetworkSession. terom@290: * terom@290: * Additionally, this provides methods to read/write NetworkObject references from/to a NetworkPacket terom@290: */ terom@185: class NetworkObjectController { terom@185: friend class NetworkObject; terom@185: friend class NetworkObject_Server; terom@185: friend class NetworkObject_Client; terom@431: terom@431: // XXX: needs to access session and channel_id terom@431: friend class NetworkMessage; terom@185: terom@185: private: terom@290: /** terom@290: * The NetworkSession that we use terom@290: */ terom@185: NetworkSession &session; terom@290: terom@290: /** terom@290: * The NetworkChannelID that we use to communicate terom@290: */ terom@185: NetworkChannelID channel_id; terom@290: terom@290: /** terom@290: * Our map of NetworkObjectID -> NetworkObject terom@290: */ terom@185: std::map objects; terom@290: terom@185: CL_Slot slot_message; terom@185: terom@185: protected: terom@290: /** terom@290: * Construct a NetworkObjectController to use the given NetworkSession and NetworkChannelID terom@290: */ terom@185: NetworkObjectController (NetworkSession &session, NetworkChannelID channel_id); terom@185: terom@185: private: terom@290: /** terom@290: * Our NetworkSession::sig_chan_message handler terom@290: * terom@290: * Reads the NetworkObjectID and NetworkMessageID from the packet, and then either calls handle_create or terom@290: * NetworkObject::handle_packet. terom@290: */ terom@200: void on_message (NetworkPacketInput &pkt, NetworkNode *node); terom@185: terom@185: protected: terom@290: /** terom@290: * Abstract method called by on_message if we recieve a message for an unknown NetworkObjectID terom@290: * terom@290: * @param obj_id the unknown NetworkObjectID terom@290: * @param msg_id the packet's NetworkMessageID terom@290: * @param pkt the packet itself, with the header read terom@290: * @param node the node that we got this packet from terom@290: */ terom@200: virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) = 0; terom@276: terom@276: public: terom@276: /** terom@328: * Read an NetworkObjectID from the given packet, and return the corresponding NetworkObject, or NULL if: terom@328: * * it was zero terom@328: * * we don't know the object (should this thrown an exception instead?) terom@328: * terom@328: * @return the NetworkObject* corresponding to the NetworkObjectID in the packet, or NULL if zero/not found terom@276: */ terom@276: NetworkObject* read_object (NetworkPacketInput &pkt); terom@185: }; terom@185: terom@290: /** terom@290: * A NetworkObjectController intended for use with a server. terom@290: * terom@290: * This has an id_pool that new NetworkObjectIDs can be generated from, and this doesn't accept unknown terom@290: * NetworkObjectIDs from clients. terom@290: */ terom@185: class NetworkObject_ServerController : public NetworkObjectController { terom@185: friend class NetworkObject_Server; terom@185: terom@185: private: terom@290: /** terom@290: * The id_pool that we use to generate NetworkObjectIDs for new NetworkObject's terom@290: */ terom@185: NetworkObjectID id_pool; terom@185: terom@185: public: terom@290: /** terom@290: * @see NetworkObjectController terom@290: */ terom@185: NetworkObject_ServerController (NetworkSession &session, NetworkChannelID channel_id); terom@185: terom@185: protected: terom@290: /** terom@290: * Get a new NetworkObjectID terom@290: */ terom@185: NetworkObjectID getObjectID (void); terom@290: terom@290: /** terom@290: * Throw an error, as we don't accept unknown NetworkObjects from clients terom@290: */ terom@200: virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node); terom@185: }; terom@185: terom@290: /** terom@290: * A NetworkObjectController intended for use with a client. terom@290: * terom@290: * This provides two ways to handle unknown objects: override handle_create, or use sig_create terom@290: */ terom@185: class NetworkObject_ClientController : public NetworkObjectController { terom@185: friend class NetworkObject_Client; terom@185: terom@290: protected: terom@290: /** terom@290: * The server node, as returned by NetworkSession::connect terom@290: */ terom@431: NetworkNode &server; terom@290: terom@290: /** terom@290: * A mapping of NetworkMessageID -> sig_create, used by the default handle_create terom@290: */ terom@223: std::map > _map_sig_create; terom@185: terom@185: public: terom@290: /** terom@290: * Construct a NetworkObjectController using the given NetworkNode (as returned by NetworkSession::connect) as terom@290: * a server. terom@290: * terom@290: * @see NetworkObjectController terom@290: */ terom@431: NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode &server); terom@185: terom@185: protected: terom@290: /** terom@290: * Handle unknown NetworkObjectIDs by constructing a new NetworkObject_Client and calling sig_create. terom@290: * terom@290: * This can be overriden to handle this differently, e.g. to create an instance of a NetworkObject_Client terom@290: * subclass instead. terom@290: */ terom@200: virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node); terom@185: terom@185: public: terom@290: /** terom@290: * Signal triggered by default handle_create when we get a message for an unknown NetworkObject. terom@290: * The signal gets the new NetworkObject_Client, and the packet itself. terom@290: * terom@290: * @param msg_id the NetworkMessageID to handle creates for terom@290: */ terom@223: CL_Signal_v2& sig_create (NetworkMessageID msg_id) { return _map_sig_create[msg_id]; } terom@185: }; terom@185: terom@290: /** terom@290: * Base class of NetworkObject_(Client/Server) terom@290: * terom@290: * A NetworkObject has an NetworkObjectID, and can handle packets to/from this object terom@290: */ terom@185: class NetworkObject { terom@185: friend class NetworkObjectController; terom@185: friend std::ostream& operator<< (std::ostream &s, const NetworkObject &obj); terom@185: terom@431: // XXX: needs to access controller and obj_id terom@431: friend class NetworkMessage; terom@431: terom@185: protected: terom@290: /** terom@337: * Generic controller terom@337: */ terom@337: NetworkObjectController &controller; terom@337: terom@337: /** terom@290: * This object's object id terom@290: */ terom@185: NetworkObjectID obj_id; terom@185: terom@185: protected: terom@290: /** terom@290: * Construct a NetworkObject using the given controller and object id terom@290: * terom@290: * @param controller the NetworkObjectController (subclass) terom@290: * @param obj_id our NetworkObjectID terom@290: */ terom@185: NetworkObject (NetworkObjectController &controller, NetworkObjectID obj_id); terom@185: terom@290: /** terom@337: * Removes this object from the controller's objects list terom@337: */ terom@337: ~NetworkObject (void); terom@337: terom@337: /** terom@290: * Abstract method to handle packets sent to this object terom@290: * terom@290: * @param node the NetworkNode that sent this packet to us terom@290: * @param msg_id the packet's NetworkMessageID terom@290: * @param pkt the packet itself, with the headers read terom@290: */ terom@200: virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) = 0; terom@185: }; terom@185: terom@290: /** terom@290: * Formats the object as " ">" terom@290: */ terom@185: std::ostream& operator<< (std::ostream &s, const NetworkObject &obj); terom@185: terom@290: /** terom@290: * A server-side NetworkObject terom@290: */ terom@185: class NetworkObject_Server : public NetworkObject { terom@185: friend class NetworkObject_ServerController; terom@185: terom@290: protected: terom@290: /** terom@290: * The NetworkObject_ServerController terom@290: */ terom@185: NetworkObject_ServerController &controller; terom@290: terom@290: /** terom@290: * Mapping of NetworkMessageID -> sig_message used for received messages terom@290: */ terom@200: std::map > _map_sig_message; terom@185: terom@185: public: terom@290: /** terom@290: * @see NetworkObject terom@290: */ terom@185: NetworkObject_Server (NetworkObject_ServerController &controller); terom@185: terom@185: protected: terom@290: /** terom@290: * Handle an incoming packet by invoking the appopriate sig_message terom@290: * terom@290: * @see NetworkObject::handlePacket terom@290: */ terom@200: virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt); terom@185: terom@185: public: terom@290: /** terom@290: * Triggered whenever we receive a message of the given type on this object, giving the node that sent it and the terom@290: * packet itself terom@290: * terom@290: * @param msg_id the NetworkMessageID to handle terom@290: */ terom@200: CL_Signal_v2& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; } terom@185: }; terom@185: terom@290: /** terom@290: * A client-side NetworkObject terom@290: */ terom@185: class NetworkObject_Client : public NetworkObject { terom@185: friend class NetworkObject_ClientController; terom@185: terom@290: protected: terom@290: /** terom@290: * Our NetworkObject_ClientController terom@290: */ terom@185: NetworkObject_ClientController &controller; terom@290: terom@290: /** terom@290: * Our mapping of NetworkMessageID -> sig_message, used to handle received packets terom@290: */ terom@200: std::map > _map_sig_message; terom@185: terom@185: protected: terom@290: /** terom@290: * @see NetworkObject terom@290: */ terom@185: NetworkObject_Client (NetworkObject_ClientController &controller, NetworkObjectID id); terom@185: terom@290: /** terom@290: * Handle an incoming packet by invoking the appropriate sig_message. terom@290: * terom@290: * This assumes that packets only come from the server terom@290: * terom@290: * @see NetworkObject::handlePacket terom@290: */ terom@200: virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt); terom@185: terom@185: public: terom@290: /** terom@290: * Triggered whenever we receive a message of the given type on this object from the server. terom@290: * terom@290: * @param msg_id the NetworkMessageID to handle terom@290: */ terom@200: CL_Signal_v1& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; } terom@185: }; terom@185: terom@185: #endif /* NETWORK_OBJECT_HH */