separate sockaddr stuff out of NetworkAddress... now called NetworkEndpoint
#ifndef NETWORK_SESSION_HH
#define NETWORK_SESSION_HH
#include <map>
#include <stdint.h>
// forward-declare
class NetworkSession;
/**
* A NetworkSession puts each packet onto a specific channel, which can the be used to run multiple different modules
* on top of a single session.
*
* NetworkChannelID zero is reserved for internal NetworkSession use
*/
typedef uint16_t NetworkChannelID;
/**
* Size of a NetworkSession's packet header:
* uint16 channel_id
*/
const size_t NETWORK_SESSION_HEADER_SIZE = sizeof(uint16_t);
#include "TCP.hh"
#include "UDP.hh"
#include "Node.hh"
/**
* A NetworkSession provides TCP/UDP Server and Client functionality, representing remote NetworkSessions with
* NetworkNodes. A NetworkSession can then communicate with its NetworkNodes using TCP or UDP NetworkPackets.
*/
class NetworkSession {
friend class NetworkNode;
private:
/**
* The application's magic ID
*/
uint64_t magic;
/**
* Our TCP server, if we're in listen() mode
*/
NetworkTCPServer *tcp_srv;
/**
* Our UDP server, if we're in listen() mode
*/
NetworkUDP *udp_srv;
/**
* Our UDP client, if we're in connect() mode
*/
NetworkUDP *udp_client;
CL_SlotContainer slots;
/**
* A map of NetworkAddress -> NetworkNode, manipulated when TCP connections are established/broken down,
* and used to map UDP packets to their NetworkNode
*/
std::map<NetworkAddress, NetworkNode*> nodes;
/**
* A map of NetworkChannelID -> signal, used to signal our users when we receieve packets
*/
std::map<NetworkChannelID, CL_Signal_v2<NetworkPacketInput&, NetworkNode *> > _map_sig_chan_message;
public:
/**
* Construct an idle NetworkSession using the given application magic, which should be unique to tell different
* applications apart from each other.
*
* @param magic unique application magic
*/
NetworkSession (uint64_t magic);
/**
* Have the NetworkSession enter server mode, listening on the given address using both TCP and UDP
*
* @param addr local address to listen on
*/
void listen (const NetworkEndpoint &addr);
/**
* Have the NetworkSession enter client mode, establishing a TCP connection to the server, and then allocating
* an UDP socket on the same local address as the TCP connection.
*
* @param addr remote address to connect to
*/
NetworkNode* connect (const NetworkEndpoint &addr);
protected:
/**
* Used to build a new NetworkNode by connect/on_tcp_client. Can be used to override what kind of NetworkNodes
* get created. Type tells what kind of node this is.
*
* @param tcp the TCP transport for this node
* @param udp the UDP socket to use for this node
* @param addr the remote address
* @param type the type of node
* @see NetworkNodeType
*/
virtual NetworkNode *build_node (NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &addr, enum NetworkNodeType type);
/**
* A NetworkNode's TCP connection has failed. Removes the node from our nodes-map (using node->getRemoteAddress)
*
* @param node the node that has disconnected
*/
void handle_disconnect (NetworkNode *node);
/**
* We have received a NetworkPacket from the given node (either TCP or UDP, we don't know)
*
* @param pkt the NetworkPacket that we received
* @param node the node that sent it
*/
void handle_message (NetworkPacketInput &pkt, NetworkNode *node);
private:
/**
* Our tcp_srv has accept()'d a new client.
*
* Create a NetworkNode using build_node and udp_srv, add it to our node-map, and trigger sig_node_connected
*/
void on_tcp_client (NetworkTCPTransport *client);
/**
* Our udp_srv has recv()'d a NetworkPacket.
*
* Map it to a NetworkNode using our node-map and call handle_message
*/
void on_udp_packet (NetworkPacketInput &pkt, const NetworkAddress &addr);
/**
* New-client signal
*/
CL_Signal_v1<NetworkNode*> _sig_node_connected;
public:
/**
* Send the given NetworkPacket to all our nodes using the given NetworkChannelID, using TCP if reliable, UDP otherwise.
*
* @param channel_id the NetworkChannelID to use
* @param pkt the NetworkPacket to send
* @param reliable Whether to use TCP or UDP
*/
void send_all (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true);
/**
* Like send_all, but do not send the packet to the specified node. If node is NULL, this behaves like
* send_all.
*
* @see send_all
*/
void send_all_except (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, const NetworkNode *node, bool reliable = true);
/**
* A new node has connected to us
*/
CL_Signal_v1<NetworkNode*>& sig_node_connected (void) { return _sig_node_connected; }
/**
* We have received a NetworkPacket from a NetworkNode on the given NetworkChannelID
*/
CL_Signal_v2<NetworkPacketInput&, NetworkNode *>& sig_chan_message (NetworkChannelID cid) { return _map_sig_chan_message[cid]; }
};
#endif /* NETWORK_SESSION_HH */