src/Network/Packet.hh
author Tero Marttila <terom@fixme.fi>
Fri, 16 Jan 2009 22:03:49 +0200
changeset 400 d64bf28c4340
parent 391 59c2499fe7bb
child 417 c503e0c6a740
permissions -rw-r--r--
more documentation tweaking, all Network/ files now have a @file comment. Fix Platform.h -> Platform.hh, and Buffer.hh + Packet.cc
#ifndef NETWORK_PACKET_HH
#define NETWORK_PACKET_HH

/**
 * @file
 *
 * Provides the NetworkPackets that are used to communicate over a NetworkTCP/NetworkUDP sockets.
 */

#include "Config.hh"
#include "../Types.hh"
#include "../Error.hh"

/**
 * Base class of errors thrown by NetworkPacket* methods
 */
class NetworkPacketError : public Error {
    public:
        NetworkPacketError (const std::string &message) : Error(message) { }
};

// forward-declare for write_packet
class NetworkPacketBuffer;

/**
 * Read-interface for network packets
 */
class NetworkPacketInput {
    public:
        /**
         * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the read offset
         *
         * @param len the number of bytes to consume
         */
        virtual const void* read_ptr (size_t len) = 0;
 
        /**
         * Abstract method that copies len bytes from the packet to ptr, first testing that they exist
         */
        virtual void read (
                void *ptr,      //<<< where to copy
                size_t len      //<<< number of bytes to copy
        ) = 0;

        /**
         * Abstract method to get the number of input bytes remaining.
         *
         * @return number of input bytes still readable
         */
        virtual size_t tell_remaining (void) = 0;
      
        /**
         * Convenience function to read() and return the value of the given type
         *
         * @return T The value
         */
        template <typename T> T read_val (void);
        
        // @{
        /**
         * Collection of methods to write out simple types, these convert from network-endianness and return the value
         */

        /** 32-bit unsigned int */
        uint32_t read_uint32 (void);

        /** 16-bit unsigned int */
        uint16_t read_uint16 (void);

        /** 8-bit unsigned int */
        uint8_t read_uint8 (void);

        /** 32-bit signed int */
        int32_t read_int32 (void);
        
        /** 16-bit signed int */
        int16_t read_int16 (void);
        
        /** 8-bit signed int */
        int8_t read_int8 (void);
        
        /** 32-bit float */
        float read_float32 (void);

        // @}
        
        /**
         * Read a Vector from the packet:
         *  float32     vec_x
         *  float32     vec_y
         *
         * @return Vector (vec_x, vec_y)
         */
        Vector read_vector (void);

        /**
         * Read compressed data written with write_compressed. The given buffer must be the same size as passed to
         * write_compressed. Returns the number of bytes that were decompressed into buf.
         */
        size_t read_uncompressed (void *buf, size_t len);
};

/**
 * Write-interface for network packets
 */
class NetworkPacketOutput {
    protected:
        /**
         * Adjust size of the most recent write_ptr area of buf_len bytes to data_len bytes.
         *
         * You must not call write() between calls to write_ptr() and write_ptr_adjust(). This is only valid for the
         * most recent write_ptr()
         */
        virtual void write_ptr_adjust (size_t buf_len, size_t data_len) = 0;

    public:    
        /**
         * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the write offset
         *
         * @param len number of bytes to commit
         */
        virtual void* write_ptr (size_t len) = 0;

        /**
         * Abstract method that copies len bytes from ptr to the packet, first testing that they fit
         */
        virtual void write (
                const void *ptr,    //<<< where to copy from
                size_t len          //<<< number of bytes to copy
        ) = 0;

        /**
         * Convenience function to write() the value of the given type-value
         *
         * @param val The value
         */
        template <typename T> void write_val (const T &val);
        
        // @{        
        /**
         * Collection of methods to write out simple types, these convert the given value to network-byte-order
         */
        void write_uint32 (uint32_t val);
        void write_uint16 (uint16_t val);
        void write_uint8 (uint8_t val);
        void write_int32 (int32_t val);
        void write_int16 (int16_t val);
        void write_int8 (int8_t val);
        void write_float32 (float val);
        
        // @{ 

        /**
         * Write a vector to the packet:
         *  float32     vec_x
         *  float32     vec_y
         *
         *  @param vec a Vector(vec_x, vec_y)
         */
        void write_vector (const Vector &vec);
        
        /**
         * This write()s the contents of the given NetworkPacketBuffer to this packet.
         *
         * @param pkt the sub-packet to write()
         */
        void write_packet (const NetworkPacketBuffer &pkt);

        /**
         * This will compress the given data buffer into this packet for reading with read_compressed. The compressed
         * data will use at most write_compressed_size(len) bytes of data.
         */
        void write_compressed (const void *ptr, uint32_t len);

        /**
         * Return upper bound on packet size of compressed data, including header.
         */
        static size_t write_compressed_size (uint32_t len);
};

/**
 * Implements an in-memory seekable buffer used by NetworkPackets
 *
 * @see NetworkPacketInput
 * @see NetworkPacketOutput
 */
class NetworkPacketBuffer : public NetworkPacketInput, public NetworkPacketOutput {
    protected:
        /**
         * Pointer to the packet data
         */
        char *buf_ptr;
        
        /**
         * The size of the memory region pointed to by buf_ptr
         */
        size_t buf_size;
        
        /**
         * The number of bytes of read()-able data stored at buf_ptr
         */
        size_t data_size;
        
        /**
         * The current offset at which to run the next read/write
         */
        size_t offset;
        
        /**
         * Assert that the given number of bytes fits into the buffer at offset. Throws NetworkPacketError if not.
         *
         * The default implementation just checks offset and buf_size
         *
         * @param item_size the size of the item that should to be written
         */
        virtual void check_write_size (size_t item_size);

        /**
         * Assert that the given number of bytes is available from the buffer. Throws NetworkPacketError if not
         *
         * The default implementation just checks offset and data_size
         *
         * @param item_size the size of the item that should be read
         */
        virtual void check_read_size (size_t item_size);
         
    public:
        /**
         * Construct the NetworkPacketBuffer using the given buf_ptr, buf_size and data_size
         */
        NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size);
 
        /**
         * Returns a read-only pointer to \a len bytes of internal buffer memory, calling check_read_size first and
         * updating offset
         *
         * @param len number of bytes from the buffer to consume
         */
        virtual const void* read_ptr (size_t len);

        /**
         * Returns a read-write pointer to \a len bytes of internal buffer memory, calling check_write_size first and
         * updating offset+data_size
         *
         * @param len number of bytes in the buffer to commit
         */
        virtual void* write_ptr (size_t len);
       
        /**
         * Copy bytes from the packet buffer to ptr using memcpy(), calling check_read_size first.
         *
         * @param ptr where to copy the data to
         * @param len number of bytes to copy
         */
        virtual void read (void *ptr, size_t len);

        /**
         * Copy bytes from ptr to the packet buffer using memcpy(), calling check_write_size first
         *
         * @param ptr where to copy the data from
         * @param len number of bytes to copy
         */
        virtual void write (const void *ptr, size_t len);
        
        virtual void write_ptr_adjust (size_t buf_len, size_t data_len);
        
        /**
         * Returns our data_size - read-offset
         */
        virtual size_t tell_remaining (void);

        /*
         * Accessor functions, used by the actual socket code to read/write the buffer
         *
         * XXX: own abstract class for these? Virtual methods <3
         */
        char* get_buf (void) { return buf_ptr; }
        const char* get_buf (void) const { return buf_ptr; }
        size_t get_data_size (void) const { return data_size; }
        size_t get_buf_size (void) const { return buf_size; }
        
        /**
         * If the contents of buf_ptr is replaced with a new packet, call this to update offset/data_size
         *
         * @param size new amount of data in the buffer
         */
        void set_data_size (size_t size) { offset = 0; data_size = size; }
};

/**
 * The common case is a packet that fits in a single UDP packet, so this just uses a static buffer of a fixed size,
 * NETWORK_PACKET_SIZE.
 *
 * @see NetworkPacketBuffer
 * @see NETWORK_PACKET_SIZE
 */
class NetworkPacket : public NetworkPacketBuffer {
    private:
        /**
         * The static buffer, NETWORK_PACKET_SIZE bytes
         */
        char _buf[NETWORK_PACKET_SIZE];

    public:
        NetworkPacket (void);
};

/**
 * This is intended for sending bigger packets via TCP; a buffer of the given size is allocated on the heap.
 *
 * @see NetworkPacketBuffer
 */
class BigNetworkPacket : public NetworkPacketBuffer {
    public:
        /**
         * Allocates a buffer of the given size on the heap and uses it for NetworkPacketBuffer
         */
        BigNetworkPacket (size_t size);

    private:
        /**
         * Object must not be copied
         */
        BigNetworkPacket (const BigNetworkPacket &pkt);
        BigNetworkPacket& operator= (const BigNetworkPacket &pkt);

    public:
        /**
         * Frees the heap buffer
         */
        virtual ~BigNetworkPacket (void);
};

#endif /* NETWORK_PACKET_HH */