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