src/common/buffer.h
author Nicola Baldo <nbaldo@cttc.es>
Thu Aug 13 09:36:16 2009 +0200 (2009-08-13)
changeset 4708 b251fb79becb
parent 4518 31f2881aa214
child 5842 e5571955464f
permissions -rw-r--r--
bug 639: Buffer::CopyData is buggy.
     1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
     2 /*
     3  * Copyright (c) 2005,2006,2007 INRIA
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License version 2 as
     7  * published by the Free Software Foundation;
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
    19  */
    20 #ifndef BUFFER_H
    21 #define BUFFER_H
    22 
    23 #include <stdint.h>
    24 #include <vector>
    25 #include <ostream>
    26 
    27 #define BUFFER_HEURISTICS 1
    28 #define BUFFER_USE_INLINE 1
    29 
    30 
    31 #ifdef BUFFER_USE_INLINE
    32 #define BUFFER_INLINE inline
    33 #else
    34 #define BUFFER_INLINE
    35 #endif
    36 
    37 namespace ns3 {
    38 
    39 /**
    40  * \ingroup packet
    41  *
    42  * \brief automatically resized byte buffer
    43  *
    44  * This represents a buffer of bytes. Its size is
    45  * automatically adjusted to hold any data prepended
    46  * or appended by the user. Its implementation is optimized
    47  * to ensure that the number of buffer resizes is minimized,
    48  * by creating new Buffers of the maximum size ever used.
    49  * The correct maximum size is learned at runtime during use by 
    50  * recording the maximum size of each packet.
    51  *
    52  * \internal
    53  * The implementation of the Buffer class uses a COW (Copy On Write)
    54  * technique to ensure that the underlying data buffer which holds
    55  * the data bytes is shared among a lot of Buffer instances despite
    56  * data being added or removed from them.
    57  *
    58  * When multiple Buffer instances hold a reference to the same 
    59  * underlying BufferData object, they must be able to detect when
    60  * the operation they want to perform should trigger a copy of the
    61  * BufferData. If the BufferData::m_count field is one, it means that
    62  * there exist only one instance of Buffer which references the 
    63  * BufferData instance so, it is safe to modify it. It is also
    64  * safe to modify the content of a BufferData if the modification
    65  * falls outside of the "dirty area" defined by the BufferData.
    66  * In every other case, the BufferData must be copied before
    67  * being modified.
    68  *
    69  * To understand the way the Buffer::Add and Buffer::Remove methods
    70  * work, you first need to understand the "virtual offsets" used to
    71  * keep track of the content of buffers. Each Buffer instance
    72  * contains real data bytes in its BufferData instance but it also
    73  * contains "virtual zero data" which typically is used to represent
    74  * application-level payload. No memory is allocated to store the
    75  * zero bytes of application-level payload unless the user fragments
    76  * a Buffer: this application-level payload is kept track of with
    77  * a pair of integers which describe where in the buffer content
    78  * the "virtual zero area" starts and ends.
    79  *
    80  * ***: unused bytes
    81  * xxx: bytes "added" at the front of the zero area
    82  * ...: bytes "added" at the back of the zero area
    83  * 000: virtual zero bytes
    84  *
    85  * Real byte buffer:      |********xxxxxxxxxxxx.........*****|
    86  *                        |--------^ m_start
    87  *                        |-------------------^ m_zeroAreaStart
    88  *                        |-----------------------------^ m_end - (m_zeroAreaEnd - m_zeroAreaStart)
    89  * virtual byte buffer:           |xxxxxxxxxxxx0000000000000.........|
    90  *                        |--------^ m_start
    91  *                        |--------------------^ m_zeroAreaStart
    92  *                        |---------------------------------^ m_zeroAreaEnd
    93  *                        |------------------------------------------^ m_end
    94  *
    95  * A simple state invariant is that m_start <= m_zeroStart <= m_zeroEnd <= m_end
    96  */
    97 class Buffer 
    98 {
    99 public:
   100   /**
   101    * \brief iterator in a Buffer instance
   102    */
   103   class Iterator 
   104   {
   105   public:
   106       Iterator ();
   107       /**
   108        * go forward by one byte
   109        */
   110       void Next (void);
   111       /**
   112        * go backward by one byte
   113        */
   114       void Prev (void);
   115       /**
   116        * \param delta number of bytes to go forward
   117        */
   118       void Next (uint32_t delta);
   119       /**
   120        * \param delta number of bytes to go backward
   121        */
   122       void Prev (uint32_t delta);
   123       /**
   124        * \param o the second iterator
   125        * \return number of bytes included between the two iterators
   126        *
   127        * This method works only if the two iterators point
   128        * to the same underlying buffer. Debug builds ensure
   129        * this with an assert.
   130        */
   131       uint32_t GetDistanceFrom (Iterator const &o) const;
   132       
   133       /**
   134        * \return true if this iterator points to the end of the byte array.
   135        *     false otherwise.
   136        */
   137       bool IsEnd (void) const;
   138       /**
   139        * \return true if this iterator points to the start of the byte array.
   140        *     false otherwise.
   141        */
   142       bool IsStart (void) const;
   143 
   144       /**
   145        * \param data data to write in buffer
   146        *
   147        * Write the data in buffer and avance the iterator position
   148        * by one byte.
   149        */
   150       BUFFER_INLINE void WriteU8 (uint8_t  data);
   151       /**
   152        * \param data data to write in buffer
   153        * \param len number of times data must be written in buffer
   154        *
   155        * Write the data in buffer len times and avance the iterator position
   156        * by len byte.
   157        */
   158       BUFFER_INLINE void WriteU8 (uint8_t data, uint32_t len);
   159       /**
   160        * \param data data to write in buffer
   161        *
   162        * Write the data in buffer and avance the iterator position
   163        * by two bytes. The format of the data written in the byte
   164        * buffer is non-portable. We only ensure that readU16 will
   165        * return exactly what we wrote with writeU16 if the program
   166        * is run on the same machine.
   167        */
   168       void WriteU16 (uint16_t data);
   169       /**
   170        * \param data data to write in buffer
   171        *
   172        * Write the data in buffer and avance the iterator position
   173        * by four bytes. The format of the data written in the byte
   174        * buffer is non-portable. We only ensure that readU32 will
   175        * return exactly what we wrote with writeU32 if the program
   176        * is run on the same machine.
   177        */
   178       void WriteU32 (uint32_t data);
   179       /**
   180        * \param data data to write in buffer
   181        *
   182        * Write the data in buffer and avance the iterator position
   183        * by eight bytes. The format of the data written in the byte
   184        * buffer is non-portable. We only ensure that readU64 will
   185        * return exactly what we wrote with writeU64 if the program
   186        * is run on the same machine.
   187        */
   188       void WriteU64 (uint64_t data);
   189       /**
   190        * \param data data to write in buffer
   191        *
   192        * Write the data in buffer and avance the iterator position
   193        * by two bytes. The data is written in network order and the
   194        * input data is expected to be in host order.
   195        */
   196       void WriteHtolsbU16 (uint16_t data);
   197       /**
   198        * \param data data to write in buffer
   199        *
   200        * Write the data in buffer and avance the iterator position
   201        * by four bytes. The data is written in least significant byte order and the
   202        * input data is expected to be in host order.
   203        */
   204       void WriteHtolsbU32 (uint32_t data);
   205       /**
   206        * \param data data to write in buffer
   207        *
   208        * Write the data in buffer and avance the iterator position
   209        * by eight bytes. The data is written in least significant byte order and the
   210        * input data is expected to be in host order.
   211        */
   212       void WriteHtolsbU64 (uint64_t data);
   213       /**
   214        * \param data data to write in buffer
   215        *
   216        * Write the data in buffer and avance the iterator position
   217        * by two bytes. The data is written in least significant byte order and the
   218        * input data is expected to be in host order.
   219        */
   220       void WriteHtonU16 (uint16_t data);
   221       /**
   222        * \param data data to write in buffer
   223        *
   224        * Write the data in buffer and avance the iterator position
   225        * by four bytes. The data is written in network order and the
   226        * input data is expected to be in host order.
   227        */
   228       void WriteHtonU32 (uint32_t data);
   229       /**
   230        * \param data data to write in buffer
   231        *
   232        * Write the data in buffer and avance the iterator position
   233        * by eight bytes. The data is written in network order and the
   234        * input data is expected to be in host order.
   235        */
   236       void WriteHtonU64 (uint64_t data);
   237       /**
   238        * \param buffer a byte buffer to copy in the internal buffer.
   239        * \param size number of bytes to copy.
   240        *
   241        * Write the data in buffer and avance the iterator position
   242        * by size bytes.
   243        */
   244       void Write (uint8_t const*buffer, uint32_t size);
   245       /**
   246        * \param start the start of the data to copy
   247        * \param end the end of the data to copy
   248        *
   249        * Write the data delimited by start and end in internal buffer 
   250        * and avance the iterator position by the number of bytes
   251        * copied.
   252        * The input interators _must_ not point to the same Buffer as
   253        * we do to avoid overlapping copies. This is enforced 
   254        * in debug builds by asserts.
   255        */
   256       void Write (Iterator start, Iterator end);
   257 
   258       /**
   259        * \return the byte read in the buffer.
   260        *
   261        * Read data and advance the Iterator by the number of bytes
   262        * read.
   263        */
   264       BUFFER_INLINE uint8_t  ReadU8 (void);
   265       /**
   266        * \return the two bytes read in the buffer.
   267        *
   268        * Read data and advance the Iterator by the number of bytes
   269        * read.
   270        * The data is read in the format written by writeU16.
   271        */
   272       uint16_t ReadU16 (void);
   273       /**
   274        * \return the four bytes read in the buffer.
   275        *
   276        * Read data and advance the Iterator by the number of bytes
   277        * read.
   278        * The data is read in the format written by writeU32.
   279        */
   280       uint32_t ReadU32 (void);
   281       /**
   282        * \return the eight bytes read in the buffer.
   283        *
   284        * Read data and advance the Iterator by the number of bytes
   285        * read.
   286        * The data is read in the format written by writeU64.
   287        */
   288       uint64_t ReadU64 (void);
   289       /**
   290        * \return the two bytes read in the buffer.
   291        *
   292        * Read data and advance the Iterator by the number of bytes
   293        * read.
   294        * The data is read in network format and return in host format.
   295        */
   296       uint16_t ReadNtohU16 (void);
   297       /**
   298        * \return the four bytes read in the buffer.
   299        *
   300        * Read data and advance the Iterator by the number of bytes
   301        * read.
   302        * The data is read in network format and return in host format.
   303        */
   304       uint32_t ReadNtohU32 (void);
   305       /**
   306        * \return the eight bytes read in the buffer.
   307        *
   308        * Read data and advance the Iterator by the number of bytes
   309        * read.
   310        * The data is read in network format and return in host format.
   311        */
   312       uint64_t ReadNtohU64 (void);
   313       /**
   314        * \return the two bytes read in the buffer.
   315        *
   316        * Read data and advance the Iterator by the number of bytes
   317        * read.
   318        * The data is read in network format and return in host format.
   319        */
   320       uint16_t ReadLsbtohU16 (void);
   321       /**
   322        * \return the four bytes read in the buffer.
   323        *
   324        * Read data and advance the Iterator by the number of bytes
   325        * read.
   326        * The data is read in network format and return in host format.
   327        */
   328       uint32_t ReadLsbtohU32 (void);
   329       /**
   330        * \return the eight bytes read in the buffer.
   331        *
   332        * Read data and advance the Iterator by the number of bytes
   333        * read.
   334        * The data is read in network format and return in host format.
   335        */
   336       uint64_t ReadLsbtohU64 (void);
   337       /**
   338        * \param buffer buffer to copy data into
   339        * \param size number of bytes to copy
   340        *
   341        * Copy size bytes of data from the internal buffer to the
   342        * input buffer and avance the Iterator by the number of
   343        * bytes read.
   344        */
   345       void Read (uint8_t *buffer, uint32_t size);
   346 
   347       /**
   348        * \brief Calculate the checksum.
   349        * \param size size of the buffer.
   350        * \return checksum
   351        */
   352       uint16_t CalculateIpChecksum(uint16_t size);
   353 
   354       /**
   355        * \brief Calculate the checksum.
   356        * \param size size of the buffer.
   357        * \param initialChecksum initial value
   358        * \return checksum
   359        */
   360       uint16_t CalculateIpChecksum(uint16_t size, uint32_t initialChecksum);
   361 
   362       /**
   363        * \returns the size of the underlying buffer we are iterating
   364        */
   365       uint32_t GetSize (void) const;
   366 
   367   private:
   368       friend class Buffer;
   369       Iterator (Buffer const*buffer);
   370       Iterator (Buffer const*buffer, bool);
   371       void Construct (const Buffer *buffer);
   372       bool CheckNoZero (uint32_t start, uint32_t end) const;
   373       bool Check (uint32_t i) const;
   374 
   375     /* offset in virtual bytes from the start of the data buffer to the
   376      * start of the "virtual zero area".
   377      */
   378       uint32_t m_zeroStart;
   379     /* offset in virtual bytes from the start of the data buffer to the
   380      * end of the "virtual zero area".
   381      */
   382       uint32_t m_zeroEnd;
   383     /* offset in virtual bytes from the start of the data buffer to the
   384      * start of the data which can be read by this iterator
   385      */
   386       uint32_t m_dataStart;
   387     /* offset in virtual bytes from the start of the data buffer to the
   388      * end of the data which can be read by this iterator
   389      */
   390       uint32_t m_dataEnd;
   391     /* offset in virtual bytes from the start of the data buffer to the
   392      * current position represented by this iterator.
   393      */
   394       uint32_t m_current;
   395     /* a pointer to the underlying byte buffer. All offsets are relative
   396      * to this pointer.
   397      */
   398       uint8_t *m_data;
   399   };
   400 
   401   /**
   402    * \return the number of bytes stored in this buffer.
   403    */
   404   uint32_t GetSize (void) const;
   405 
   406   /**
   407    * \return a pointer to the start of the internal 
   408    * byte buffer.
   409    *
   410    * The returned pointer points to an area of
   411    * memory which is ns3::Buffer::GetSize () bytes big.
   412    * Please, try to never ever use this method. It is really
   413    * evil and is present only for a few specific uses.
   414    */
   415   uint8_t const*PeekData (void) const;
   416 
   417   /**
   418    * \param start size to reserve
   419    * \returns true if the buffer needed resizing, false otherwise.
   420    *
   421    * Add bytes at the start of the Buffer. The
   422    * content of these bytes is undefined but debugging
   423    * builds initialize them to 0x33.
   424    * Any call to this method invalidates any Iterator
   425    * pointing to this Buffer.
   426    */
   427   bool AddAtStart (uint32_t start);
   428   /**
   429    * \param end size to reserve
   430    * \returns true if the buffer needed resizing, false otherwise.
   431    *
   432    * Add bytes at the end of the Buffer. The
   433    * content of these bytes is undefined but debugging
   434    * builds initialize them to 0x33.
   435    * Any call to this method invalidates any Iterator
   436    * pointing to this Buffer.
   437    */
   438   bool AddAtEnd (uint32_t end);
   439 
   440   /**
   441    * \param o the buffer to append to the end of this buffer.
   442    *
   443    * Add bytes at the end of the Buffer.
   444    * Any call to this method invalidates any Iterator
   445    * pointing to this Buffer.
   446    */
   447   void AddAtEnd (const Buffer &o);
   448   /**
   449    * \param start size to remove
   450    *
   451    * Remove bytes at the start of the Buffer.
   452    * Any call to this method invalidates any Iterator
   453    * pointing to this Buffer.
   454    */
   455   void RemoveAtStart (uint32_t start);
   456   /**
   457    * \param end size to remove
   458    *
   459    * Remove bytes at the end of the Buffer.
   460    * Any call to this method invalidates any Iterator
   461    * pointing to this Buffer.
   462    */
   463   void RemoveAtEnd (uint32_t end);
   464 
   465   /**
   466    * \param start offset from start of packet
   467    * \param length
   468    *
   469    * \return a fragment of size length starting at offset
   470    * start.
   471    */
   472   Buffer CreateFragment (uint32_t start, uint32_t length) const;
   473 
   474   /**
   475    * \return an Iterator which points to the
   476    * start of this Buffer.
   477    */
   478   Buffer::Iterator Begin (void) const;
   479   /**
   480    * \return an Iterator which points to the
   481    * end of this Buffer.
   482    */
   483   Buffer::Iterator End (void) const;
   484 
   485   Buffer CreateFullCopy (void) const;
   486 
   487   int32_t GetCurrentStartOffset (void) const;
   488   int32_t GetCurrentEndOffset (void) const;
   489 
   490   /** 
   491    * Copy the specified amount of data from the buffer to the given output stream.
   492    * 
   493    * @param os the output stream
   494    * @param size the maximum amount of bytes to copy. If zero, nothing is copied.
   495    */
   496   void CopyData (std::ostream *os, uint32_t size) const;
   497 
   498   Buffer (Buffer const &o);
   499   Buffer &operator = (Buffer const &o);
   500   Buffer ();
   501   Buffer (uint32_t dataSize);
   502   ~Buffer ();
   503 private:
   504 
   505   void TransformIntoRealBuffer (void) const;
   506   bool CheckInternalState (void) const;
   507   void Initialize (uint32_t zeroSize);
   508   uint32_t GetInternalSize (void) const;
   509   uint32_t GetInternalEnd (void) const;
   510   static void Recycle (struct BufferData *data);
   511   static struct BufferData *Create (uint32_t size);
   512 
   513   /* This structure is described in the buffer.cc file.
   514    */
   515   struct BufferData *m_data;
   516 #ifdef BUFFER_HEURISTICS
   517   /* keep track of the maximum value of m_zeroAreaStart across
   518    * the lifetime of a Buffer instance. This variable is used
   519    * purely as a source of information for the heuristics which
   520    * decide on the position of the zero area in new buffers.
   521    * It is read from the Buffer destructor to update the global
   522    * heuristic data and these global heuristic data are used from
   523    * the Buffer constructor to choose an initial value for 
   524    * m_zeroAreaStart.
   525    * It is possible to disable all these heuristics by undefining the
   526    * BUFFER_HEURISTICS macro at the top of buffer.h
   527    */
   528   uint32_t m_maxZeroAreaStart;
   529 #endif /* BUFFER_HEURISTICS */
   530   /* offset to the start of the virtual zero area from the start 
   531    * of m_data->m_data
   532    */
   533   uint32_t m_zeroAreaStart;
   534   /* offset to the end of the virtual zero area from the start 
   535    * of m_data->m_data
   536    */
   537   uint32_t m_zeroAreaEnd;
   538   /* offset to the start of the data referenced by this Buffer
   539    * instance from the start of m_data->m_data
   540    */
   541   uint32_t m_start;
   542   /* offset to the end of the data referenced by this Buffer
   543    * instance from the start of m_data->m_data
   544    */
   545   uint32_t m_end;
   546 };
   547 
   548 } // namespace ns3
   549 
   550 #ifdef BUFFER_USE_INLINE
   551 
   552 #include "ns3/assert.h"
   553 #include <string.h>
   554 
   555 namespace ns3 {
   556 
   557 void
   558 Buffer::Iterator::WriteU8 (uint8_t data)
   559 {
   560   NS_ASSERT (Check (m_current));
   561 
   562   if (m_current < m_zeroStart)
   563     {
   564       m_data[m_current] = data;
   565       m_current++;
   566     }
   567   else
   568     {
   569       m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
   570       m_current++;      
   571     }
   572 }
   573 
   574 void 
   575 Buffer::Iterator::WriteU8 (uint8_t  data, uint32_t len)
   576 {
   577   NS_ASSERT (CheckNoZero (m_current, m_current + len));
   578   if (m_current <= m_zeroStart)
   579     {
   580       memset (&(m_data[m_current]), data, len);
   581       m_current += len;
   582     }
   583   else
   584     {
   585       uint8_t *buffer = &m_data[m_current - (m_zeroEnd-m_zeroStart)];
   586       memset (buffer, data, len);
   587       m_current += len;
   588     }
   589 }
   590 
   591 uint8_t  
   592 Buffer::Iterator::ReadU8 (void)
   593 {
   594   NS_ASSERT (m_current >= m_dataStart &&
   595              m_current <= m_dataEnd);
   596 
   597   if (m_current < m_zeroStart)
   598     {
   599       uint8_t data = m_data[m_current];
   600       m_current++;
   601       return data;
   602     }
   603   else if (m_current < m_zeroEnd)
   604     {
   605       m_current++;
   606       return 0;
   607     }
   608   else
   609     {
   610       uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
   611       m_current++;
   612       return data;
   613     }
   614 }
   615 
   616 
   617 } // namespace ns3
   618 
   619 #endif /* BUFFER_USE_INLINE */
   620 
   621 #endif /* BUFFER_H */