1 /** @file
2 
3   I/O classes
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   @section watermark Watermark
24 
25   Watermarks can be used as an interface between the data transferring
26   layer (VConnection) and the user layer (a state machine).  Watermarks
27   should be used when you need to have at least a certain amount of data
28   to make some determination.  For example, when parsing a string, one
29   might wish to ensure that an entire line will come in before consuming
30   the data.  In such a case, the water_mark should be set to the largest
31   possible size of the string. (appropriate error handling should take
32   care of excessively long strings).
33 
34   In all other cases, especially when all data will be consumed, the
35   water_mark should be set to 0 (the default).
36 
37  */
38 
39 #pragma once
40 #define I_IOBuffer_h
41 
42 #include "tscore/ink_platform.h"
43 #include "tscore/ink_apidefs.h"
44 #include "tscore/Allocator.h"
45 #include "tscore/Ptr.h"
46 #include "tscore/ink_assert.h"
47 #include "tscore/ink_resource.h"
48 
49 struct MIOBufferAccessor;
50 
51 class MIOBuffer;
52 class IOBufferReader;
53 class VIO;
54 
55 inkcoreapi extern int64_t max_iobuffer_size;
56 extern int64_t default_small_iobuffer_size;
57 extern int64_t default_large_iobuffer_size; // matched to size of OS buffers
58 
59 enum AllocType {
60   NO_ALLOC,
61   MEMALIGNED,
62   DEFAULT_ALLOC,
63 };
64 
65 #define DEFAULT_BUFFER_NUMBER 128
66 #define DEFAULT_HUGE_BUFFER_NUMBER 32
67 #define MAX_MIOBUFFER_READERS 5
68 #define DEFAULT_BUFFER_ALIGNMENT 8192 // should be disk/page size
69 #define DEFAULT_BUFFER_BASE_SIZE 128
70 
71 ////////////////////////////////////////////////
72 // These are defines so that code that used 2 //
73 // for buffer size index when 2 was 2K will   //
74 // still work if it uses BUFFER_SIZE_INDEX_2K //
75 // instead.                                   //
76 ////////////////////////////////////////////////
77 #define BUFFER_SIZE_INDEX_128 0
78 #define BUFFER_SIZE_INDEX_256 1
79 #define BUFFER_SIZE_INDEX_512 2
80 #define BUFFER_SIZE_INDEX_1K 3
81 #define BUFFER_SIZE_INDEX_2K 4
82 #define BUFFER_SIZE_INDEX_4K 5
83 #define BUFFER_SIZE_INDEX_8K 6
84 #define BUFFER_SIZE_INDEX_16K 7
85 #define BUFFER_SIZE_INDEX_32K 8
86 #define BUFFER_SIZE_INDEX_64K 9
87 #define BUFFER_SIZE_INDEX_128K 10
88 #define BUFFER_SIZE_INDEX_256K 11
89 #define BUFFER_SIZE_INDEX_512K 12
90 #define BUFFER_SIZE_INDEX_1M 13
91 #define BUFFER_SIZE_INDEX_2M 14
92 #define MAX_BUFFER_SIZE_INDEX 14
93 #define DEFAULT_BUFFER_SIZES (MAX_BUFFER_SIZE_INDEX + 1)
94 
95 #define BUFFER_SIZE_FOR_INDEX(_i) (DEFAULT_BUFFER_BASE_SIZE * (1 << (_i)))
96 #define DEFAULT_SMALL_BUFFER_SIZE BUFFER_SIZE_INDEX_512
97 #define DEFAULT_LARGE_BUFFER_SIZE BUFFER_SIZE_INDEX_4K
98 #define DEFAULT_TS_BUFFER_SIZE BUFFER_SIZE_INDEX_8K
99 #define DEFAULT_MAX_BUFFER_SIZE BUFFER_SIZE_FOR_INDEX(MAX_BUFFER_SIZE_INDEX)
100 #define MIN_IOBUFFER_SIZE BUFFER_SIZE_INDEX_128
101 #define MAX_IOBUFFER_SIZE (DEFAULT_BUFFER_SIZES - 1)
102 
103 #define BUFFER_SIZE_ALLOCATED(_i) (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_i) || BUFFER_SIZE_INDEX_IS_XMALLOCED(_i))
104 
105 #define BUFFER_SIZE_NOT_ALLOCATED DEFAULT_BUFFER_SIZES
106 #define BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index) (_size_index < 0)
107 #define BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index) (((uint64_t)_size_index) < DEFAULT_BUFFER_SIZES)
108 #define BUFFER_SIZE_INDEX_IS_CONSTANT(_size_index) (_size_index >= DEFAULT_BUFFER_SIZES)
109 
110 #define BUFFER_SIZE_FOR_XMALLOC(_size) (-(_size))
111 #define BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(_size) (-(_size))
112 
113 #define BUFFER_SIZE_FOR_CONSTANT(_size) (_size - DEFAULT_BUFFER_SIZES)
114 #define BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(_size) (_size + DEFAULT_BUFFER_SIZES)
115 
116 inkcoreapi extern Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES];
117 
118 void init_buffer_allocators(int iobuffer_advice);
119 
120 /**
121   A reference counted wrapper around fast allocated or malloced memory.
122   The IOBufferData class provides two basic services around a portion
123   of allocated memory.
124 
125   First, it is a reference counted object and ...
126 
127   @remarks The AllocType enum, is used to define the type of allocation
128   for the memory this IOBufferData object manages.
129 
130   <table>
131     <tr>
132       <td align="center">AllocType</td>
133       <td align="center">Meaning</td>
134     </tr>
135     <tr>
136       <td>NO_ALLOC</td>
137       <td></td>
138     </tr>
139     <tr>
140       <td>MEMALIGNED</td>
141       <td></td>
142     </tr>
143     <tr>
144       <td>DEFAULT_ALLOC</td>
145       <td></td>
146     </tr>
147   </table>
148 
149  */
150 class IOBufferData : public RefCountObj
151 {
152 public:
153   /**
154     The size of the memory allocated by this IOBufferData. Calculates
155     the amount of memory allocated by this IOBufferData.
156 
157     @return number of bytes allocated for the '_data' member.
158 
159   */
160   int64_t block_size();
161 
162   /**
163     Frees the memory managed by this IOBufferData.  Deallocates the
164     memory previously allocated by this IOBufferData object. It frees
165     the memory pointed to by '_data' according to the '_mem_type' and
166     '_size_index' members.
167 
168   */
169   void dealloc();
170 
171   /**
172     Allocates memory and sets this IOBufferData to point to it.
173     Allocates memory according to the size_index and type
174     parameters. Any previously allocated memory pointed to by
175     this IOBufferData is deallocated.
176 
177     @param size_index
178     @param type of allocation to use; see remarks section.
179   */
180   void alloc(int64_t size_index, AllocType type = DEFAULT_ALLOC);
181 
182   /**
183     Provides access to the allocated memory. Returns the address of the
184     allocated memory handled by this IOBufferData.
185 
186     @return address of the memory handled by this IOBufferData.
187 
188   */
189   char *
data()190   data()
191   {
192     return _data;
193   }
194 
195   /**
196     Cast operator. Provided as a convenience, the cast to a char* applied
197     to the IOBufferData returns the address of the memory handled by the
198     IOBuffer data. In this manner, objects of this class can be used as
199     parameter to functions requiring a char*.
200 
201   */
202   operator char *() { return _data; }
203   /**
204     Frees the IOBufferData object and its underlying memory. Deallocates
205     the memory managed by this IOBufferData and then frees itself. You
206     should not use this object or reference after this call.
207 
208   */
209   void free() override;
210 
211   int64_t _size_index;
212 
213   /**
214     Type of allocation used for the managed memory. Stores the type of
215     allocation used for the memory currently managed by the IOBufferData
216     object. Do not set or modify this value directly. Instead use the
217     alloc or dealloc methods.
218 
219   */
220   AllocType _mem_type = NO_ALLOC;
221 
222   /**
223     Points to the allocated memory. This member stores the address of
224     the allocated memory. You should not modify its value directly,
225     instead use the alloc or dealloc methods.
226 
227   */
228   char *_data = nullptr;
229 
230   const char *_location = nullptr;
231 
232   /**
233     Constructor. Initializes state for a IOBufferData object. Do not use
234     this method. Use one of the functions with the 'new_' prefix instead.
235 
236   */
IOBufferData()237   IOBufferData() : _size_index(BUFFER_SIZE_NOT_ALLOCATED) {}
238 
239   // noncopyable, declaration only
240   IOBufferData(const IOBufferData &) = delete;
241   IOBufferData &operator=(const IOBufferData &) = delete;
242 };
243 
244 inkcoreapi extern ClassAllocator<IOBufferData> ioDataAllocator;
245 
246 /**
247   A linkable portion of IOBufferData. IOBufferBlock is a chainable
248   buffer block descriptor. The IOBufferBlock represents both the used
249   and available space in the underlying block. The IOBufferBlock is not
250   sharable between buffers but rather represents what part of the data
251   block is both in use and usable by the MIOBuffer it is attached to.
252 
253 */
254 class IOBufferBlock : public RefCountObj
255 {
256 public:
257   /**
258     Access the actual data. Provides access to rhe underlying data
259     managed by the IOBufferData.
260 
261     @return pointer to the underlying data.
262 
263   */
264   char *
buf()265   buf()
266   {
267     return data->_data;
268   }
269 
270   /**
271     Beginning of the inuse section. Returns the position in the buffer
272     where the inuse area begins.
273 
274     @return pointer to the start of the inuse section.
275 
276   */
277   char *
start()278   start()
279   {
280     return _start;
281   }
282 
283   /**
284     End of the used space. Returns a pointer to end of the used space
285     in the data buffer represented by this block.
286 
287     @return pointer to the end of the inuse portion of the block.
288 
289   */
290   char *
end()291   end()
292   {
293     return _end;
294   }
295 
296   /**
297     End of the data buffer. Returns a pointer to end of the data buffer
298     represented by this block.
299 
300   */
301   char *
buf_end()302   buf_end()
303   {
304     return _buf_end;
305   }
306 
307   /**
308     Size of the inuse area. Returns the size of the current inuse area.
309 
310     @return bytes occupied by the inuse area.
311 
312   */
313   int64_t
size()314   size()
315   {
316     return (int64_t)(_end - _start);
317   }
318 
319   /**
320     Size of the data available for reading. Returns the size of the data
321     available for reading in the inuse area.
322 
323     @return bytes available for reading from the inuse area.
324 
325   */
326   int64_t
read_avail() const327   read_avail() const
328   {
329     return (int64_t)(_end - _start);
330   }
331 
332   /**
333     Space available in the buffer. Returns the number of bytes that can
334     be written to the data buffer.
335 
336     @return space available for writing in this IOBufferBlock.
337   */
338   int64_t
write_avail()339   write_avail()
340   {
341     return (int64_t)(_buf_end - _end);
342   }
343 
344   /**
345     Size of the memory allocated by the underlying IOBufferData.
346     Computes the size of the entire block, which includes the used and
347     available areas. It is the memory allocated by the IOBufferData
348     referenced by this IOBufferBlock.
349 
350     @return bytes allocated to the IOBufferData referenced by this
351       IOBufferBlock.
352 
353   */
354   int64_t
block_size()355   block_size()
356   {
357     return data->block_size();
358   }
359 
360   /**
361     Decrease the size of the inuse area. Moves forward the start of
362     the inuse area. This also decreases the number of available bytes
363     for reading.
364 
365     @param len bytes to consume or positions to skip for the start of
366       the inuse area.
367 
368   */
369   void consume(int64_t len);
370 
371   /**
372     Increase the inuse area of the block. Adds 'len' bytes to the inuse
373     area of the block. Data should be copied into the data buffer by
374     using end() to find the start of the free space in the data buffer
375     before calling fill()
376 
377     @param len bytes to increase the inuse area. It must be less than
378       or equal to the value of write_avail().
379 
380   */
381   void fill(int64_t len);
382 
383   /**
384     Reset the inuse area. The start and end of the inuse area are reset
385     but the actual IOBufferData referenced by this IOBufferBlock is not
386     modified.  This effectively reduces the number of bytes available
387     for reading to zero, and the number of bytes available for writing
388     to the size of the entire buffer.
389 
390   */
391   void reset();
392 
393   /**
394     Create a copy of the IOBufferBlock. Creates and returns a copy of this
395     IOBufferBlock that references the same data that this IOBufferBlock
396     (it does not allocate an another buffer). The cloned block will not
397     have a writable space since the original IOBufferBlock maintains the
398     ownership for writing data to the block.
399 
400     @return copy of this IOBufferBlock.
401 
402   */
403   IOBufferBlock *clone() const;
404 
405   /**
406     Clear the IOBufferData this IOBufferBlock handles. Clears this
407     IOBufferBlock's reference to the data buffer (IOBufferData). You can
408     use alloc after this call to allocate an IOBufferData associated to
409     this IOBufferBlock.
410 
411   */
412   void clear();
413 
414   /**
415     Allocate a data buffer. Allocates a data buffer for this IOBufferBlock
416     based on index 'i'.  Index values are described in the remarks
417     section in MIOBuffer.
418 
419   */
420   void alloc(int64_t i = default_large_iobuffer_size);
421 
422   /**
423     Clear the IOBufferData this IOBufferBlock handles. Clears this
424     IOBufferBlock's reference to the data buffer (IOBufferData).
425 
426   */
427   void dealloc();
428 
429   /**
430     Set or replace this IOBufferBlock's IOBufferData member. Sets this
431     IOBufferBlock's IOBufferData member to point to the IOBufferData
432     passed in. You can optionally specify the inuse area with the 'len'
433     argument and an offset for the start.
434 
435     @param d new IOBufferData this IOBufferBlock references.
436     @param len in use area to set. It must be less than or equal to the
437       length of the block size *IOBufferData).
438     @param offset bytes to skip from the beginning of the IOBufferData
439       and to mark its start.
440 
441   */
442   void set(IOBufferData *d, int64_t len = 0, int64_t offset = 0);
443   void set_internal(void *b, int64_t len, int64_t asize_index);
444 
445   /**
446     Frees the IOBufferBlock object and its underlying memory.
447     Removes the reference to the IOBufferData object and then frees
448     itself. You should not use this object or reference after this
449     call.
450 
451   */
452   void free() override;
453 
454   char *_start   = nullptr;
455   char *_end     = nullptr;
456   char *_buf_end = nullptr;
457 
458   const char *_location = nullptr;
459 
460   /**
461     The underlying reference to the allocated memory. A reference to a
462     IOBufferData representing the memory allocated to this buffer. Do
463     not set or modify its value directly.
464 
465   */
466   Ptr<IOBufferData> data;
467 
468   /**
469     Reference to another IOBufferBlock. A reference to another
470     IOBufferBlock that allows this object to link to other.
471 
472   */
473   Ptr<IOBufferBlock> next;
474 
475   /**
476     Constructor of a IOBufferBlock. Do not use it to create a new object,
477     instead call new_IOBufferBlock
478 
479   */
480   IOBufferBlock();
481 
482   // noncopyable
483   IOBufferBlock(const IOBufferBlock &) = delete;
484   IOBufferBlock &operator=(const IOBufferBlock &) = delete;
485 };
486 
487 extern inkcoreapi ClassAllocator<IOBufferBlock> ioBlockAllocator;
488 
489 /** A class for holding a chain of IO buffer blocks.
490     This class is intended to be used as a member variable for other classes that
491     need to anchor an IO Buffer chain but don't need the full @c MIOBuffer machinery.
492     That is, the owner is the only reader/writer of the data.
493 
494     This does not handle incremental reads or writes well. The intent is that data is
495     placed in the instance, held for a while, then used and discarded.
496 
497     @note Contrast also with @c IOBufferReader which is similar but requires an
498     @c MIOBuffer as its owner.
499 */
500 class IOBufferChain
501 {
502   using self_type = IOBufferChain; ///< Self reference type.
503 
504 public:
505   /// Default constructor - construct empty chain.
506   IOBufferChain() = default;
507   /// Shallow copy.
508   self_type &operator=(self_type const &that);
509 
510   /// Shallow append.
511   self_type &operator+=(self_type const &that);
512 
513   /// Number of bytes of content.
514   int64_t length() const;
515 
516   /// Copy a chain of @a blocks in to this object up to @a length bytes.
517   /// If @a offset is greater than 0 that many bytes are skipped. Those bytes do not count
518   /// as part of @a length.
519   /// This creates a new chain using existing data blocks. This
520   /// breaks the original chain so that changes there (such as appending blocks)
521   /// is not reflected in this chain.
522   /// @return The number of bytes written to the chain.
523   int64_t write(IOBufferBlock *blocks, int64_t length, int64_t offset = 0);
524 
525   /// Add the content of a buffer block.
526   /// The buffer block is unchanged.
527   int64_t write(IOBufferData *data, int64_t length = 0, int64_t offset = 0);
528 
529   /// Remove @a size bytes of content from the front of the chain.
530   /// @return The actual number of bytes removed.
531   int64_t consume(int64_t size);
532 
533   /// Clear current chain.
534   void clear();
535 
536   /// Get the first block.
537   IOBufferBlock *head();
538   IOBufferBlock const *head() const;
539 
540   /// STL Container support.
541 
542   /// Block iterator.
543   /// @internal The reason for this is to override the increment operator.
544   class const_iterator : public std::forward_iterator_tag
545   {
546     using self_type = const_iterator; ///< Self reference type.
547   protected:
548     /// Current buffer block.
549     IOBufferBlock *_b = nullptr;
550 
551   public:
552     using value_type = const IOBufferBlock; ///< Iterator value type.
553 
554     const_iterator() = default; ///< Default constructor.
555 
556     /// Copy constructor.
557     // cppcheck-suppress noExplicitConstructor; copy constructor
558     const_iterator(self_type const &that);
559 
560     /// Assignment.
561     self_type &operator=(self_type const &that);
562 
563     /// Equality.
564     bool operator==(self_type const &that) const;
565     /// Inequality.
566     bool operator!=(self_type const &that) const;
567 
568     value_type &operator*() const;
569     value_type *operator->() const;
570 
571     self_type &operator++();
572     self_type operator++(int);
573   };
574 
575   class iterator : public const_iterator
576   {
577     using self_type = iterator; ///< Self reference type.
578   public:
579     using value_type = IOBufferBlock; ///< Dereferenced type.
580 
581     value_type &operator*() const;
582     value_type *operator->() const;
583   };
584 
585   using value_type = IOBufferBlock;
586 
587   iterator begin();
588   const_iterator begin() const;
589 
590   iterator end();
591   const_iterator end() const;
592 
593 protected:
594   /// Append @a block.
595   void append(IOBufferBlock *block);
596 
597   /// Head of buffer block chain.
598   Ptr<IOBufferBlock> _head;
599   /// Tail of the block chain.
600   IOBufferBlock *_tail = nullptr;
601   /// The amount of data of interest.
602   /// Not necessarily the amount of data in the chain of blocks.
603   int64_t _len = 0;
604 };
605 
606 /**
607   An independent reader from an MIOBuffer. A reader for a set of
608   IOBufferBlocks. The IOBufferReader represents the place where a given
609   consumer of buffer data is reading from. It provides a uniform interface
610   for easily accessing the data contained in a list of IOBufferBlocks
611   associated with the IOBufferReader.
612 
613   IOBufferReaders are the abstraction that determine when data blocks
614   can be removed from the buffer.
615 
616 */
617 class IOBufferReader
618 {
619 public:
620   /**
621     Start of unconsumed data. Returns a pointer to first unconsumed data
622     on the buffer for this reader. A null pointer indicates no data is
623     available. It uses the current start_offset value.
624 
625     @return pointer to the start of the unconsumed data.
626 
627   */
628   char *start();
629 
630   /**
631     End of inuse area of the first block with unconsumed data. Returns a
632     pointer to the end of the first block with unconsumed data for this
633     reader. A nullptr pointer indicates there are no blocks with unconsumed
634     data for this reader.
635 
636     @return pointer to the end of the first block with unconsumed data.
637 
638   */
639   char *end();
640 
641   /**
642     Amount of data available across all of the IOBufferBlocks. Returns the
643     number of unconsumed bytes of data available to this reader across
644     all remaining IOBufferBlocks. It subtracts the current start_offset
645     value from the total.
646 
647     @return bytes of data available across all the buffers.
648 
649   */
650   int64_t read_avail();
651 
652   /** Check if there is more than @a size bytes available to read.
653       @return @c true if more than @a size byte are available.
654   */
655   bool is_read_avail_more_than(int64_t size);
656 
657   /**
658     Number of IOBufferBlocks with data in the block list. Returns the
659     number of IOBufferBlocks on the block list with data remaining for
660     this reader.
661 
662     @return number of blocks with data for this reader.
663 
664   */
665   int block_count();
666 
667   /**
668     Amount of data available in the first buffer with data for this
669     reader.  Returns the number of unconsumed bytes of data available
670     on the first IOBufferBlock with data for this reader.
671 
672     @return number of unconsumed bytes of data available in the first
673       buffer.
674 
675   */
676   int64_t block_read_avail();
677 
678   /** Get a view of the data available to read.
679    *
680    * @return A view encompassing currently available readable data.
681    */
682   std::string_view block_read_view();
683 
684   void skip_empty_blocks();
685 
686   /**
687     Clears all fields in this IOBuffeReader, rendering it unusable. Drops
688     the reference to the IOBufferBlock list, the accessor, MIOBuffer and
689     resets this reader's state. You have to set those fields in order
690     to use this object again.
691 
692   */
693   void clear();
694 
695   /**
696     Instruct the reader to reset the IOBufferBlock list. Resets the
697     reader to the point to the start of the block where new data will
698     be written. After this call, the start_offset field is set to zero
699     and the list of IOBufferBlocks is set using the associated MIOBuffer.
700 
701   */
702   void reset();
703 
704   /**
705     Consume a number of bytes from this reader's IOBufferBlock
706     list. Advances the current position in the IOBufferBlock list of
707     this reader by n bytes.
708 
709     @param n number of bytes to consume. It must be less than or equal
710       to read_avail().
711 
712   */
713   void consume(int64_t n);
714 
715   /**
716     Create another reader with access to the same data as this
717     IOBufferReader. Allocates a new reader with the same state as this
718     IOBufferReader. This means that the new reader will point to the same
719     list of IOBufferBlocks and to the same buffer position as this reader.
720 
721     @return new reader with the same state as this.
722 
723   */
724   IOBufferReader *clone();
725 
726   /**
727     Deallocate this reader. Removes and deallocates this reader from
728     the underlying MIOBuffer. This IOBufferReader object must not be
729     used after this call.
730 
731   */
732   void dealloc();
733 
734   /**
735     Get a pointer to the first block with data. Returns a pointer to
736     the first IOBufferBlock in the block chain with data available for
737     this reader
738 
739     @return pointer to the first IOBufferBlock in the list with data
740       available for this reader.
741 
742   */
743   IOBufferBlock *get_current_block();
744 
745   /**
746     Consult this reader's MIOBuffer writable space. Queries the MIOBuffer
747     associated with this reader about the amount of writable space
748     available without adding any blocks on the buffer and returns true
749     if it is less than the water mark.
750 
751     @return true if the MIOBuffer associated with this IOBufferReader
752       returns true in MIOBuffer::current_low_water().
753 
754   */
755   bool current_low_water();
756 
757   /**
758     Queries the underlying MIOBuffer about. Returns true if the amount
759     of writable space after adding a block on the underlying MIOBuffer
760     is less than its water mark. This function call may add blocks to
761     the MIOBuffer (see MIOBuffer::low_water()).
762 
763     @return result of MIOBuffer::low_water() on the MIOBuffer for
764       this reader.
765 
766   */
767   bool low_water();
768 
769   /**
770     To see if the amount of data available to the reader is greater than
771     the MIOBuffer's water mark. Indicates whether the amount of data
772     available to this reader exceeds the water mark for this reader's
773     MIOBuffer.
774 
775     @return true if the amount of data exceeds the MIOBuffer's water mark.
776 
777   */
778   bool high_water();
779 
780   /**
781     Perform a memchr() across the list of IOBufferBlocks. Returns the
782     offset from the current start point of the reader to the first
783     occurrence of character 'c' in the buffer.
784 
785     @param c character to look for.
786     @param len number of characters to check. If len exceeds the number
787       of bytes available on the buffer or INT64_MAX is passed in, the
788       number of bytes available to the reader is used. It is independent
789       of the offset value.
790     @param offset number of the bytes to skip over before beginning
791       the operation.
792     @return -1 if c is not found, otherwise position of the first
793       occurrence.
794 
795   */
796   inkcoreapi int64_t memchr(char c, int64_t len = INT64_MAX, int64_t offset = 0);
797 
798   /**
799     Copies and consumes data. Copies len bytes of data from the buffer
800     into the supplied buffer, which must be allocated prior to the call
801     and it must be at large enough for the requested bytes. Once the
802     data is copied, it consumed from the reader.
803 
804     @param buf in which to place the data.
805     @param len bytes to copy and consume. If 'len' exceeds the bytes
806       available to the reader, the number of bytes available is used
807       instead.
808 
809     @return number of bytes copied and consumed.
810 
811   */
812   inkcoreapi int64_t read(void *buf, int64_t len);
813 
814   /**
815     Copy data but do not consume it. Copies 'len' bytes of data from
816     the current buffer into the supplied buffer. The copy skips the
817     number of bytes specified by 'offset' beyond the current point of
818     the reader. It also takes into account the current start_offset value.
819 
820     @param buf in which to place the data. The pointer is modified after
821       the call and points one position after the end of the data copied.
822     @param len bytes to copy. If len exceeds the bytes available to the
823       reader or INT64_MAX is passed in, the number of bytes available is
824       used instead. No data is consumed from the reader in this operation.
825     @param offset bytes to skip from the current position. The parameter
826       is modified after the call.
827     @return pointer to one position after the end of the data copied. The
828       parameter buf is set to this value also.
829 
830   */
831   inkcoreapi char *memcpy(void *buf, int64_t len = INT64_MAX, int64_t offset = 0);
832 
833   /**
834     Subscript operator. Returns a reference to the character at the
835     specified position. You must ensure that it is within an appropriate
836     range.
837 
838     @param i positions beyond the current point of the reader. It must
839       be less than the number of the bytes available to the reader.
840 
841     @return reference to the character in that position.
842 
843   */
844   char &operator[](int64_t i);
845 
846   MIOBuffer *
writer() const847   writer() const
848   {
849     return mbuf;
850   }
851   MIOBuffer *
allocated() const852   allocated() const
853   {
854     return mbuf;
855   }
856 
857   MIOBufferAccessor *accessor = nullptr; // pointer back to the accessor
858 
859   /**
860     Back pointer to this object's MIOBuffer. A pointer back to the
861     MIOBuffer this reader is allocated from.
862 
863   */
864   MIOBuffer *mbuf = nullptr;
865   Ptr<IOBufferBlock> block;
866 
867   /**
868     Offset beyond the shared start(). The start_offset is used in the
869     calls that copy or consume data and is an offset at the beginning
870     of the available data.
871 
872   */
873   int64_t start_offset = 0;
874   int64_t size_limit   = INT64_MAX;
875 
IOBufferReader()876   IOBufferReader() {}
877 };
878 
879 /**
880   A multiple reader, single writer memory buffer. MIOBuffers are at
881   the center of all IOCore data transfer. MIOBuffers are the data
882   buffers used to transfer data to and from VConnections. A MIOBuffer
883   points to a list of IOBufferBlocks which in turn point to IOBufferData
884   structures that in turn point to the actual data. MIOBuffer allows one
885   producer and multiple consumers. The buffer fills up according the
886   amount of data outstanding for the slowest consumer. Thus, MIOBuffer
887   implements automatic flow control between readers of different speeds.
888   Data on IOBuffer is immutable. Once written it cannot be modified, only
889   deallocated once all consumers have finished with it. Immutability is
890   necessary since data can be shared between buffers, which means that
891   multiple IOBufferBlock objects may reference the same data but only
892   one will have ownership for writing.
893 
894 */
895 class MIOBuffer
896 {
897 public:
898   /**
899     Increase writer's inuse area. Instructs the writer associated with
900     this MIOBuffer to increase the inuse area of the block by as much as
901     'len' bytes.
902 
903     @param len number of bytes to add to the inuse area of the block.
904 
905   */
906   void fill(int64_t len);
907 
908   /**
909     Adds a block to the end of the block list. The block added to list
910     must be writable by this buffer and must not be writable by any
911     other buffer.
912 
913   */
914   void append_block(IOBufferBlock *b);
915 
916   /**
917     Adds a new block to the end of the block list. The size is determined
918     by asize_index. See the remarks section for a mapping of indexes to
919     buffer block sizes.
920 
921   */
922   void append_block(int64_t asize_index);
923 
924   /**
925     Adds a new block to the end of the block list. Note that this does nothing when the next block of the current writer exists.
926     The block size is the same as specified size when the buffer was allocated.
927   */
928   void add_block();
929 
930   /**
931     Deprecated
932 
933     TODO: remove this function. Because ats_xmalloc() doesn't exist anymore.
934 
935     Adds by reference len bytes of data pointed to by b to the end
936     of the buffer.  b MUST be a pointer to the beginning of  block
937     allocated from the ats_xmalloc() routine. The data will be deallocated
938     by the buffer once all readers on the buffer have consumed it.
939 
940   */
941   void append_xmalloced(void *b, int64_t len);
942 
943   /**
944     Adds by reference len bytes of data pointed to by b to the end of the
945     buffer. b MUST be a pointer to the beginning of  block allocated from
946     ioBufAllocator of the corresponding index for fast_size_index. The
947     data will be deallocated by the buffer once all readers on the buffer
948     have consumed it.
949 
950   */
951   void append_fast_allocated(void *b, int64_t len, int64_t fast_size_index);
952 
953   /**
954     Adds the nbytes worth of data pointed by rbuf to the buffer. The
955     data is copied into the buffer. write() does not respect watermarks
956     or buffer size limits. Users of write must implement their own flow
957     control. Returns the number of bytes added.
958 
959   */
960   inkcoreapi int64_t write(const void *rbuf, int64_t nbytes);
961 
962   /**
963     Add by data from IOBufferReader r to the this buffer by reference. If
964     len is INT64_MAX, all available data on the reader is added. If len is
965     less than INT64_MAX, the smaller of len or the amount of data on the
966     buffer is added. If offset is greater than zero, than the offset
967     bytes of data at the front of the reader are skipped. Bytes skipped
968     by offset reduce the number of bytes available on the reader used
969     in the amount of data to add computation. write() does not respect
970     watermarks or buffer size limits. Users of write must implement
971     their own flow control. Returns the number of bytes added. Each
972     write() call creates a new IOBufferBlock, even if it is for one
973     byte. As such, it's necessary to exercise caution in any code that
974     repeatedly transfers data from one buffer to another, especially if
975     the data is being read over the network as it may be coming in very
976     small chunks. Because deallocation of outstanding buffer blocks is
977     recursive, it's possible to overrun the stack if too many blocks
978     have been added to the buffer chain. It's imperative that users
979     both implement their own flow control to prevent too many bytes
980     from becoming outstanding on a buffer that the write() call is
981     being used and that care be taken to ensure the transfers are of a
982     minimum size. Should it be necessary to make a large number of small
983     transfers, it's preferable to use a interface that copies the data
984     rather than sharing blocks to prevent a build of blocks on the buffer.
985 
986   */
987   inkcoreapi int64_t write(IOBufferReader *r, int64_t len = INT64_MAX, int64_t offset = 0);
988 
989   /** Copy data from the @a chain to this buffer.
990       New IOBufferBlocks are allocated so this gets a copy of the data that is independent of the source.
991       @a offset bytes are skipped at the start of the @a chain. The length is bounded by @a len and the
992       size in the @a chain.
993 
994       @return the number of bytes copied.
995 
996       @internal I do not like counting @a offset against @a bytes but that's how @c write works...
997   */
998   int64_t write(IOBufferChain const *chain, int64_t len = INT64_MAX, int64_t offset = 0);
999 
1000   /**
1001     Returns a pointer to the first writable block on the block chain.
1002     Returns nullptr if there are not currently any writable blocks on the
1003     block list.
1004   */
1005   IOBufferBlock *
first_write_block()1006   first_write_block()
1007   {
1008     if (_writer) {
1009       if (_writer->next && !_writer->write_avail()) {
1010         return _writer->next.get();
1011       }
1012       ink_assert(!_writer->next || !_writer->next->read_avail());
1013       return _writer.get();
1014     }
1015 
1016     return nullptr;
1017   }
1018 
1019   char *
buf()1020   buf()
1021   {
1022     IOBufferBlock *b = first_write_block();
1023     return b ? b->buf() : nullptr;
1024   }
1025 
1026   char *
buf_end()1027   buf_end()
1028   {
1029     return first_write_block()->buf_end();
1030   }
1031 
1032   char *
start()1033   start()
1034   {
1035     return first_write_block()->start();
1036   }
1037 
1038   char *
end()1039   end()
1040   {
1041     return first_write_block()->end();
1042   }
1043 
1044   /**
1045     Returns the amount of space of available for writing on the first
1046     writable block on the block chain (the one that would be returned
1047     by first_write_block()).
1048 
1049   */
1050   int64_t block_write_avail();
1051 
1052   /**
1053     Returns the amount of space of available for writing on all writable
1054     blocks currently on the block chain.  Will NOT add blocks to the
1055     block chain.
1056 
1057   */
1058   int64_t current_write_avail();
1059 
1060   /**
1061     Adds blocks for writing if the watermark criteria are met. Returns
1062     the amount of space of available for writing on all writable blocks
1063     on the block chain after a block due to the watermark criteria.
1064 
1065   */
1066   int64_t write_avail();
1067 
1068   /**
1069     Returns the default data block size for this buffer.
1070 
1071   */
1072   int64_t block_size();
1073 
1074   /**
1075     Returns true if amount of the data outstanding on the buffer exceeds
1076     the watermark.
1077 
1078   */
1079   bool
high_water()1080   high_water()
1081   {
1082     return is_max_read_avail_more_than(this->water_mark);
1083   }
1084 
1085   /**
1086     Returns true if the amount of writable space after adding a block on
1087     the buffer is less than the water mark. Since this function relies
1088     on write_avail() it may add blocks.
1089 
1090   */
1091   bool
low_water()1092   low_water()
1093   {
1094     return write_avail() <= water_mark;
1095   }
1096 
1097   /**
1098     Returns true if amount the amount writable space without adding and
1099     blocks on the buffer is less than the water mark.
1100 
1101   */
1102   bool
current_low_water()1103   current_low_water()
1104   {
1105     return current_write_avail() <= water_mark;
1106   }
1107 
1108   /**
1109     Allocates a new IOBuffer reader and sets it's its 'accessor' field
1110     to point to 'anAccessor'.
1111 
1112   */
1113   IOBufferReader *alloc_accessor(MIOBufferAccessor *anAccessor);
1114 
1115   /**
1116     Allocates an IOBufferReader for this buffer. IOBufferReaders hold
1117     data on the buffer for different consumers. IOBufferReaders are
1118     REQUIRED when using buffer. alloc_reader() MUST ONLY be a called
1119     on newly allocated buffers. Calling on a buffer with data already
1120     placed on it will result in the reader starting at an indeterminate
1121     place on the buffer.
1122 
1123   */
1124   IOBufferReader *alloc_reader();
1125 
1126   /**
1127     Allocates a new reader on this buffer and places it's starting
1128     point at the same place as reader r. r MUST be a pointer to a reader
1129     previous allocated from this buffer.
1130 
1131   */
1132   IOBufferReader *clone_reader(IOBufferReader *r);
1133 
1134   /**
1135     Deallocates reader e from this buffer. e MUST be a pointer to a reader
1136     previous allocated from this buffer. Reader need to allocated when a
1137     particularly consumer is being removed from the buffer but the buffer
1138     is still in use. Deallocation is not necessary when the buffer is
1139     being freed as all outstanding readers are automatically deallocated.
1140 
1141   */
1142   void dealloc_reader(IOBufferReader *e);
1143 
1144   /**
1145     Deallocates all outstanding readers on the buffer.
1146 
1147   */
1148   void dealloc_all_readers();
1149 
1150   void set(void *b, int64_t len);
1151   void alloc(int64_t i = default_large_iobuffer_size);
1152   void append_block_internal(IOBufferBlock *b);
1153   int64_t write(IOBufferBlock const *b, int64_t len, int64_t offset);
1154 
1155   // internal interface
1156 
1157   /**
1158     Get the maximum amount of available data across all of the readers.
1159     If there're no allocated reader, return available data size of current writer.
1160 
1161     This calls IOBufferReader::read_avail() and it could be expensive when it has a ton of IOBufferBlock.
1162     The `is_max_read_avail(int64_t size)` is preferred if possible.
1163 
1164     @return maximum amount of available data
1165    */
1166   int64_t max_read_avail();
1167 
1168   /**
1169     Check if there is more than @a size bytes available to read.
1170 
1171     @return @c true if more than @a size byte are available.
1172   */
1173   bool is_max_read_avail_more_than(int64_t size);
1174 
1175   int max_block_count();
1176   void check_add_block();
1177 
1178   IOBufferBlock *get_current_block();
1179 
1180   void
reset()1181   reset()
1182   {
1183     if (_writer) {
1184       _writer->reset();
1185     }
1186     for (auto &reader : readers) {
1187       if (reader.allocated()) {
1188         reader.reset();
1189       }
1190     }
1191   }
1192 
1193   void
init_readers()1194   init_readers()
1195   {
1196     for (auto &reader : readers) {
1197       if (reader.allocated() && !reader.block) {
1198         reader.block = _writer;
1199       }
1200     }
1201   }
1202 
1203   void
dealloc()1204   dealloc()
1205   {
1206     _writer = nullptr;
1207     dealloc_all_readers();
1208   }
1209 
1210   void
clear()1211   clear()
1212   {
1213     dealloc();
1214     size_index = BUFFER_SIZE_NOT_ALLOCATED;
1215     water_mark = 0;
1216   }
1217 
1218   int64_t size_index;
1219 
1220   /**
1221     Determines when to stop writing or reading. The watermark is the
1222     level to which the producer (filler) is required to fill the buffer
1223     before it can expect the reader to consume any data.  A watermark
1224     of zero means that the reader will consume any amount of data,
1225     no matter how small.
1226 
1227   */
1228   int64_t water_mark;
1229 
1230   Ptr<IOBufferBlock> _writer;
1231   IOBufferReader readers[MAX_MIOBUFFER_READERS];
1232 
1233   const char *_location = nullptr;
1234 
1235   MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark);
1236   // cppcheck-suppress noExplicitConstructor; allow implicit conversion
1237   MIOBuffer(int64_t default_size_index);
1238   MIOBuffer();
1239   ~MIOBuffer();
1240 };
1241 
1242 /**
1243   A wrapper for either a reader or a writer of an MIOBuffer.
1244 
1245 */
1246 struct MIOBufferAccessor {
1247   IOBufferReader *
readerMIOBufferAccessor1248   reader() const
1249   {
1250     return entry;
1251   }
1252 
1253   MIOBuffer *
writerMIOBufferAccessor1254   writer() const
1255   {
1256     return mbuf;
1257   }
1258 
1259   int64_t
block_sizeMIOBufferAccessor1260   block_size() const
1261   {
1262     return mbuf->block_size();
1263   }
1264 
1265   void reader_for(IOBufferReader *abuf);
1266   void reader_for(MIOBuffer *abuf);
1267   void writer_for(MIOBuffer *abuf);
1268 
1269   void
clearMIOBufferAccessor1270   clear()
1271   {
1272     mbuf  = nullptr;
1273     entry = nullptr;
1274   }
1275 
MIOBufferAccessorMIOBufferAccessor1276   MIOBufferAccessor() {}
1277 
1278   ~MIOBufferAccessor();
1279 
1280 #ifdef DEBUG
1281   const char *name = nullptr;
1282 #endif
1283 
1284   // noncopyable
1285   MIOBufferAccessor(const MIOBufferAccessor &) = delete;
1286   MIOBufferAccessor &operator=(const MIOBufferAccessor &) = delete;
1287 
1288 private:
1289   MIOBuffer *mbuf       = nullptr;
1290   IOBufferReader *entry = nullptr;
1291 };
1292 
1293 extern MIOBuffer *new_MIOBuffer_internal(const char *loc, int64_t size_index = default_large_iobuffer_size);
1294 
1295 class MIOBuffer_tracker
1296 {
1297   const char *loc;
1298 
1299 public:
MIOBuffer_tracker(const char * _loc)1300   explicit MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1301   MIOBuffer *
operator ()(int64_t size_index=default_large_iobuffer_size)1302   operator()(int64_t size_index = default_large_iobuffer_size)
1303   {
1304     return new_MIOBuffer_internal(loc, size_index);
1305   }
1306 };
1307 
1308 extern MIOBuffer *new_empty_MIOBuffer_internal(const char *loc, int64_t size_index = default_large_iobuffer_size);
1309 
1310 class Empty_MIOBuffer_tracker
1311 {
1312   const char *loc;
1313 
1314 public:
Empty_MIOBuffer_tracker(const char * _loc)1315   explicit Empty_MIOBuffer_tracker(const char *_loc) : loc(_loc) {}
1316   MIOBuffer *
operator ()(int64_t size_index=default_large_iobuffer_size)1317   operator()(int64_t size_index = default_large_iobuffer_size)
1318   {
1319     return new_empty_MIOBuffer_internal(loc, size_index);
1320   }
1321 };
1322 
1323 /// MIOBuffer allocator/deallocator
1324 #define new_MIOBuffer MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1325 #define new_empty_MIOBuffer Empty_MIOBuffer_tracker(RES_PATH("memory/IOBuffer/"))
1326 extern void free_MIOBuffer(MIOBuffer *mio);
1327 //////////////////////////////////////////////////////////////////////
1328 
1329 extern IOBufferBlock *new_IOBufferBlock_internal(const char *loc);
1330 
1331 extern IOBufferBlock *new_IOBufferBlock_internal(const char *loc, IOBufferData *d, int64_t len = 0, int64_t offset = 0);
1332 
1333 class IOBufferBlock_tracker
1334 {
1335   const char *loc;
1336 
1337 public:
IOBufferBlock_tracker(const char * _loc)1338   explicit IOBufferBlock_tracker(const char *_loc) : loc(_loc) {}
1339   IOBufferBlock *
operator ()()1340   operator()()
1341   {
1342     return new_IOBufferBlock_internal(loc);
1343   }
1344   IOBufferBlock *
operator ()(Ptr<IOBufferData> & d,int64_t len=0,int64_t offset=0)1345   operator()(Ptr<IOBufferData> &d, int64_t len = 0, int64_t offset = 0)
1346   {
1347     return new_IOBufferBlock_internal(loc, d.get(), len, offset);
1348   }
1349 };
1350 
1351 /// IOBufferBlock allocator
1352 #define new_IOBufferBlock IOBufferBlock_tracker(RES_PATH("memory/IOBuffer/"))
1353 ////////////////////////////////////////////////////////////
1354 
1355 extern IOBufferData *new_IOBufferData_internal(const char *location, int64_t size_index = default_large_iobuffer_size,
1356                                                AllocType type = DEFAULT_ALLOC);
1357 
1358 extern IOBufferData *new_xmalloc_IOBufferData_internal(const char *location, void *b, int64_t size);
1359 
1360 class IOBufferData_tracker
1361 {
1362   const char *loc;
1363 
1364 public:
IOBufferData_tracker(const char * _loc)1365   explicit IOBufferData_tracker(const char *_loc) : loc(_loc) {}
1366   IOBufferData *
operator ()(int64_t size_index=default_large_iobuffer_size,AllocType type=DEFAULT_ALLOC)1367   operator()(int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC)
1368   {
1369     return new_IOBufferData_internal(loc, size_index, type);
1370   }
1371 };
1372 
1373 // TODO: remove new_xmalloc_IOBufferData. Because ats_xmalloc() doesn't exist anymore.
1374 #define new_IOBufferData IOBufferData_tracker(RES_PATH("memory/IOBuffer/"))
1375 #define new_xmalloc_IOBufferData(b, size) new_xmalloc_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), (b), (size))
1376 
1377 extern int64_t iobuffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size);
1378 extern int64_t index_to_buffer_size(int64_t idx);
1379 /**
1380   Clone a IOBufferBlock chain. Used to snarf a IOBufferBlock chain
1381   w/o copy.
1382 
1383   @param b head of source IOBufferBlock chain.
1384   @param offset # bytes in the beginning to skip.
1385   @param len bytes to copy from source.
1386   @return ptr to head of new IOBufferBlock chain.
1387 
1388 */
1389 extern IOBufferBlock *iobufferblock_clone(IOBufferBlock *b, int64_t offset, int64_t len);
1390 /**
1391   Skip over specified bytes in chain. Used for dropping references.
1392 
1393   @param b head of source IOBufferBlock chain.
1394   @param poffset originally offset in b, finally offset in returned
1395     IOBufferBlock.
1396   @param plen value of write is subtracted from plen in the function.
1397   @param write bytes to skip.
1398   @return ptr to head of new IOBufferBlock chain.
1399 
1400 */
1401 extern IOBufferBlock *iobufferblock_skip(IOBufferBlock *b, int64_t *poffset, int64_t *plen, int64_t write);
1402 
1403 inline IOBufferChain &
operator =(self_type const & that)1404 IOBufferChain::operator=(self_type const &that)
1405 {
1406   _head = that._head;
1407   _tail = that._tail;
1408   _len  = that._len;
1409   return *this;
1410 }
1411 
1412 inline IOBufferChain &
operator +=(self_type const & that)1413 IOBufferChain::operator+=(self_type const &that)
1414 {
1415   if (nullptr == _head)
1416     *this = that;
1417   else {
1418     _tail->next = that._head;
1419     _tail       = that._tail;
1420     _len += that._len;
1421   }
1422   return *this;
1423 }
1424 
1425 inline int64_t
length() const1426 IOBufferChain::length() const
1427 {
1428   return _len;
1429 }
1430 
1431 inline IOBufferBlock const *
head() const1432 IOBufferChain::head() const
1433 {
1434   return _head.get();
1435 }
1436 
1437 inline IOBufferBlock *
head()1438 IOBufferChain::head()
1439 {
1440   return _head.get();
1441 }
1442 
1443 inline void
clear()1444 IOBufferChain::clear()
1445 {
1446   _head = nullptr;
1447   _tail = nullptr;
1448   _len  = 0;
1449 }
1450 
const_iterator(self_type const & that)1451 inline IOBufferChain::const_iterator::const_iterator(self_type const &that) : _b(that._b) {}
1452 
1453 inline IOBufferChain::const_iterator &
operator =(self_type const & that)1454 IOBufferChain::const_iterator::operator=(self_type const &that)
1455 {
1456   _b = that._b;
1457   return *this;
1458 }
1459 
1460 inline bool
operator ==(self_type const & that) const1461 IOBufferChain::const_iterator::operator==(self_type const &that) const
1462 {
1463   return _b == that._b;
1464 }
1465 
1466 inline bool
operator !=(self_type const & that) const1467 IOBufferChain::const_iterator::operator!=(self_type const &that) const
1468 {
1469   return _b != that._b;
1470 }
1471 
1472 inline IOBufferChain::const_iterator::value_type &
operator *() const1473 IOBufferChain::const_iterator::operator*() const
1474 {
1475   return *_b;
1476 }
1477 
1478 inline IOBufferChain::const_iterator::value_type *
operator ->() const1479 IOBufferChain::const_iterator::operator->() const
1480 {
1481   return _b;
1482 }
1483 
1484 inline IOBufferChain::const_iterator &
operator ++()1485 IOBufferChain::const_iterator::operator++()
1486 {
1487   _b = _b->next.get();
1488   return *this;
1489 }
1490 
1491 inline IOBufferChain::const_iterator
operator ++(int)1492 IOBufferChain::const_iterator::operator++(int)
1493 {
1494   self_type pre{*this};
1495   ++*this;
1496   return pre;
1497 }
1498 
1499 inline IOBufferChain::iterator::value_type &
operator *() const1500 IOBufferChain::iterator::operator*() const
1501 {
1502   return *_b;
1503 }
1504 
1505 inline IOBufferChain::iterator::value_type *
operator ->() const1506 IOBufferChain::iterator::operator->() const
1507 {
1508   return _b;
1509 }
1510