src/Network/Packet.cc
author Tero Marttila <terom@fixme.fi>
Fri, 16 Jan 2009 22:03:49 +0200
changeset 400 d64bf28c4340
parent 391 59c2499fe7bb
child 425 567144562978
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

#include <cassert>
#include <cstring>

#include "Packet.hh"
#include "Platform.hh"

#include <zlib.h>

// XXX: assumes that sizeof(float32) == sizeof(int32);

/*
 * NetworkPacketInput
 */
template <typename T> T NetworkPacketInput::read_val (void) {
    T val;

    // read
    read(&val, sizeof(T));

    // return
    return val;
}

uint32_t NetworkPacketInput::read_uint32 (void) {
    return ntohl(read_val<uint32_t>());
}

uint16_t NetworkPacketInput::read_uint16 (void) {
    return ntohs(read_val<uint16_t>());
}

uint8_t NetworkPacketInput::read_uint8 (void) {
    return read_val<uint8_t>();
}

int32_t NetworkPacketInput::read_int32 (void) {
    return ntohl(read_val<int32_t>());
}

int16_t NetworkPacketInput::read_int16 (void) {
    return ntohs(read_val<int16_t>());
}

int8_t NetworkPacketInput::read_int8 (void) {
    return read_val<int8_t>();
}
        
float NetworkPacketInput::read_float32 (void) {
    int32_t ival = read_int32();
    float fval;
    
    assert(sizeof(ival) == sizeof(fval));

    memcpy(&fval, &ival, sizeof(float));

    return fval;
}

Vector NetworkPacketInput::read_vector (void) {
    float fx = read_float32();
    float fy = read_float32();

    return Vector(fx, fy);
}
        
size_t NetworkPacketInput::read_uncompressed (void *buf, size_t len) {
    // given len
    unsigned long inflate_size = len;

    // read deflate size
    unsigned long deflate_size = read_uint32();

    // pointer to packet data
    const void *deflate_ptr = read_ptr(deflate_size);

    // uncompress the rest of the packet data
    if (uncompress((uint8_t *) buf, &inflate_size, (const uint8_t *) deflate_ptr, deflate_size) != Z_OK)
        throw Error("uncompress");
    
    // return inflated size
    return inflate_size;
}

/*
 * NetworkPacketOutput
 */
template <typename T> void NetworkPacketOutput::write_val (const T &val) {
    // write
    write(&val, sizeof(T));
}


void NetworkPacketOutput::write_uint32 (uint32_t val) {
    write_val<uint32_t>(htonl(val));
}

void NetworkPacketOutput::write_uint16 (uint16_t val) {
    write_val<uint16_t>(htons(val));
}

void NetworkPacketOutput::write_uint8 (uint8_t val) {
    write_val<uint8_t>(val);
}

void NetworkPacketOutput::write_int32 (int32_t val) {
    write_val<int32_t>(htonl(val));
}

void NetworkPacketOutput::write_int16 (int16_t val) {
    write_val<int16_t>(htons(val));
}

void NetworkPacketOutput::write_int8 (int8_t val) {
    write_val<int8_t>(val);
}
        
void NetworkPacketOutput::write_float32 (float fval) {
    int32_t ival;

    assert(sizeof(ival) == sizeof(fval));

    memcpy(&ival, &fval, sizeof(int32_t));

    write_int32(ival);
}

void NetworkPacketOutput::write_vector (const Vector &vec) {
    write_float32(vec.x);
    write_float32(vec.y);
}

void NetworkPacketOutput::write_packet (const NetworkPacketBuffer &pkt) {
    // just write() it
    write(pkt.get_buf(), pkt.get_data_size());
}
        
void NetworkPacketOutput::write_compressed (const void *ptr, uint32_t len) {
    // full compression buffer size, including header
    unsigned long deflate_buf_size = write_compressed_size(len);

    // size of compressed data area after header
    unsigned long deflate_size = deflate_buf_size - sizeof(uint32_t);
    
    // packet buffer
    void *deflate_buf = write_ptr(deflate_buf_size);

    // compress
    if (compress((uint8_t *) deflate_buf + sizeof(uint32_t), &deflate_size, (const uint8_t *) ptr, len) != Z_OK)
       throw Error("compress failed"); 

    // write data size
    *((uint32_t *) deflate_buf) = htonl(deflate_size);
    
    // adjust final area
    write_ptr_adjust(deflate_buf_size, sizeof(uint32_t) + deflate_size);
}
        
size_t NetworkPacketOutput::write_compressed_size (uint32_t len) {
    return sizeof(uint32_t) + compressBound(len);
}

/*
 * NetworkPacketBuffer
 */
NetworkPacketBuffer::NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size) :
    buf_ptr(buf_ptr), buf_size(buf_size), data_size(data_size), offset(0) {
    
    // nothing
    if (buf_ptr == NULL)
        throw NetworkPacketError("buf_ptr may not be NULL");
}

void NetworkPacketBuffer::check_write_size (size_t item_size) {
     if (offset + item_size > buf_size)
        throw NetworkPacketError("not enough space to write");

}
        
void NetworkPacketBuffer::check_read_size (size_t item_size) {
    if (offset + item_size > data_size)
        throw NetworkPacketError("not enough data to read");
}
       
const void* NetworkPacketBuffer::read_ptr (size_t len) {
    // check buffer overflow
    check_read_size(len);

    // pointer value...
    const void *ptr = buf_ptr + offset;
    
    // update offset
    offset += len;
    
    // return pointer
    return ptr;
}
        
void* NetworkPacketBuffer::write_ptr (size_t len) {
    // check buffer overflow
    check_write_size(len);

    // pointer value...
    void *ptr = buf_ptr + offset;

    // update offset and size
    offset += len;
    data_size += len;
    
    // return pointer
    return ptr;
}

void NetworkPacketBuffer::read (void *ptr, size_t len) {
    // get input pointer...
    const void *input_ptr = read_ptr(len);

    // copy value out
    memcpy(ptr, input_ptr, len);
}
 
void NetworkPacketBuffer::write (const void *ptr, size_t len) {
    // get output pointer...
    void *output_ptr = write_ptr(len);

    // copy value in
    memcpy(output_ptr, ptr, len);
}
        
void NetworkPacketBuffer::write_ptr_adjust (size_t buf_len, size_t data_len) {
    assert(data_len <= buf_len);
    
    // adjust offset backwards
    offset -= (buf_len - data_len);
    data_size -= (buf_len - data_len);
}

size_t NetworkPacketBuffer::tell_remaining (void) {
    // number of bytes in total - number of bytes read
    return data_size - offset;
}

/*
 * NetworkPacket
 */
NetworkPacket::NetworkPacket (void) : 
    NetworkPacketBuffer(_buf, NETWORK_PACKET_SIZE, 0) 
{ 
    
}

/*
 * BigNetworkPacket
 */
BigNetworkPacket::BigNetworkPacket (size_t size) :
    NetworkPacketBuffer((char *) malloc(size), size, 0)
{

}

BigNetworkPacket::~BigNetworkPacket (void) {
    free(buf_ptr);
}