src/Network/Session.hh
author Tero Marttila <terom@fixme.fi>
Sun, 02 Jun 2013 16:15:23 +0300
changeset 448 34bdf0783874
parent 431 c6d7272a164b
permissions -rw-r--r--
network: fix size_t compile errors
#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 */