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