bug 639: Buffer::CopyData is buggy.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2005,2006,2007 INRIA
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;
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.
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
18 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
27 #define BUFFER_HEURISTICS 1
28 #define BUFFER_USE_INLINE 1
31 #ifdef BUFFER_USE_INLINE
32 #define BUFFER_INLINE inline
42 * \brief automatically resized byte buffer
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.
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.
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
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.
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
85 * Real byte buffer: |********xxxxxxxxxxxx.........*****|
87 * |-------------------^ m_zeroAreaStart
88 * |-----------------------------^ m_end - (m_zeroAreaEnd - m_zeroAreaStart)
89 * virtual byte buffer: |xxxxxxxxxxxx0000000000000.........|
91 * |--------------------^ m_zeroAreaStart
92 * |---------------------------------^ m_zeroAreaEnd
93 * |------------------------------------------^ m_end
95 * A simple state invariant is that m_start <= m_zeroStart <= m_zeroEnd <= m_end
101 * \brief iterator in a Buffer instance
108 * go forward by one byte
112 * go backward by one byte
116 * \param delta number of bytes to go forward
118 void Next (uint32_t delta);
120 * \param delta number of bytes to go backward
122 void Prev (uint32_t delta);
124 * \param o the second iterator
125 * \return number of bytes included between the two iterators
127 * This method works only if the two iterators point
128 * to the same underlying buffer. Debug builds ensure
129 * this with an assert.
131 uint32_t GetDistanceFrom (Iterator const &o) const;
134 * \return true if this iterator points to the end of the byte array.
137 bool IsEnd (void) const;
139 * \return true if this iterator points to the start of the byte array.
142 bool IsStart (void) const;
145 * \param data data to write in buffer
147 * Write the data in buffer and avance the iterator position
150 BUFFER_INLINE void WriteU8 (uint8_t data);
152 * \param data data to write in buffer
153 * \param len number of times data must be written in buffer
155 * Write the data in buffer len times and avance the iterator position
158 BUFFER_INLINE void WriteU8 (uint8_t data, uint32_t len);
160 * \param data data to write in buffer
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.
168 void WriteU16 (uint16_t data);
170 * \param data data to write in buffer
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.
178 void WriteU32 (uint32_t data);
180 * \param data data to write in buffer
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.
188 void WriteU64 (uint64_t data);
190 * \param data data to write in buffer
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.
196 void WriteHtolsbU16 (uint16_t data);
198 * \param data data to write in buffer
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.
204 void WriteHtolsbU32 (uint32_t data);
206 * \param data data to write in buffer
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.
212 void WriteHtolsbU64 (uint64_t data);
214 * \param data data to write in buffer
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.
220 void WriteHtonU16 (uint16_t data);
222 * \param data data to write in buffer
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.
228 void WriteHtonU32 (uint32_t data);
230 * \param data data to write in buffer
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.
236 void WriteHtonU64 (uint64_t data);
238 * \param buffer a byte buffer to copy in the internal buffer.
239 * \param size number of bytes to copy.
241 * Write the data in buffer and avance the iterator position
244 void Write (uint8_t const*buffer, uint32_t size);
246 * \param start the start of the data to copy
247 * \param end the end of the data to copy
249 * Write the data delimited by start and end in internal buffer
250 * and avance the iterator position by the number of bytes
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.
256 void Write (Iterator start, Iterator end);
259 * \return the byte read in the buffer.
261 * Read data and advance the Iterator by the number of bytes
264 BUFFER_INLINE uint8_t ReadU8 (void);
266 * \return the two bytes read in the buffer.
268 * Read data and advance the Iterator by the number of bytes
270 * The data is read in the format written by writeU16.
272 uint16_t ReadU16 (void);
274 * \return the four bytes read in the buffer.
276 * Read data and advance the Iterator by the number of bytes
278 * The data is read in the format written by writeU32.
280 uint32_t ReadU32 (void);
282 * \return the eight bytes read in the buffer.
284 * Read data and advance the Iterator by the number of bytes
286 * The data is read in the format written by writeU64.
288 uint64_t ReadU64 (void);
290 * \return the two bytes read in the buffer.
292 * Read data and advance the Iterator by the number of bytes
294 * The data is read in network format and return in host format.
296 uint16_t ReadNtohU16 (void);
298 * \return the four bytes read in the buffer.
300 * Read data and advance the Iterator by the number of bytes
302 * The data is read in network format and return in host format.
304 uint32_t ReadNtohU32 (void);
306 * \return the eight bytes read in the buffer.
308 * Read data and advance the Iterator by the number of bytes
310 * The data is read in network format and return in host format.
312 uint64_t ReadNtohU64 (void);
314 * \return the two bytes read in the buffer.
316 * Read data and advance the Iterator by the number of bytes
318 * The data is read in network format and return in host format.
320 uint16_t ReadLsbtohU16 (void);
322 * \return the four bytes read in the buffer.
324 * Read data and advance the Iterator by the number of bytes
326 * The data is read in network format and return in host format.
328 uint32_t ReadLsbtohU32 (void);
330 * \return the eight bytes read in the buffer.
332 * Read data and advance the Iterator by the number of bytes
334 * The data is read in network format and return in host format.
336 uint64_t ReadLsbtohU64 (void);
338 * \param buffer buffer to copy data into
339 * \param size number of bytes to copy
341 * Copy size bytes of data from the internal buffer to the
342 * input buffer and avance the Iterator by the number of
345 void Read (uint8_t *buffer, uint32_t size);
348 * \brief Calculate the checksum.
349 * \param size size of the buffer.
352 uint16_t CalculateIpChecksum(uint16_t size);
355 * \brief Calculate the checksum.
356 * \param size size of the buffer.
357 * \param initialChecksum initial value
360 uint16_t CalculateIpChecksum(uint16_t size, uint32_t initialChecksum);
363 * \returns the size of the underlying buffer we are iterating
365 uint32_t GetSize (void) const;
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;
375 /* offset in virtual bytes from the start of the data buffer to the
376 * start of the "virtual zero area".
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".
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
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
391 /* offset in virtual bytes from the start of the data buffer to the
392 * current position represented by this iterator.
395 /* a pointer to the underlying byte buffer. All offsets are relative
402 * \return the number of bytes stored in this buffer.
404 uint32_t GetSize (void) const;
407 * \return a pointer to the start of the internal
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.
415 uint8_t const*PeekData (void) const;
418 * \param start size to reserve
419 * \returns true if the buffer needed resizing, false otherwise.
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.
427 bool AddAtStart (uint32_t start);
429 * \param end size to reserve
430 * \returns true if the buffer needed resizing, false otherwise.
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.
438 bool AddAtEnd (uint32_t end);
441 * \param o the buffer to append to the end of this buffer.
443 * Add bytes at the end of the Buffer.
444 * Any call to this method invalidates any Iterator
445 * pointing to this Buffer.
447 void AddAtEnd (const Buffer &o);
449 * \param start size to remove
451 * Remove bytes at the start of the Buffer.
452 * Any call to this method invalidates any Iterator
453 * pointing to this Buffer.
455 void RemoveAtStart (uint32_t start);
457 * \param end size to remove
459 * Remove bytes at the end of the Buffer.
460 * Any call to this method invalidates any Iterator
461 * pointing to this Buffer.
463 void RemoveAtEnd (uint32_t end);
466 * \param start offset from start of packet
469 * \return a fragment of size length starting at offset
472 Buffer CreateFragment (uint32_t start, uint32_t length) const;
475 * \return an Iterator which points to the
476 * start of this Buffer.
478 Buffer::Iterator Begin (void) const;
480 * \return an Iterator which points to the
481 * end of this Buffer.
483 Buffer::Iterator End (void) const;
485 Buffer CreateFullCopy (void) const;
487 int32_t GetCurrentStartOffset (void) const;
488 int32_t GetCurrentEndOffset (void) const;
491 * Copy the specified amount of data from the buffer to the given output stream.
493 * @param os the output stream
494 * @param size the maximum amount of bytes to copy. If zero, nothing is copied.
496 void CopyData (std::ostream *os, uint32_t size) const;
498 Buffer (Buffer const &o);
499 Buffer &operator = (Buffer const &o);
501 Buffer (uint32_t dataSize);
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);
513 /* This structure is described in the buffer.cc file.
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
525 * It is possible to disable all these heuristics by undefining the
526 * BUFFER_HEURISTICS macro at the top of buffer.h
528 uint32_t m_maxZeroAreaStart;
529 #endif /* BUFFER_HEURISTICS */
530 /* offset to the start of the virtual zero area from the start
533 uint32_t m_zeroAreaStart;
534 /* offset to the end of the virtual zero area from the start
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
542 /* offset to the end of the data referenced by this Buffer
543 * instance from the start of m_data->m_data
550 #ifdef BUFFER_USE_INLINE
552 #include "ns3/assert.h"
558 Buffer::Iterator::WriteU8 (uint8_t data)
560 NS_ASSERT (Check (m_current));
562 if (m_current < m_zeroStart)
564 m_data[m_current] = data;
569 m_data[m_current - (m_zeroEnd-m_zeroStart)] = data;
575 Buffer::Iterator::WriteU8 (uint8_t data, uint32_t len)
577 NS_ASSERT (CheckNoZero (m_current, m_current + len));
578 if (m_current <= m_zeroStart)
580 memset (&(m_data[m_current]), data, len);
585 uint8_t *buffer = &m_data[m_current - (m_zeroEnd-m_zeroStart)];
586 memset (buffer, data, len);
592 Buffer::Iterator::ReadU8 (void)
594 NS_ASSERT (m_current >= m_dataStart &&
595 m_current <= m_dataEnd);
597 if (m_current < m_zeroStart)
599 uint8_t data = m_data[m_current];
603 else if (m_current < m_zeroEnd)
610 uint8_t data = m_data[m_current - (m_zeroEnd-m_zeroStart)];
619 #endif /* BUFFER_USE_INLINE */
621 #endif /* BUFFER_H */