better NetworkBuffer/Packet stuff + some additional Physics+Network stuff + random fixes
#ifndef NETWORK_BUFFER_HH
#define NETWORK_BUFFER_HH
#include "Socket.hh"
#include "../Error.hh"
#include <cassert>
/*
* Minimum chunk size to avoid handling single bytes at a time (for resize, mainly)
*/
const size_t NETWORK_BUFFER_CHUNK_SIZE = 1024;
class NetworkBufferError : public Error {
public:
NetworkBufferError (const std::string &message) : Error(message) { }
};
/*
* Base buffer operations for uffered socket send/recv
*/
class NetworkBufferBase {
protected:
// the socket that we use
NetworkSocket socket;
char *buf;
size_t size, offset;
public:
NetworkBufferBase (NetworkSocket &socket, size_t size_hint);
~NetworkBufferBase (void);
private:
NetworkBufferBase (const NetworkBufferBase ©);
NetworkBufferBase& operator= (const NetworkBufferBase ©);
protected:
void resize (size_t item_size);
void trim (size_t prefix_size);
};
/*
* Buffered prefix-len socket input
*/
class NetworkBufferInput : public NetworkBufferBase {
public:
NetworkBufferInput (NetworkSocket &socket, size_t size_hint);
private:
/*
* Attempts to recv the given number of bytes, returning true on success
*/
bool try_read (size_t item_size);
/*
* Returns true if the buffer contains at least the given amount of data
*/
bool have_data (size_t data_size);
public:
/*
* Attempts to read the length prefix into val_ref, returning true on success
*/
bool peek_prefix (uint16_t &val_ref);
bool peek_prefix (uint32_t &val_ref);
/*
* This attempts to collect the prefix + data into our buffer, and then returns the length and a pointer to the
* internal memory buffer. Use flush_data when done with the data
*/
// XXX: template definition moved here from .cc
template <typename PrefixType> bool peek_data (PrefixType &prefix, char *&buf_ref) {
size_t missing = 0;
do {
// do we have the prefix?
if (peek_prefix(prefix)) {
// do we already have the payload?
if (offset >= sizeof(PrefixType) + prefix) {
break;
} else {
missing = (sizeof(PrefixType) + prefix) - offset;
}
} else {
missing = sizeof(PrefixType);
}
// sanity-check
// XXX: a zero-prefix will trigger this
assert(missing);
// try and read the missing data
if (try_read(missing) == false) {
// if unable to read what we need, return zero.
return false;
}
// assess the situation again
} while (true);
// update the buf_ref to point past the prefix-length
buf_ref = buf + sizeof(PrefixType);
// return
return true;
}
template <typename PrefixType> void flush_data (void) {
PrefixType prefix;
// we *must* have a valid prefix
assert(peek_prefix(prefix));
// trim the bytes out
trim(sizeof(PrefixType) + prefix);
}
};
/*
* Buffered prefix-len socket output
*/
class NetworkBufferOutput : public NetworkBufferBase {
public:
NetworkBufferOutput (NetworkSocket &socket, size_t size_hint);
private:
/*
* If our buffer is empty, fast-path the given buf_ptr directly to send(), else copy the remaining
* portion to our buffer for later use with flush_write
*/
void push_write (char *buf_ptr, size_t buf_size);
public:
/*
* Try and send() stuff out of our buffer, or ignore if it's empty
*/
void flush_write (void);
/*
* push_write, first the given prefix and then the buf (which contains <prefix> bytes of data)
*/
void write_prefix (char *buf, uint16_t prefix);
void write_prefix (char *buf, uint32_t prefix);
};
#endif