src/Network/Buffer.hh
changeset 200 2dbf40661580
child 284 27ce69fd1e06
equal deleted inserted replaced
199:f5c86420facd 200:2dbf40661580
       
     1 #ifndef NETWORK_BUFFER_HH
       
     2 #define NETWORK_BUFFER_HH
       
     3 
       
     4 #include "Socket.hh"
       
     5 #include "../Error.hh"
       
     6 
       
     7 #include <cassert>
       
     8 
       
     9 /*
       
    10  * Minimum chunk size to avoid handling single bytes at a time (for resize, mainly)
       
    11  */
       
    12 const size_t NETWORK_BUFFER_CHUNK_SIZE = 1024;
       
    13 
       
    14 class NetworkBufferError : public Error {
       
    15     public:
       
    16         NetworkBufferError (const std::string &message) : Error(message) { }
       
    17 };
       
    18 
       
    19 /*
       
    20  * Base buffer operations for uffered socket send/recv
       
    21  */
       
    22 class NetworkBufferBase {
       
    23     protected:
       
    24         // the socket that we use
       
    25         NetworkSocket socket;
       
    26 
       
    27         char *buf;
       
    28         size_t size, offset;
       
    29     
       
    30     public:
       
    31         NetworkBufferBase (NetworkSocket &socket, size_t size_hint);
       
    32         ~NetworkBufferBase (void);
       
    33     
       
    34     private:
       
    35         NetworkBufferBase (const NetworkBufferBase &copy);
       
    36         NetworkBufferBase& operator= (const NetworkBufferBase &copy);
       
    37     
       
    38     protected:
       
    39         void resize (size_t item_size);
       
    40         void trim (size_t prefix_size);
       
    41 };
       
    42 
       
    43 /*
       
    44  * Buffered prefix-len socket input
       
    45  */
       
    46 class NetworkBufferInput : public NetworkBufferBase {
       
    47     public:
       
    48         NetworkBufferInput (NetworkSocket &socket, size_t size_hint);
       
    49 
       
    50     private:
       
    51         /*
       
    52          * Attempts to recv the given number of bytes, returning true on success
       
    53          */
       
    54         bool try_read (size_t item_size);
       
    55 
       
    56         /*
       
    57          * Returns true if the buffer contains at least the given amount of data
       
    58          */
       
    59         bool have_data (size_t data_size);
       
    60     
       
    61     public:
       
    62         /*
       
    63          * Attempts to read the length prefix into val_ref, returning true on success
       
    64          */
       
    65         bool peek_prefix (uint16_t &val_ref);
       
    66         bool peek_prefix (uint32_t &val_ref);
       
    67         
       
    68         /*
       
    69          * This attempts to collect the prefix + data into our buffer, and then returns the length and a pointer to the
       
    70          * internal memory buffer. Use flush_data when done with the data
       
    71          */
       
    72 
       
    73         // XXX: template definition moved here from .cc
       
    74         template <typename PrefixType> bool peek_data (PrefixType &prefix, char *&buf_ref) {
       
    75             size_t missing = 0;
       
    76             
       
    77             do {    
       
    78                 // do we have the prefix?
       
    79                 if (peek_prefix(prefix)) {
       
    80                     // do we already have the payload?
       
    81                     if (offset >= sizeof(PrefixType) + prefix) {
       
    82                         break;
       
    83 
       
    84                     } else {
       
    85                         missing = (sizeof(PrefixType) + prefix) - offset;
       
    86                     }
       
    87 
       
    88                 } else {
       
    89                     missing = sizeof(PrefixType);
       
    90                 }
       
    91 
       
    92                 // sanity-check
       
    93                 // XXX: a zero-prefix will trigger this
       
    94                 assert(missing);
       
    95                 
       
    96                 // try and read the missing data
       
    97                 if (try_read(missing) == false) {
       
    98                     // if unable to read what we need, return zero.
       
    99                     return false;
       
   100                 }
       
   101                 
       
   102                 // assess the situation again
       
   103             } while (true);
       
   104             
       
   105             // update the buf_ref to point past the prefix-length
       
   106             buf_ref = buf + sizeof(PrefixType);
       
   107 
       
   108             // return
       
   109             return true;
       
   110         }
       
   111             
       
   112         template <typename PrefixType> void flush_data (void) {
       
   113             PrefixType prefix;
       
   114             
       
   115             // we *must* have a valid prefix
       
   116             assert(peek_prefix(prefix));
       
   117 
       
   118             // trim the bytes out
       
   119             trim(sizeof(PrefixType) + prefix);
       
   120         }
       
   121 };
       
   122 
       
   123 /*
       
   124  * Buffered prefix-len socket output
       
   125  */
       
   126 class NetworkBufferOutput : public NetworkBufferBase {
       
   127     public:
       
   128         NetworkBufferOutput (NetworkSocket &socket, size_t size_hint);
       
   129 
       
   130     private:
       
   131         /*
       
   132          * If our buffer is empty, fast-path the given buf_ptr directly to send(), else copy the remaining
       
   133          * portion to our buffer for later use with flush_write
       
   134          */
       
   135         void push_write (char *buf_ptr, size_t buf_size);
       
   136    
       
   137     public:    
       
   138         /*
       
   139          * Try and send() stuff out of our buffer, or ignore if it's empty
       
   140          */
       
   141         void flush_write (void);
       
   142         
       
   143         /*
       
   144          * push_write, first the given prefix and then the buf (which contains <prefix> bytes of data)
       
   145          */
       
   146         void write_prefix (char *buf, uint16_t prefix);
       
   147         void write_prefix (char *buf, uint32_t prefix);
       
   148 };
       
   149 
       
   150 #endif