terom@185: #ifndef NETWORK_PACKET_HH terom@185: #define NETWORK_PACKET_HH terom@185: terom@400: /** terom@400: * @file terom@400: * terom@400: * Provides the NetworkPackets that are used to communicate over a NetworkTCP/NetworkUDP sockets. terom@400: */ terom@400: terom@417: #include "../Config.hh" terom@300: #include "../Types.hh" terom@186: #include "../Error.hh" terom@185: terom@284: /** terom@284: * Base class of errors thrown by NetworkPacket* methods terom@284: */ terom@185: class NetworkPacketError : public Error { terom@185: public: terom@185: NetworkPacketError (const std::string &message) : Error(message) { } terom@185: }; terom@185: terom@200: // forward-declare for write_packet terom@200: class NetworkPacketBuffer; terom@185: terom@284: /** terom@200: * Read-interface for network packets terom@200: */ terom@200: class NetworkPacketInput { terom@185: public: terom@284: /** terom@387: * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the read offset terom@387: * terom@387: * @param len the number of bytes to consume terom@387: */ terom@387: virtual const void* read_ptr (size_t len) = 0; terom@387: terom@387: /** terom@284: * Abstract method that copies len bytes from the packet to ptr, first testing that they exist terom@200: */ terom@284: virtual void read ( terom@284: void *ptr, //<<< where to copy terom@284: size_t len //<<< number of bytes to copy terom@284: ) = 0; terom@391: terom@391: /** terom@391: * Abstract method to get the number of input bytes remaining. terom@391: * terom@391: * @return number of input bytes still readable terom@391: */ terom@391: virtual size_t tell_remaining (void) = 0; terom@387: terom@284: /** terom@200: * Convenience function to read() and return the value of the given type terom@284: * terom@284: * @return T The value terom@200: */ terom@200: template T read_val (void); terom@296: terom@296: // @{ terom@284: /** terom@296: * Collection of methods to write out simple types, these convert from network-endianness and return the value terom@284: */ terom@284: terom@284: /** 32-bit unsigned int */ terom@185: uint32_t read_uint32 (void); terom@284: terom@284: /** 16-bit unsigned int */ terom@185: uint16_t read_uint16 (void); terom@284: terom@284: /** 8-bit unsigned int */ terom@185: uint8_t read_uint8 (void); terom@185: terom@284: /** 32-bit signed int */ terom@185: int32_t read_int32 (void); terom@284: terom@284: /** 16-bit signed int */ terom@185: int16_t read_int16 (void); terom@284: terom@284: /** 8-bit signed int */ terom@185: int8_t read_int8 (void); terom@185: terom@284: /** 32-bit float */ terom@185: float read_float32 (void); terom@284: terom@296: // @} terom@200: terom@284: /** terom@284: * Read a Vector from the packet: terom@284: * float32 vec_x terom@284: * float32 vec_y terom@284: * terom@284: * @return Vector (vec_x, vec_y) terom@284: */ terom@200: Vector read_vector (void); terom@387: terom@387: /** terom@391: * Read compressed data written with write_compressed. The given buffer must be the same size as passed to terom@391: * write_compressed. Returns the number of bytes that were decompressed into buf. terom@387: */ terom@391: size_t read_uncompressed (void *buf, size_t len); terom@200: }; terom@185: terom@284: /** terom@200: * Write-interface for network packets terom@200: */ terom@200: class NetworkPacketOutput { terom@391: protected: terom@391: /** terom@391: * Adjust size of the most recent write_ptr area of buf_len bytes to data_len bytes. terom@400: * terom@400: * You must not call write() between calls to write_ptr() and write_ptr_adjust(). This is only valid for the terom@400: * most recent write_ptr() terom@391: */ terom@391: virtual void write_ptr_adjust (size_t buf_len, size_t data_len) = 0; terom@391: terom@200: public: terom@284: /** terom@387: * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the write offset terom@387: * terom@387: * @param len number of bytes to commit terom@387: */ terom@387: virtual void* write_ptr (size_t len) = 0; terom@387: terom@387: /** terom@284: * Abstract method that copies len bytes from ptr to the packet, first testing that they fit terom@200: */ terom@284: virtual void write ( terom@284: const void *ptr, //<<< where to copy from terom@284: size_t len //<<< number of bytes to copy terom@284: ) = 0; terom@185: terom@284: /** terom@200: * Convenience function to write() the value of the given type-value terom@284: * terom@284: * @param val The value terom@200: */ terom@200: template void write_val (const T &val); terom@284: terom@296: // @{ terom@284: /** terom@296: * Collection of methods to write out simple types, these convert the given value to network-byte-order terom@284: */ terom@185: void write_uint32 (uint32_t val); terom@185: void write_uint16 (uint16_t val); terom@185: void write_uint8 (uint8_t val); terom@185: void write_int32 (int32_t val); terom@185: void write_int16 (int16_t val); terom@185: void write_int8 (int8_t val); terom@284: void write_float32 (float val); terom@185: terom@296: // @{ terom@185: terom@284: /** terom@284: * Write a vector to the packet: terom@284: * float32 vec_x terom@284: * float32 vec_y terom@284: * terom@284: * @param vec a Vector(vec_x, vec_y) terom@284: */ terom@185: void write_vector (const Vector &vec); terom@200: terom@284: /** terom@284: * This write()s the contents of the given NetworkPacketBuffer to this packet. terom@284: * terom@284: * @param pkt the sub-packet to write() terom@200: */ terom@200: void write_packet (const NetworkPacketBuffer &pkt); terom@391: terom@391: /** terom@391: * This will compress the given data buffer into this packet for reading with read_compressed. The compressed terom@391: * data will use at most write_compressed_size(len) bytes of data. terom@391: */ terom@391: void write_compressed (const void *ptr, uint32_t len); terom@391: terom@391: /** terom@391: * Return upper bound on packet size of compressed data, including header. terom@391: */ terom@391: static size_t write_compressed_size (uint32_t len); terom@200: }; terom@200: terom@284: /** terom@284: * Implements an in-memory seekable buffer used by NetworkPackets terom@284: * terom@284: * @see NetworkPacketInput terom@284: * @see NetworkPacketOutput terom@200: */ terom@200: class NetworkPacketBuffer : public NetworkPacketInput, public NetworkPacketOutput { terom@200: protected: terom@284: /** terom@284: * Pointer to the packet data terom@284: */ terom@200: char *buf_ptr; terom@200: terom@284: /** terom@284: * The size of the memory region pointed to by buf_ptr terom@284: */ terom@284: size_t buf_size; terom@200: terom@284: /** terom@284: * The number of bytes of read()-able data stored at buf_ptr terom@284: */ terom@284: size_t data_size; terom@284: terom@284: /** terom@284: * The current offset at which to run the next read/write terom@284: */ terom@284: size_t offset; terom@284: terom@284: /** terom@284: * Assert that the given number of bytes fits into the buffer at offset. Throws NetworkPacketError if not. terom@200: * terom@200: * The default implementation just checks offset and buf_size terom@284: * terom@284: * @param item_size the size of the item that should to be written terom@200: */ terom@200: virtual void check_write_size (size_t item_size); terom@200: terom@284: /** terom@284: * Assert that the given number of bytes is available from the buffer. Throws NetworkPacketError if not terom@200: * terom@200: * The default implementation just checks offset and data_size terom@284: * terom@284: * @param item_size the size of the item that should be read terom@200: */ terom@200: virtual void check_read_size (size_t item_size); terom@200: terom@200: public: terom@284: /** terom@284: * Construct the NetworkPacketBuffer using the given buf_ptr, buf_size and data_size terom@200: */ terom@200: NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size); terom@387: terom@387: /** terom@387: * Returns a read-only pointer to \a len bytes of internal buffer memory, calling check_read_size first and terom@387: * updating offset terom@387: * terom@387: * @param len number of bytes from the buffer to consume terom@387: */ terom@387: virtual const void* read_ptr (size_t len); terom@387: terom@387: /** terom@387: * Returns a read-write pointer to \a len bytes of internal buffer memory, calling check_write_size first and terom@387: * updating offset+data_size terom@387: * terom@387: * @param len number of bytes in the buffer to commit terom@387: */ terom@387: virtual void* write_ptr (size_t len); terom@387: terom@284: /** terom@284: * Copy bytes from the packet buffer to ptr using memcpy(), calling check_read_size first. terom@284: * terom@284: * @param ptr where to copy the data to terom@284: * @param len number of bytes to copy terom@200: */ terom@200: virtual void read (void *ptr, size_t len); terom@284: terom@284: /** terom@284: * Copy bytes from ptr to the packet buffer using memcpy(), calling check_write_size first terom@284: * terom@284: * @param ptr where to copy the data from terom@284: * @param len number of bytes to copy terom@284: */ terom@200: virtual void write (const void *ptr, size_t len); terom@387: terom@391: virtual void write_ptr_adjust (size_t buf_len, size_t data_len); terom@391: terom@387: /** terom@387: * Returns our data_size - read-offset terom@387: */ terom@387: virtual size_t tell_remaining (void); terom@200: terom@200: /* terom@200: * Accessor functions, used by the actual socket code to read/write the buffer terom@400: * terom@400: * XXX: own abstract class for these? Virtual methods <3 terom@200: */ terom@200: char* get_buf (void) { return buf_ptr; } terom@200: const char* get_buf (void) const { return buf_ptr; } terom@200: size_t get_data_size (void) const { return data_size; } terom@200: size_t get_buf_size (void) const { return buf_size; } terom@200: terom@284: /** terom@284: * If the contents of buf_ptr is replaced with a new packet, call this to update offset/data_size terom@284: * terom@284: * @param size new amount of data in the buffer terom@200: */ terom@200: void set_data_size (size_t size) { offset = 0; data_size = size; } terom@200: }; terom@200: terom@284: /** terom@200: * The common case is a packet that fits in a single UDP packet, so this just uses a static buffer of a fixed size, terom@200: * NETWORK_PACKET_SIZE. terom@284: * terom@284: * @see NetworkPacketBuffer terom@284: * @see NETWORK_PACKET_SIZE terom@200: */ terom@200: class NetworkPacket : public NetworkPacketBuffer { terom@200: private: terom@284: /** terom@284: * The static buffer, NETWORK_PACKET_SIZE bytes terom@284: */ terom@200: char _buf[NETWORK_PACKET_SIZE]; terom@200: terom@200: public: terom@200: NetworkPacket (void); terom@200: }; terom@200: terom@284: /** terom@284: * This is intended for sending bigger packets via TCP; a buffer of the given size is allocated on the heap. terom@200: * terom@284: * @see NetworkPacketBuffer terom@200: */ terom@200: class BigNetworkPacket : public NetworkPacketBuffer { terom@200: public: terom@284: /** terom@284: * Allocates a buffer of the given size on the heap and uses it for NetworkPacketBuffer terom@284: */ terom@200: BigNetworkPacket (size_t size); terom@202: terom@202: private: terom@284: /** terom@284: * Object must not be copied terom@284: */ terom@202: BigNetworkPacket (const BigNetworkPacket &pkt); terom@202: BigNetworkPacket& operator= (const BigNetworkPacket &pkt); terom@202: terom@203: public: terom@284: /** terom@284: * Frees the heap buffer terom@284: */ terom@202: virtual ~BigNetworkPacket (void); terom@185: }; terom@185: terom@185: #endif /* NETWORK_PACKET_HH */