#ifndef NETWORK_SESSION_HH
#define NETWORK_SESSION_HH
/**
* @file
*
* Support for a groups of clients/servers with associated TCP/UDP sockets
*/
#include <map>
#include <stdint.h>
#include <stddef.h>
// forward-declare
class NetworkSession;
/**
* 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"
#include "Group.hh"
#include "Packet.hh"
#include "Channel.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*> node_map;
/**
* A plain list of connected NetworkNode's
*/
std::list<NetworkNode*> node_list;
/**
* 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:
/**
* Get a NetworkGroup containing all connected nodes
*/
NetworkGroup all_nodes (void) {
return NetworkGroup(node_list.begin(), node_list.end(), NULL);
}
/**
* Get a NetworkGroup containing all connected nodes, but excluding the given one
*/
NetworkGroup all_nodes_except (NetworkNode &node) {
return NetworkGroup(node_list.begin(), node_list.end(), &node);
}
/**
* Write the appropriate NetworkSession header to the given packet. Can be used to prepare packets for use with
* NetworkTarget::send_raw(). The size of the header is equal to NETWORK_SESSION_HEADER_SIZE
*
* XXX: this interface needs fixing to be less procedural
*
* @param pkt the packet to write the header to
* @param channel_id the NetworkChannelID to use
*
* @see NetworkTarget::send_raw()
* @see NETWORK_SESSION_HEADER_SIZE
*/
void write_packet_header (NetworkPacketOutput &pkt, NetworkChannelID channel_id);
/**
* 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 */