Home | History | Annotate | Download | only in flip
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef NET_FLIP_FRAME_BUILDER_H_
      6 #define NET_FLIP_FRAME_BUILDER_H_
      7 
      8 #ifdef WIN32
      9 #include <winsock2.h>  // for htonl() functions
     10 #else
     11 #include <arpa/inet.h>
     12 #endif
     13 
     14 #include <string>
     15 
     16 #include "base/logging.h"
     17 #include "flip_protocol.h"  // cross-google3 directory naming.
     18 
     19 namespace flip {
     20 
     21 // This class provides facilities for basic binary value packing and unpacking
     22 // into Flip frames.
     23 //
     24 // The FlipFrameBuilder supports appending primitive values (int, string, etc)
     25 // to a frame instance.  The FlipFrameBuilder grows its internal memory buffer
     26 // dynamically to hold the sequence of primitive values.   The internal memory
     27 // buffer is exposed as the "data" of the FlipFrameBuilder.
     28 //
     29 // When reading from a FlipFrameBuilder the consumer must know what value types
     30 // to read and in what order to read them as the FlipFrameBuilder does not keep
     31 // track of the type of data written to it.
     32 class FlipFrameBuilder {
     33  public:
     34   FlipFrameBuilder();
     35   ~FlipFrameBuilder();
     36 
     37   // Initializes a FlipFrameBuilder from a const block of data.  The data is
     38   // not copied; instead the data is merely referenced by this
     39   // FlipFrameBuilder.  Only const methods should be used when initialized
     40   // this way.
     41   FlipFrameBuilder(const char* data, int data_len);
     42 
     43   // Returns the size of the FlipFrameBuilder's data.
     44   int length() const { return length_; }
     45 
     46   // Takes the buffer from the FlipFrameBuilder.
     47   FlipFrame* take() {
     48     FlipFrame* rv = new FlipFrame(buffer_, true);
     49     buffer_ = NULL;
     50     capacity_ = 0;
     51     length_ = 0;
     52     return rv;
     53   }
     54 
     55   // Methods for reading the payload of the FlipFrameBuilder.  To read from the
     56   // start of the FlipFrameBuilder, initialize *iter to NULL.  If successful,
     57   // these methods return true.  Otherwise, false is returned to indicate that
     58   // the result could not be extracted.
     59   bool ReadUInt16(void** iter, uint16* result) const;
     60   bool ReadUInt32(void** iter, uint32* result) const;
     61   bool ReadString(void** iter, std::string* result) const;
     62   bool ReadBytes(void** iter, const char** data, uint16 length) const;
     63   bool ReadData(void** iter, const char** data, uint16* length) const;
     64 
     65   // Methods for adding to the payload.  These values are appended to the end
     66   // of the FlipFrameBuilder payload.  When reading values, you must read them
     67   // in the order they were added.  Note - binary integers are converted from
     68   // host to network form.
     69   bool WriteUInt16(uint16 value) {
     70     value = htons(value);
     71     return WriteBytes(&value, sizeof(value));
     72   }
     73   bool WriteUInt32(uint32 value) {
     74     value = htonl(value);
     75     return WriteBytes(&value, sizeof(value));
     76   }
     77   bool WriteString(const std::string& value);
     78   bool WriteBytes(const void* data, uint16 data_len);
     79 
     80   // Write an integer to a particular offset in the data buffer.
     81   bool WriteUInt32ToOffset(int offset, uint32 value) {
     82     value = htonl(value);
     83     return WriteBytesToOffset(offset, &value, sizeof(value));
     84   }
     85 
     86   // Write to a particular offset in the data buffer.
     87   bool WriteBytesToOffset(int offset, const void* data, uint32 data_len) {
     88     if (offset + data_len > length_)
     89       return false;
     90     char *ptr = buffer_ + offset;
     91     memcpy(ptr, data, data_len);
     92     return true;
     93   }
     94 
     95   // Allows the caller to write data directly into the FlipFrameBuilder.
     96   // This saves a copy when the data is not already available in a buffer.
     97   // The caller must not write more than the length it declares it will.
     98   // Use ReadData to get the data.
     99   // Returns NULL on failure.
    100   //
    101   // The returned pointer will only be valid until the next write operation
    102   // on this FlipFrameBuilder.
    103   char* BeginWriteData(uint16 length);
    104 
    105   // Returns true if the given iterator could point to data with the given
    106   // length. If there is no room for the given data before the end of the
    107   // payload, returns false.
    108   bool IteratorHasRoomFor(const void* iter, int len) const {
    109     const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
    110     if (len < 0 ||
    111         iter < buffer_ ||
    112         iter > end_of_payload() ||
    113         iter > end_of_region ||
    114         end_of_region > end_of_payload())
    115       return false;
    116 
    117     // Watch out for overflow in pointer calculation, which wraps.
    118     return (iter <= end_of_region) && (end_of_region <= end_of_payload());
    119   }
    120 
    121  protected:
    122   size_t capacity() const {
    123     return capacity_;
    124   }
    125 
    126   const char* end_of_payload() const { return buffer_ + length_; }
    127 
    128   // Resizes the buffer for use when writing the specified amount of data. The
    129   // location that the data should be written at is returned, or NULL if there
    130   // was an error. Call EndWrite with the returned offset and the given length
    131   // to pad out for the next write.
    132   char* BeginWrite(size_t length);
    133 
    134   // Completes the write operation by padding the data with NULL bytes until it
    135   // is padded. Should be paired with BeginWrite, but it does not necessarily
    136   // have to be called after the data is written.
    137   void EndWrite(char* dest, int length);
    138 
    139   // Resize the capacity, note that the input value should include the size of
    140   // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
    141   // A new failure will cause a Resize failure... and caller should check
    142   // the return result for true (i.e., successful resizing).
    143   bool Resize(size_t new_capacity);
    144 
    145   // Moves the iterator by the given number of bytes.
    146   static void UpdateIter(void** iter, int bytes) {
    147     *iter = static_cast<char*>(*iter) + bytes;
    148   }
    149 
    150   // Initial size of the payload.
    151   static const int kInitialPayload = 1024;
    152 
    153  private:
    154   char* buffer_;
    155   size_t capacity_;  // Allocation size of payload (or -1 if buffer is const).
    156   size_t length_;    // current length of the buffer
    157   size_t variable_buffer_offset_;  // IF non-zero, then offset to a buffer.
    158 };
    159 
    160 }  // namespace flip
    161 
    162 #endif  // NET_FLIP_FRAME_BUILDER_H_
    163 
    164