Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2016-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines the chip::System::PacketBuffer class,
22 : * which provides the mechanisms for manipulating packets of *
23 : * octet-serialized data.
24 : */
25 :
26 : #pragma once
27 :
28 : // Include configuration header
29 : #include <system/SystemPacketBufferInternal.h>
30 :
31 : // Include dependent headers
32 : #include <lib/support/BufferWriter.h>
33 : #include <lib/support/CodeUtils.h>
34 : #include <lib/support/DLLUtil.h>
35 : #include <system/SystemAlignSize.h>
36 : #include <system/SystemError.h>
37 :
38 : #include <stddef.h>
39 : #include <utility>
40 :
41 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
42 : #include <lwip/mem.h>
43 : #include <lwip/memp.h>
44 : #include <lwip/pbuf.h>
45 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
46 :
47 : namespace chip {
48 : namespace System {
49 :
50 : class PacketBufferHandle;
51 :
52 : #if !CHIP_SYSTEM_CONFIG_USE_LWIP
53 : struct pbuf
54 : {
55 : struct pbuf * next;
56 : void * payload;
57 : size_t tot_len;
58 : size_t len;
59 : uint16_t ref;
60 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
61 : size_t alloc_size;
62 : #endif
63 : };
64 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
65 :
66 : /** @class PacketBuffer
67 : *
68 : * @brief
69 : * The packet buffer class is the core structure used for manipulating packets of octet-serialized data, usually in the
70 : * context of a data communications network, like Bluetooth or the Internet protocol.
71 : *
72 : * In LwIP-based environments, this class is built on top of the pbuf structure defined in that library. In the absence of
73 : * LwIP, chip provides either a malloc-based implementation, or a pool-based implementation that closely approximates the
74 : * memory challenges of deeply embedded devices.
75 : *
76 : * The PacketBuffer class, like many similar structures used in layered network stacks, provide a mechanism to reserve space
77 : * for protocol headers at each layer of a configurable communication stack. For details, see `PacketBufferHandle::New()`
78 : * as well as LwIP documentation.
79 : *
80 : * PacketBuffer objects are reference-counted, and normally held and used through a PacketBufferHandle that owns one of the
81 : * counted references. When a PacketBufferHandle goes out of scope, its reference is released. To take ownership, a function
82 : * takes a PacketBufferHandle by value. To borrow ownership, a function takes a `const PacketBufferHandle &`.
83 : *
84 : * New objects of PacketBuffer class are initialized at the beginning of an allocation of memory obtained from the underlying
85 : * environment, e.g. from LwIP pbuf target pools, from the standard C library heap, from an internal buffer pool. In the
86 : * simple pool case, the size of the data buffer is PacketBuffer::kBlockSize.
87 : *
88 : * PacketBuffer objects may be chained to accommodate larger payloads. Chaining, however, is not transparent, and users of the
89 : * class must explicitly decide to support chaining. Examples of classes written with chaining support are as follows:
90 : *
91 : * @ref chip::TLVReader
92 : * @ref chip::TLVWriter
93 : *
94 : * ### PacketBuffer format
95 : *
96 : * <pre>
97 : * ┌────────────────────────────────────┐
98 : * │ ┌────────────────────┐ │
99 : * │ │ │◁──────┴───────▷│
100 : * ┏━━━━━━━━┿━━━━━━━┿━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┓
101 : * ┃ pbuf len payload ┃ reserve ┃ data ┃ unused ┃
102 : * ┗━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━┛
103 : * │ │← ReservedSize() →│← DataLength() →│← AvailableDataLength() →│
104 : * │ │ │← MaxDataLength() → · · · · · · · · · · ·→│
105 : * │ │ Start() │
106 : * │← kStructureSize →│← AllocSize() → · · · · · · · · · · · · · · · · · · · · · · →│
107 : * </pre>
108 : *
109 : */
110 : class DLL_EXPORT PacketBuffer : private pbuf
111 : {
112 : private:
113 : // The effective size of the packet buffer structure.
114 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
115 : static constexpr size_t kStructureSize = LWIP_MEM_ALIGN_SIZE(sizeof(struct ::pbuf));
116 : #else // CHIP_SYSTEM_CONFIG_USE_LWIP
117 : static constexpr size_t kStructureSize = CHIP_SYSTEM_ALIGN_SIZE(sizeof(::chip::System::pbuf), 4u);
118 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
119 :
120 : public:
121 : /**
122 : * The maximum size of a regular buffer an application can allocate with no protocol header reserve.
123 : */
124 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
125 : static constexpr size_t kMaxSizeWithoutReserve = LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE);
126 : #else
127 : static constexpr size_t kMaxSizeWithoutReserve = CHIP_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX;
128 : #endif
129 :
130 : /**
131 : * The number of bytes to reserve in a network packet buffer to contain all the possible protocol encapsulation headers
132 : * before the application data.
133 : */
134 : static constexpr uint16_t kDefaultHeaderReserve = CHIP_SYSTEM_CONFIG_HEADER_RESERVE_SIZE;
135 :
136 : /**
137 : * The maximum size of a regular buffer an application can allocate with the default protocol header reserve.
138 : */
139 : static constexpr size_t kMaxSize = kMaxSizeWithoutReserve - kDefaultHeaderReserve;
140 :
141 : /**
142 : * The maximum size of a large buffer(> IPv6 MTU) that an application can allocate with no protocol header reserve.
143 : */
144 : static constexpr size_t kLargeBufMaxSizeWithoutReserve = CHIP_SYSTEM_CONFIG_MAX_LARGE_BUFFER_SIZE_BYTES;
145 :
146 : /**
147 : * The maximum size of a large buffer(> IPv6 MTU) that an application can allocate with the default protocol header reserve.
148 : */
149 : static constexpr size_t kLargeBufMaxSize = kLargeBufMaxSizeWithoutReserve - kDefaultHeaderReserve;
150 :
151 : /**
152 : * Unified constant(both regular and large buffers) for the maximum size that an application can allocate with no
153 : * protocol header reserve.
154 : */
155 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
156 : static constexpr size_t kMaxAllocSize = kLargeBufMaxSizeWithoutReserve;
157 : #else
158 : static constexpr size_t kMaxAllocSize = kMaxSizeWithoutReserve;
159 : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
160 :
161 : /**
162 : * Return the size of the allocation including the reserved and payload data spaces but not including space
163 : * allocated for the PacketBuffer structure.
164 : *
165 : * @note The allocation size is equal to or greater than the \c aAllocSize parameter to the \c Create method).
166 : *
167 : * @return size of the allocation
168 : */
169 199876 : size_t AllocSize() const
170 : {
171 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_LWIP_STANDARD_POOL || CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL
172 : return kMaxSizeWithoutReserve;
173 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_HEAP
174 199876 : return this->alloc_size;
175 : #elif CHIP_SYSTEM_PACKETBUFFER_FROM_LWIP_CUSTOM_POOL
176 : // Temporary workaround for custom pbufs by assuming size to be PBUF_POOL_BUFSIZE
177 : if (this->flags & PBUF_FLAG_IS_CUSTOM)
178 : return LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - kStructureSize;
179 : else
180 : return LWIP_MEM_ALIGN_SIZE(memp_sizes[this->pool]) - kStructureSize;
181 : #elif CHIP_SYSTEM_CONFIG_PACKETBUFFER_LWIP_PBUF_RAM
182 : return PacketBuffer::kMaxAllocSize;
183 : #else
184 : #error "Unimplemented PacketBuffer storage case"
185 : #endif
186 : }
187 :
188 : /**
189 : * Get a pointer to the start of data in a buffer.
190 : *
191 : * @return pointer to the start of data.
192 : */
193 571418 : uint8_t * Start() const { return static_cast<uint8_t *>(this->payload); }
194 :
195 : /**
196 : * Set the the start of data in a buffer, adjusting length and total length accordingly.
197 : *
198 : * @note The data within the buffer is not moved, only accounting information is changed. The function is commonly used to
199 : * either strip or prepend protocol headers in a zero-copy way.
200 : *
201 : * @note This call should not be used on any buffer that is not the head of a buffer chain, as it only alters the current
202 : * buffer.
203 : *
204 : * @param[in] aNewStart - A pointer to where the new payload should start. newStart will be adjusted internally to fall within
205 : * the boundaries of the first buffer in the PacketBuffer chain.
206 : */
207 : void SetStart(uint8_t * aNewStart);
208 :
209 : /**
210 : * Get the length, in bytes, of data in a packet buffer.
211 : *
212 : * @return length, in bytes (current payload length).
213 : */
214 250504 : size_t DataLength() const { return this->len; }
215 :
216 : /**
217 : * Set the length, in bytes, of data in a packet buffer, adjusting total length accordingly.
218 : *
219 : * The function sets the length, in bytes, of the data in the buffer, adjusting the total length appropriately. When the buffer
220 : * is not the head of the buffer chain (common case: the caller adds data to the last buffer in the PacketBuffer chain prior to
221 : * calling higher layers), the aChainHead __must__ be passed in to properly adjust the total lengths of each buffer ahead of
222 : * the current buffer.
223 : *
224 : * @param[in] aNewLen - new length, in bytes, of this buffer.
225 : *
226 : * @param[in,out] aChainHead - the head of the buffer chain the current buffer belongs to. May be \c nullptr if the current
227 : * buffer is the head of the buffer chain.
228 : */
229 : void SetDataLength(size_t aNewLen, const PacketBufferHandle & aChainHead);
230 31588 : void SetDataLength(size_t aNewLen) { SetDataLength(aNewLen, nullptr); }
231 :
232 : /**
233 : * Get the total length of packet data in the buffer chain.
234 : *
235 : * @return total length, in octets.
236 : */
237 112174 : size_t TotalLength() const { return this->tot_len; }
238 :
239 : /**
240 : * Get the maximum amount, in bytes, of data that will fit in the buffer given the current start position and buffer size.
241 : *
242 : * @return number of bytes that fits in the buffer given the current start position.
243 : */
244 : size_t MaxDataLength() const;
245 :
246 : /**
247 : * Get the number of bytes of data that can be added to the current buffer given the current start position and data length.
248 : *
249 : * @return the length, in bytes, of data that will fit in the current buffer given the current start position and data length.
250 : */
251 : size_t AvailableDataLength() const;
252 :
253 : /**
254 : * Get the number of bytes within the current buffer between the start of the buffer and the current data start position.
255 : *
256 : * @return the amount, in bytes, of space between the start of the buffer and the current data start position.
257 : */
258 : uint16_t ReservedSize() const;
259 :
260 : /**
261 : * Determine whether there are any additional buffers chained to the current buffer.
262 : *
263 : * @return \c true if there is a chained buffer.
264 : */
265 90968 : bool HasChainedBuffer() const { return ChainedBuffer() != nullptr; }
266 :
267 : /**
268 : * Add the given packet buffer to the end of the buffer chain, adjusting the total length of each buffer in the chain
269 : * accordingly.
270 : *
271 : * @note The current packet buffer must be the head of the buffer chain for the lengths to be adjusted properly.
272 : *
273 : * @note Ownership is transferred from the argument to the `next` link at the end of the current chain.
274 : *
275 : * @param[in] aPacket - the packet buffer to be added to the end of the current chain.
276 : */
277 : void AddToEnd(PacketBufferHandle && aPacket);
278 :
279 : /**
280 : * Move data from subsequent buffers in the chain into the current buffer until it is full.
281 : *
282 : * Only the current buffer is compacted: the data within the current buffer is moved to the front of the buffer, eliminating
283 : * any reserved space. The remaining available space is filled with data moved from subsequent buffers in the chain, until the
284 : * current buffer is full. If a subsequent buffer in the chain is moved into the current buffer in its entirety, it is removed
285 : * from the chain and freed. The method takes no parameters, returns no results and cannot fail.
286 : */
287 : void CompactHead();
288 :
289 : /**
290 : * Adjust the current buffer to indicate the amount of data consumed.
291 : *
292 : * Advance the data start position in the current buffer by the specified amount, in bytes, up to the length of data in the
293 : * buffer. Decrease the length and total length by the amount consumed.
294 : *
295 : * @param[in] aConsumeLength - number of bytes to consume from the current buffer.
296 : */
297 : void ConsumeHead(size_t aConsumeLength);
298 :
299 : /**
300 : * Ensure the buffer has at least the specified amount of reserved space.
301 : *
302 : * Ensure the buffer has at least the specified amount of reserved space, moving the data in the buffer forward to make room if
303 : * necessary.
304 : *
305 : * @param[in] aReservedSize - number of bytes desired for the headers.
306 : *
307 : * @return \c true if the requested reserved size is available, \c false if there's not enough room in the buffer.
308 : */
309 : CHECK_RETURN_VALUE bool EnsureReservedSize(uint16_t aReservedSize);
310 :
311 : /**
312 : * Align the buffer payload on the specified bytes boundary.
313 : *
314 : * Moving the payload in the buffer forward if necessary.
315 : *
316 : * @param[in] aAlignBytes - specifies number of bytes alignment for the payload start pointer.
317 : *
318 : * @return \c true if alignment is successful, \c false if there's not enough room in the buffer.
319 : */
320 : bool AlignPayload(uint16_t aAlignBytes);
321 :
322 : /**
323 : * Return the next buffer in a buffer chain.
324 : *
325 : * If there is no next buffer, the handle will have \c IsNull() \c true.
326 : *
327 : * @return a handle to the next buffer in the buffer chain.
328 : */
329 : CHECK_RETURN_VALUE PacketBufferHandle Next();
330 :
331 : /**
332 : * Return the last buffer in a buffer chain.
333 : *
334 : * @return a handle to the last buffer in the buffer chain.
335 : */
336 : CHECK_RETURN_VALUE PacketBufferHandle Last();
337 :
338 : /**
339 : * Copies data from the payloads of a chain of packet buffers until a given amount of data has been copied.
340 : *
341 : * @param[in] buf Destination buffer; must be at least @a length bytes.
342 : * @param[in] length Destination buffer length.
343 : *
344 : * @retval #CHIP_ERROR_BUFFER_TOO_SMALL If the total length of the payloads in the chain is less than the requested @a length.
345 : * @retval #CHIP_ERROR_INTERNAL In case of an inconsistency in the buffer chain.
346 : * @retval #CHIP_NO_ERROR If the requested payload has been copied.
347 : */
348 : CHIP_ERROR Read(uint8_t * buf, size_t length) const;
349 : template <size_t N>
350 22 : inline CHIP_ERROR Read(uint8_t (&buf)[N]) const
351 : {
352 22 : return Read(buf, N);
353 : }
354 :
355 : /**
356 : * Perform an implementation-defined check on the validity of a PacketBuffer pointer.
357 : *
358 : * Unless enabled by #CHIP_CONFIG_MEMORY_DEBUG_CHECKS == 1, this function does nothing.
359 : *
360 : * When enabled, it performs an implementation- and configuration-defined check on
361 : * the validity of the packet buffer. It MAY log an error and/or abort the program
362 : * if the packet buffer or the implementation-defined memory management system is in
363 : * a faulty state. (Some configurations may not actually perform any check.)
364 : *
365 : * @note A null pointer is not considered faulty.
366 : *
367 : * @param[in] buffer - the packet buffer to check.
368 : */
369 97277 : static void Check(const PacketBuffer * buffer)
370 : {
371 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
372 : InternalCheck(buffer);
373 : #endif
374 97277 : }
375 :
376 : private:
377 : // Memory required for a maximum-size PacketBuffer.
378 : static constexpr uint16_t kBlockSize = PacketBuffer::kStructureSize + PacketBuffer::kMaxSizeWithoutReserve;
379 :
380 : // Note: this condition includes DOXYGEN to work around a Doxygen error. DOXYGEN is never defined in any actual build.
381 : #if CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL || defined(DOXYGEN)
382 : typedef union
383 : {
384 : pbuf Header;
385 : uint8_t Block[PacketBuffer::kBlockSize];
386 : } BufferPoolElement;
387 : static BufferPoolElement sBufferPool[CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE];
388 : static PacketBuffer * sFreeList;
389 : static PacketBuffer * BuildFreeList();
390 : #endif // CHIP_SYSTEM_PACKETBUFFER_FROM_CHIP_POOL || defined(DOXYGEN)
391 :
392 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
393 : static void InternalCheck(const PacketBuffer * buffer);
394 : #endif
395 :
396 : void AddRef();
397 : bool HasSoleOwnership() const { return (this->ref == 1); }
398 : static void Free(PacketBuffer * aPacket);
399 : static PacketBuffer * FreeHead(PacketBuffer * aPacket);
400 :
401 264158 : PacketBuffer * ChainedBuffer() const { return static_cast<PacketBuffer *>(this->next); }
402 : PacketBuffer * Consume(size_t aConsumeLength);
403 : void Clear();
404 : void SetDataLength(size_t aNewLen, PacketBuffer * aChainHead);
405 :
406 : /**
407 : * Get a pointer to the start of the reserved space (which comes before the
408 : * payload). The actual reserved space is the ReservedSize() bytes starting
409 : * at this pointer.
410 : */
411 : uint8_t * ReserveStart();
412 : const uint8_t * ReserveStart() const;
413 :
414 : friend class PacketBufferHandle;
415 : friend class TestSystemPacketBuffer;
416 : };
417 :
418 : static_assert(sizeof(pbuf) == sizeof(PacketBuffer), "PacketBuffer must not have additional members");
419 :
420 : /**
421 : * @class PacketBufferHandle
422 : *
423 : * @brief
424 : * Tracks ownership of a PacketBuffer.
425 : *
426 : * PacketBuffer objects are reference-counted, and normally held and used through a PacketBufferHandle that owns one of the
427 : * counted references. When a PacketBufferHandle goes out of scope, its reference is released. To take ownership, a function
428 : * takes a PacketBufferHandle by value. To borrow ownership, a function takes a `const PacketBufferHandle &`.
429 : */
430 : class DLL_EXPORT PacketBufferHandle
431 : {
432 : public:
433 : /**
434 : * Construct an empty PacketBufferHandle.
435 : */
436 163170 : PacketBufferHandle() : mBuffer(nullptr) {}
437 40880 : PacketBufferHandle(decltype(nullptr)) : mBuffer(nullptr) {}
438 :
439 : /**
440 : * Construct a PacketBufferHandle that takes ownership of a PacketBuffer from another.
441 : */
442 117115 : PacketBufferHandle(PacketBufferHandle && aOther)
443 117115 : {
444 117115 : mBuffer = aOther.mBuffer;
445 117115 : aOther.mBuffer = nullptr;
446 117115 : }
447 :
448 445653 : ~PacketBufferHandle() { *this = nullptr; }
449 :
450 : /**
451 : * Take ownership of a PacketBuffer from another PacketBufferHandle, freeing any existing owned buffer.
452 : */
453 157436 : PacketBufferHandle & operator=(PacketBufferHandle && aOther)
454 : {
455 157436 : if (mBuffer != nullptr)
456 : {
457 4472 : PacketBuffer::Free(mBuffer);
458 : }
459 157436 : mBuffer = aOther.mBuffer;
460 157436 : aOther.mBuffer = nullptr;
461 157436 : return *this;
462 : }
463 :
464 : /**
465 : * Free any buffer owned by this handle.
466 : */
467 491920 : PacketBufferHandle & operator=(decltype(nullptr))
468 : {
469 491920 : if (mBuffer != nullptr)
470 : {
471 102775 : PacketBuffer::Free(mBuffer);
472 : }
473 491920 : mBuffer = nullptr;
474 491920 : return *this;
475 : }
476 :
477 : /**
478 : * Get a new handle to an existing buffer.
479 : *
480 : * @return a PacketBufferHandle that shares ownership with this.
481 : */
482 57991 : PacketBufferHandle Retain() const
483 : {
484 57991 : mBuffer->AddRef();
485 57991 : return PacketBufferHandle(mBuffer);
486 : }
487 :
488 : /**
489 : * Access a PackerBuffer's public methods.
490 : */
491 1021975 : PacketBuffer * operator->() const { return mBuffer; }
492 :
493 : /**
494 : * Test whether this PacketBufferHandle is empty, or conversely owns a PacketBuffer.
495 : *
496 : * @return \c true if this PacketBufferHandle is empty; return \c false if it owns a PacketBuffer.
497 : */
498 190321 : bool IsNull() const { return mBuffer == nullptr; }
499 :
500 : /**
501 : * Test whether the PacketBuffer owned by this PacketBufferHandle has unique ownership.
502 : *
503 : * @return \c true if the PacketBuffer owned by this PacketBufferHandle is solely owned; return \c false if
504 : * it has more than one ownership.
505 : */
506 : bool HasSoleOwnership() const { return mBuffer->HasSoleOwnership(); }
507 :
508 : /**
509 : * Detach and return the head of a buffer chain while updating this handle to point to the remaining buffers.
510 : * The current buffer must be the head of the chain.
511 : *
512 : * This PacketBufferHandle now holds the ownership formerly held by the head of the chain.
513 : * The returned PacketBufferHandle holds the ownership formerly held by this.
514 : *
515 : * @return the detached buffer formerly at the head of the buffer chain.
516 : */
517 : CHECK_RETURN_VALUE PacketBufferHandle PopHead();
518 :
519 : /**
520 : * Free the first buffer in a chain.
521 : *
522 : * @note When the buffer chain is referenced by multiple handles, `FreeHead()` will detach the head, but will not forcibly
523 : * deallocate the head buffer.
524 : */
525 49 : void FreeHead()
526 : {
527 : // `PacketBuffer::FreeHead()` frees the current head; this takes ownership from the `next` link.
528 49 : mBuffer = PacketBuffer::FreeHead(mBuffer);
529 49 : }
530 :
531 : /**
532 : * Add the given packet buffer to the end of the buffer chain, adjusting the total length of each buffer in the chain
533 : * accordingly.
534 : *
535 : * @note The current packet buffer handle must either be the head of the buffer chain for the lengths to be adjusted properly,
536 : * or be null (in which case it becomes the head).
537 : *
538 : * @note Ownership is transferred from the argument to the `next` link at the end of the current chain,
539 : * or to the handle if it's currently null.
540 : *
541 : * @param[in] aPacket - the packet buffer to be added to the end of the current chain.
542 : */
543 4150 : void AddToEnd(PacketBufferHandle && aPacket)
544 : {
545 4150 : if (IsNull())
546 : {
547 1138 : mBuffer = aPacket.mBuffer;
548 1138 : aPacket.mBuffer = nullptr;
549 : }
550 : else
551 : {
552 3012 : mBuffer->AddToEnd(std::move(aPacket));
553 : }
554 4150 : }
555 :
556 : /**
557 : * Consume data in a chain of buffers.
558 : *
559 : * Consume data in a chain of buffers starting with the current buffer and proceeding through the remaining buffers in the
560 : * chain. Each buffer that is completely consumed is freed and the handle holds the first buffer (if any) containing the
561 : * remaining data. The current buffer must be the head of the buffer chain.
562 : *
563 : * @param[in] aConsumeLength - number of bytes to consume from the current chain.
564 : */
565 6508 : void Consume(size_t aConsumeLength) { mBuffer = mBuffer->Consume(aConsumeLength); }
566 :
567 : /**
568 : * Copy the given buffer to a right-sized buffer if applicable.
569 : *
570 : * Only operates on single buffers (for chains, use \c CompactHead() and RightSize the tail).
571 : * Requires that this handle be the only reference to the underlying buffer.
572 : */
573 8056 : void RightSize()
574 : {
575 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_RIGHTSIZE
576 8056 : InternalRightSize();
577 : #endif
578 8056 : }
579 :
580 : /**
581 : * Get a new handle to a raw PacketBuffer pointer.
582 : *
583 : * @brief The caller's ownership is transferred to this.
584 : *
585 : * @note This should only be used in low-level code, e.g. to import buffers from LwIP or a similar stack.
586 : */
587 9 : static PacketBufferHandle Adopt(PacketBuffer * buffer) { return PacketBufferHandle(buffer); }
588 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
589 : static PacketBufferHandle Adopt(pbuf * buffer) { return Adopt(reinterpret_cast<PacketBuffer *>(buffer)); }
590 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
591 :
592 : /**
593 : * Advance this PacketBufferHandle to the next buffer in a chain.
594 : *
595 : * @note This differs from `FreeHead()` in that it does not touch any content in the currently referenced packet buffer;
596 : * it only changes which buffer this handle owns. (Note that this could result in the previous buffer being freed,
597 : * if there is no other owner.) `Advance()` is designed to be used with an additional handle to traverse a buffer chain,
598 : * whereas `FreeHead()` modifies a chain.
599 : */
600 1400 : void Advance() { *this = Hold(mBuffer->ChainedBuffer()); }
601 :
602 : /**
603 : * Export a raw PacketBuffer pointer.
604 : *
605 : * @brief The PacketBufferHandle's ownership is transferred to the caller.
606 : *
607 : * @note This should only be used in low-level code. The caller owns one counted reference to the \c PacketBuffer
608 : * and is responsible for managing it safely.
609 : *
610 : * @note The ref-qualifier `&&` requires the caller to use `std::move` to emphasize that ownership is
611 : * moved out of this handle.
612 : */
613 11991 : CHECK_RETURN_VALUE PacketBuffer * UnsafeRelease() &&
614 : {
615 11991 : PacketBuffer::Check(mBuffer);
616 11991 : PacketBuffer * buffer = mBuffer;
617 11991 : mBuffer = nullptr;
618 11991 : return buffer;
619 : }
620 :
621 : /**
622 : * Allocates a packet buffer.
623 : *
624 : * A packet buffer is conceptually divided into two parts:
625 : * @li Space reserved for network protocol headers. The size of this space normally defaults to a value determined
626 : * by the network layer configuration, but can be given explicity by \c aReservedSize for special cases.
627 : * @li Space for application data. The minimum size of this space is given by \c aAvailableSize, and then \c Start()
628 : * provides a pointer to the start of this space.
629 : *
630 : * Fails and returns \c nullptr if no memory is available, or if the size requested is too large.
631 : * When the sum of \a aAvailableSize and \a aReservedSize is no greater than \c PacketBuffer::kMaxSizeWithoutReserve,
632 : * that is guaranteed not to be too large.
633 : *
634 : * On success, it is guaranteed that \c AvailableDataSize() is no less than \a aAvailableSize.
635 : *
636 : * @param[in] aAvailableSize Minimum number of octets to for application data (at `Start()`).
637 : * @param[in] aReservedSize Number of octets to reserve for protocol headers (before `Start()`).
638 : *
639 : * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
640 : */
641 : static PacketBufferHandle New(size_t aAvailableSize, uint16_t aReservedSize = PacketBuffer::kDefaultHeaderReserve);
642 :
643 : /**
644 : * Allocates a packet buffer with initial contents.
645 : *
646 : * @param[in] aData Initial buffer contents.
647 : * @param[in] aDataSize Size of initial buffer contents.
648 : * @param[in] aAdditionalSize Size of additional application data space after the initial contents.
649 : * @param[in] aReservedSize Number of octets to reserve for protocol headers.
650 : *
651 : * @return On success, a PacketBufferHandle to the allocated buffer. On fail, \c nullptr.
652 : */
653 : static PacketBufferHandle NewWithData(const void * aData, size_t aDataSize, size_t aAdditionalSize = 0,
654 : uint16_t aReservedSize = PacketBuffer::kDefaultHeaderReserve);
655 :
656 : /**
657 : * Creates a copy of a packet buffer (or chain).
658 : *
659 : * @returns empty handle on allocation failure. Otherwise, the returned buffer has the same sizes and contents as the original.
660 : */
661 : PacketBufferHandle CloneData() const;
662 :
663 : /**
664 : * Perform an implementation-defined check on the validity of a PacketBufferHandle.
665 : *
666 : * Unless enabled by #CHIP_CONFIG_MEMORY_DEBUG_CHECKS == 1, this function does nothing.
667 : *
668 : * When enabled, it performs an implementation- and configuration-defined check on
669 : * the validity of the packet buffer. It MAY log an error and/or abort the program
670 : * if the packet buffer or the implementation-defined memory management system is in
671 : * a faulty state. (Some configurations may not actually perform any check.)
672 : *
673 : * @note A null handle is not considered faulty.
674 : */
675 : void Check() const
676 : {
677 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_CHECK
678 : PacketBuffer::Check(mBuffer);
679 : #endif
680 : }
681 :
682 4525 : bool operator==(const PacketBufferHandle & aOther) const { return mBuffer == aOther.mBuffer; }
683 :
684 : protected:
685 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
686 : // For use via LwIPPacketBufferView only.
687 : static struct pbuf * GetLwIPpbuf(const PacketBufferHandle & handle)
688 : {
689 : PacketBuffer::Check(handle.mBuffer);
690 : return static_cast<struct pbuf *>(handle.mBuffer);
691 : }
692 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
693 :
694 : private:
695 : PacketBufferHandle(const PacketBufferHandle &) = delete;
696 : PacketBufferHandle & operator=(const PacketBufferHandle &) = delete;
697 :
698 : // The caller's ownership is transferred to this.
699 124488 : explicit PacketBufferHandle(PacketBuffer * buffer) : mBuffer(buffer) {}
700 :
701 2579 : static PacketBufferHandle Hold(PacketBuffer * buffer)
702 : {
703 2579 : if (buffer != nullptr)
704 : {
705 1775 : buffer->AddRef();
706 : }
707 2579 : return PacketBufferHandle(buffer);
708 : }
709 :
710 19825 : PacketBuffer * Get() const { return mBuffer; }
711 2106 : PacketBuffer * GetNext() const { return static_cast<PacketBuffer *>(mBuffer->next); }
712 :
713 : #if CHIP_SYSTEM_PACKETBUFFER_HAS_RIGHTSIZE
714 : void InternalRightSize();
715 : #endif
716 :
717 : PacketBuffer * mBuffer;
718 :
719 : friend class PacketBuffer;
720 : friend class TestSystemPacketBuffer;
721 : };
722 :
723 45533 : inline void PacketBuffer::SetDataLength(size_t aNewLen, const PacketBufferHandle & aChainHead)
724 : {
725 45533 : SetDataLength(aNewLen, aChainHead.mBuffer);
726 45533 : }
727 :
728 93 : inline PacketBufferHandle PacketBuffer::Next()
729 : {
730 93 : return PacketBufferHandle::Hold(ChainedBuffer());
731 : }
732 :
733 1080 : inline PacketBufferHandle PacketBuffer::Last()
734 : {
735 1080 : PacketBuffer * p = this;
736 1560 : while (p->HasChainedBuffer())
737 480 : p = p->ChainedBuffer();
738 1080 : return PacketBufferHandle::Hold(p);
739 : }
740 :
741 : } // namespace System
742 :
743 : namespace Encoding {
744 :
745 : class PacketBufferWriterUtil
746 : {
747 : private:
748 : template <typename>
749 : friend class PacketBufferWriterBase;
750 : static System::PacketBufferHandle Finalize(BufferWriter & aBufferWriter, System::PacketBufferHandle & aPacket);
751 : };
752 :
753 : /**
754 : * BufferWriter backed by packet buffer.
755 : *
756 : * Typical use:
757 : * @code
758 : * PacketBufferWriter buf(maximumLength);
759 : * if (buf.IsNull()) { return CHIP_ERROR_NO_MEMORY; }
760 : * buf.Put(...);
761 : * ...
762 : * PacketBufferHandle handle = buf.Finalize();
763 : * if (buf.IsNull()) { return CHIP_ERROR_BUFFER_TOO_SMALL; }
764 : * // valid data
765 : * @endcode
766 : */
767 : template <class Writer>
768 : class PacketBufferWriterBase : public Writer
769 : {
770 : public:
771 : /**
772 : * Constructs a BufferWriter that writes into a packet buffer, using all available space.
773 : *
774 : * @param[in] aPacket A handle to PacketBuffer, to be used as backing store for the BufferWriter.
775 : */
776 32 : PacketBufferWriterBase(System::PacketBufferHandle && aPacket) :
777 32 : Writer(aPacket->Start() + aPacket->DataLength(), aPacket->AvailableDataLength())
778 : {
779 32 : mPacket = std::move(aPacket);
780 32 : }
781 :
782 : /**
783 : * Constructs a BufferWriter that writes into a packet buffer, using no more than the requested space.
784 : *
785 : * @param[in] aPacket A handle to PacketBuffer, to be used as backing store for the BufferWriter.
786 : * @param[in] aSize Maximum number of octects to write into the packet buffer.
787 : */
788 57 : PacketBufferWriterBase(System::PacketBufferHandle && aPacket, size_t aSize) :
789 57 : Writer(aPacket->Start() + aPacket->DataLength(), std::min(aSize, static_cast<size_t>(aPacket->AvailableDataLength())))
790 : {
791 57 : mPacket = std::move(aPacket);
792 57 : }
793 :
794 : /**
795 : * Test whether this PacketBufferWriter is null, or conversely owns a PacketBuffer.
796 : *
797 : * @retval true The PacketBufferWriter is null; it does not own a PacketBuffer. This implies either that
798 : * construction failed, or that \c Finalize() has previously been called to release the buffer.
799 : * @retval false The PacketBufferWriter owns a PacketBuffer, which can be written using BufferWriter \c Put() methods,
800 : * and (assuming no overflow) obtained by calling \c Finalize().
801 : */
802 67 : bool IsNull() const { return mPacket.IsNull(); }
803 :
804 : /**
805 : * Obtain the backing packet buffer, if it is valid.
806 : *
807 : * If construction succeeded, \c Finalize() has not already been called, and \c BufferWriter::Fit() is true,
808 : * the caller takes ownership of a buffer containing the desired data. Otherwise, the returned handle tests null,
809 : * and any underlying storage has been released.
810 : *
811 : * @return A packet buffer handle.
812 : */
813 89 : System::PacketBufferHandle Finalize() { return PacketBufferWriterUtil::Finalize(*this, mPacket); }
814 :
815 : private:
816 : System::PacketBufferHandle mPacket;
817 : };
818 :
819 : using PacketBufferWriter = PacketBufferWriterBase<chip::Encoding::BufferWriter>;
820 :
821 : namespace LittleEndian {
822 : using PacketBufferWriter = PacketBufferWriterBase<chip::Encoding::LittleEndian::BufferWriter>;
823 : } // namespace LittleEndian
824 :
825 : namespace BigEndian {
826 : using PacketBufferWriter = PacketBufferWriterBase<chip::Encoding::BigEndian::BufferWriter>;
827 : } // namespace BigEndian
828 :
829 : } // namespace Encoding
830 :
831 : } // namespace chip
832 :
833 : #if CHIP_SYSTEM_CONFIG_USE_LWIP
834 :
835 : namespace chip {
836 :
837 : namespace Inet {
838 : class UDPEndPointImplLwIP;
839 : } // namespace Inet
840 :
841 : namespace System {
842 :
843 : /**
844 : * Provide low-level access to a raw `pbuf *`, limited to specific classes that interface with LwIP.
845 : */
846 : class LwIPPacketBufferView : public PacketBufferHandle
847 : {
848 : private:
849 : /**
850 : * Borrow a raw LwIP `pbuf *`.
851 : *
852 : * @brief The caller has access but no ownership.
853 : *
854 : * @note This should be used ONLY by low-level code interfacing with LwIP.
855 : */
856 : static struct pbuf * UnsafeGetLwIPpbuf(const PacketBufferHandle & handle) { return PacketBufferHandle::GetLwIPpbuf(handle); }
857 : friend class Inet::UDPEndPointImplLwIP;
858 : };
859 :
860 : } // namespace System
861 : } // namespace chip
862 :
863 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
|