/*] 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. * **************************************************************************/ #include "../config.h" #include #if HAVE_BYTESWAP_H #include #endif #include #if HAVE_ARPA_INET_H #include #endif #include #include "packet.hh" #ifndef bswap_16 #define bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) #endif #ifndef bswap_32 #define bswap_32(x) ((((x) & 0xff000000) >> 24) | \ (((x) & 0x00ff0000) >> 8) | \ (((x) & 0x0000ff00) << 8) | \ (((x) & 0x000000ff) << 24)) #endif #ifndef bswap_64 #define bswap_64(x) (((x) << 56) | \ (((x) << 40) & 0xff000000000000ULL) | \ (((x) << 24) & 0xff0000000000ULL) | \ (((x) << 8) & 0xff00000000ULL) | \ (((x) >> 8) & 0xff000000ULL) | \ (((x) >> 24) & 0xff0000ULL) | \ (((x) >> 40) & 0xff00ULL) | \ ((x) >> 56)) #endif #if !HAVE_ARPA_INET_H static uint16_t htons(uint16_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_16(x); #else return x; #endif } static uint16_t ntohs(uint16_t x) { return htons(x); } static uint32_t htonl(uint32_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_32(x); #else return x; #endif } static uint32_t ntohl(uint32_t x) { return htonl(x); } #endif static uint64_t htonll(uint64_t x) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN return bswap_64(x); #else return x; #endif } static uint64_t ntohll(uint64_t x) { return htonll(x); } namespace moof { packet::packet(size_t size) : buffer_((char*)malloc(size)), size_(size) {} packet::packet(const char* data, size_t size) : buffer_((char*)malloc(size)), size_(size), state_(size), saved_(size) { if (buffer_) memcpy(buffer_, data, size); else throw std::length_error("out of memory"); } packet::packet(const packet& copy) : buffer_((char*)malloc(copy.size_)), size_(copy.size_), state_(copy.state_), saved_(copy.saved_) { if (buffer_) memcpy(buffer_, copy.buffer_, size_); else throw std::length_error("out of memory"); } packet& packet::operator = (const packet& copy) { free(buffer_); buffer_ = (char*)malloc(copy.size_); size_ = copy.size_; if (buffer_) memcpy(buffer_, copy.buffer_, size_); else throw std::length_error("out of memory"); state_ = copy.state_; saved_ = copy.saved_; return *this; } packet::~packet() { free(buffer_); } packet& packet::operator << (bool value) { int bit = state_.write_bool_num % 8; if (bit == 0) { state_.write_bool_mark = state_.write_mark; unsigned char byte = 0; if (write(&byte, 1) == 0) throw std::length_error("out of memory"); } if (value) buffer_[state_.write_bool_mark] |= (1 << bit); ++state_.write_bool_num; return *this; } packet& packet::operator << (int8_t value) { return *this << reinterpret_cast(value); } packet& packet::operator << (int16_t value) { return *this << reinterpret_cast(value); } packet& packet::operator << (int32_t value) { return *this << reinterpret_cast(value); } packet& packet::operator << (int64_t value) { return *this << reinterpret_cast(value); } packet& packet::operator << (uint8_t value) { if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } packet& packet::operator << (uint16_t value) { value = htons(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } packet& packet::operator << (uint32_t value) { value = htonl(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } packet& packet::operator << (uint64_t value) { value = htonll(value); if (write(&value, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } packet& packet::operator << (float value) { // XXX: assumes the ieee-754 uint32_t* integer = reinterpret_cast(&value); *integer = htonl(*integer); if (write(integer, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } packet& packet::operator << (double value) { // XXX: assumes the ieee-754 uint64_t* integer = reinterpret_cast(&value); *integer = htonll(*integer); if (write(integer, sizeof(value)) != sizeof(value)) { throw std::length_error("out of memory"); } return *this; } size_t packet::write(const void* bytes, size_t size) { size_t num_bytes = std::min(size, size_ - state_.write_mark); if (!buffer_ || num_bytes < size) { int num_pages = 1 + size / PAGE_SIZE; int new_size = size_ + num_pages * PAGE_SIZE; char* new_buffer = (char*)realloc(buffer_, new_size); if (new_buffer) { buffer_ = new_buffer; size_ = new_size; num_bytes = size; } if (!buffer_) return 0; } memcpy(buffer_ + state_.write_mark, bytes, num_bytes); state_.write_mark += num_bytes; return num_bytes; } packet& packet::operator >> (bool& value) { int bit = state_.read_bool_num % 8; if (bit == 0) { state_.read_bool_mark = state_.read_mark; unsigned char byte = 0; if (read(&byte, 1) == 0) throw std::out_of_range("end of packet"); } value = 1 & (buffer_[state_.read_bool_mark] >> bit); ++state_.read_bool_num; return *this; } packet& packet::operator >> (int8_t& value) { return *this >> reinterpret_cast(value); } packet& packet::operator >> (int16_t& value) { return *this >> reinterpret_cast(value); } packet& packet::operator >> (int32_t& value) { return *this >> reinterpret_cast(value); } packet& packet::operator >> (int64_t& value) { return *this >> reinterpret_cast(value); } packet& packet::operator >> (uint8_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } return *this; } packet& packet::operator >> (uint16_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohs(value); return *this; } packet& packet::operator >> (uint32_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohl(value); return *this; } packet& packet::operator >> (uint64_t& value) { if (read(&value, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } value = ntohll(value); return *this; } packet& packet::operator >> (float& value) { // XXX: assumes the ieee-754 uint32_t* integer = reinterpret_cast(&value); if (read(integer, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } *integer = htonl(*integer); return *this; } packet& packet::operator >> (double& value) { // XXX: assumes the ieee-754 uint64_t* integer = reinterpret_cast(&value); if (read(integer, sizeof(value)) != sizeof(value)) { throw std::out_of_range("end of packet"); } *integer = htonll(*integer); return *this; } size_t packet::read(void* bytes, size_t size) { size_t num_bytes = std::min(size, state_.write_mark - state_.read_mark); memcpy(bytes, buffer_ + state_.read_mark, num_bytes); state_.read_mark += num_bytes; return num_bytes; } void packet::clear() { state_.read_mark = state_.write_mark; state_.read_bool_mark = 0; state_.read_bool_num = 0; state_.write_bool_mark = 0; state_.write_bool_num = 0; } void packet::save() { saved_ = state_; } void packet::revert() { state_ = saved_; } } // namespace moof