--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Network/Buffer.hh Thu Dec 04 21:59:23 2008 +0000
@@ -0,0 +1,150 @@
+#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