X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fmoof%2Fpacket.hh;fp=src%2Fmoof%2Fpacket.hh;h=03c519fc0cb41571283bb4d1af623326be8a05ec;hp=0000000000000000000000000000000000000000;hb=831f04d4bc19a390415ac0bbac4331c7a65509bc;hpb=299af4f2047e767e5d79501c26444473bda64c64 diff --git a/src/moof/packet.hh b/src/moof/packet.hh new file mode 100644 index 0000000..03c519f --- /dev/null +++ b/src/moof/packet.hh @@ -0,0 +1,283 @@ + +/*] Copyright (c) 2009-2010, Charles McGarvey [************************** +**] All rights reserved. +* +* vi:ts=4 sw=4 tw=75 +* +* Distributable under the terms and conditions of the 2-clause BSD license; +* see the file COPYING for a complete text of the license. +* +**************************************************************************/ + +#ifndef _MOOF_PACKET_HH_ +#define _MOOF_PACKET_HH_ + +/** + * \file packet.hh + * Classes for building and interpreting datagram packets. + */ + +#include +#include +#include +#include + + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + + +namespace moof { + + +/** + * Represents a packet of serialized variables ready for transfer over the + * network. This method is most suitable for representing datagram + * packets, but it may also be useful for seralizing data for persistent + * state storage. The semantics are similar to that of a FIFO queue or + * stream where packets are written and read by inserting and extracting + * variables to and from the packet, although the actual order of the + * variables in the buffer may be different. At any time, a pointer to a + * buffer and the size of the buffer can be retrieved. This class also + * handles endian differences by serializing variables in network byte + * order (big endian). + */ +class packet +{ +public: + + /** + * Construct a packet with an initial capacity. + * \param capacity Initial capacity of the packet. + */ + explicit packet(size_t size = PAGE_SIZE); + + /** + * Construct a packet with some bytes from a buffer. The bytes will be + * copied into the packet, so you don't need to keep the original + * buffer. + * \param data The bytes. + * \param size The number of bytes. + */ + packet(const char* data, size_t size); + + /** + * Insert a variable into the packet, serializing it. This usually + * increases the size of the packet by the size of the data type. + * \param value The value to insert. + * \return This. + */ + packet& operator << (bool value); + packet& operator << (int8_t value); + packet& operator << (int16_t value); + packet& operator << (int32_t value); + packet& operator << (int64_t value); + packet& operator << (uint8_t value); + packet& operator << (uint16_t value); + packet& operator << (uint32_t value); + packet& operator << (uint64_t value); + packet& operator << (float value); + packet& operator << (double value); + + /** + * Write some bytes to the packet. + * \param bytes The bytes. + * \param size The number of bytes. + * return The number of bytes actually written. + */ + size_t write(const void* bytes, size_t size); + + + /** + * Extract a variable from the packet. This usually decreases the size + * of the packet by the size of the data type. + * \param value Reference to the variable to extract. + * \return This. + */ + packet& operator >> (bool& value); + packet& operator >> (int8_t& value); + packet& operator >> (int16_t& value); + packet& operator >> (int32_t& value); + packet& operator >> (int64_t& value); + packet& operator >> (uint8_t& value); + packet& operator >> (uint16_t& value); + packet& operator >> (uint32_t& value); + packet& operator >> (uint64_t& value); + packet& operator >> (float& value); + packet& operator >> (double& value); + + /** + * Read some bytes from the packet. + * \param bytes The buffer to hold the bytes read. + * \param size The size of the read buffer. + * \return The number of bytes actually read. + */ + size_t read(void* bytes, size_t size); + + + /** + * Clear the contents of the packet, setting the size of the packet to + * zero. + */ + void clear(); + + + /** + * Save the current state internally, allowing it to be reverted to + * later using revert(). + */ + void save(); + + /** + * Revert the packet to a previously saved state, or to that state + * immediately after construction if none other state has been + * explicitly saved using save(). + */ + void revert(); + + + /** + * Get a pointer to an internal structure holding the serialized bytes + * of the packet. + * return The pointer. + */ + const char* bytes() const + { + return buffer_ + state_.read_mark; + } + + /** + * Get the size of the buffer holding the serialized bytes of the + * packet. + * \return The number of bytes. + */ + size_t size() const + { + return state_.write_mark - state_.read_mark; + } + + + // The rest of this stuff is just to implement correct copy semantics. + + packet(const packet& copy); + packet& operator = (const packet& copy); + ~packet(); + + +private: + + char* buffer_; + size_t size_; + + struct state + { + size_t read_mark; + size_t read_bool_mark; + size_t read_bool_num; + size_t write_mark; + size_t write_bool_mark; + size_t write_bool_num; + + state(size_t size = 0) : + read_mark(0), + read_bool_mark(0), + read_bool_num(0), + write_mark(size), + write_bool_mark(0), + write_bool_num(0) {} + }; + + state state_; + state saved_; +}; + + +template +inline packet& operator << (packet& packet, const T& value) +{ + value.pack(packet); + return packet; +} + +template +inline packet& operator >> (packet& packet, T& value) +{ + value.unpack(packet); + return packet; +} + + +inline packet& operator << (packet& packet, const char* value) +{ + uint16_t length = strlen(value); + packet << length; + if (packet.write(value, length) != length) + { + throw std::length_error("out of memory"); + } + return packet; +} + +template +inline packet& operator << (packet& packet, const std::basic_string& value) +{ + packet << static_cast(value.length()); + size_t num_bytes = value.length() * sizeof(T); + if (packet.write(value.data(), num_bytes) != num_bytes) + { + throw std::length_error("out of memory"); + } + return packet; +} + +template +inline packet& operator >> (packet& packet, std::basic_string& value) +{ + uint16_t length = 0; + packet >> length; + + T str[length]; + size_t num_bytes = length * sizeof(T); + if (packet.read(str, num_bytes) != num_bytes) + { + throw std::out_of_range("end of packet"); + } + value.assign(str, length); + return packet; +} + + +template +inline packet& operator << (packet& packet, const std::vector& value) +{ + packet << static_cast(value.size()); + typename std::vector::const_iterator it; + for (it = value.begin(); it != value.end(); ++it) + { + packet << *it; + } + return packet; +} + +template +inline packet& operator >> (packet& packet, std::vector& value) +{ + uint16_t size = 0; + packet >> size; + + value.clear(); + for (uint16_t i = 0; i < size; ++i) + { + T item; + packet >> item; + value.push_back(item); + } + return packet; +} + + +} // namespace moof + +#endif // _MOOF_PACKET_HH_ +