/src/openweave-core/src/system/SystemPacketBuffer.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2016-2017 Nest Labs, Inc. |
4 | | * All rights reserved. |
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 member functions and private data for |
22 | | * the nl::Weave::System::PacketBuffer class, which provides the |
23 | | * mechanisms for manipulating packets of octet-serialized |
24 | | * data. |
25 | | */ |
26 | | |
27 | | // Include standard C library limit macros |
28 | | #ifndef __STDC_LIMIT_MACROS |
29 | | #define __STDC_LIMIT_MACROS |
30 | | #endif |
31 | | #include <stdint.h> |
32 | | |
33 | | // Include module header |
34 | | #include <SystemLayer/SystemPacketBuffer.h> |
35 | | |
36 | | // Include common private header |
37 | | #include "SystemLayerPrivate.h" |
38 | | |
39 | | // Include local headers |
40 | | #include <SystemLayer/SystemMutex.h> |
41 | | #include <SystemLayer/SystemFaultInjection.h> |
42 | | |
43 | | #include <string.h> |
44 | | #include <stdlib.h> |
45 | | #include <stddef.h> |
46 | | |
47 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
48 | | #include <lwip/pbuf.h> |
49 | | #include <lwip/mem.h> |
50 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
51 | | |
52 | | #include <Weave/Support/logging/WeaveLogging.h> |
53 | | #include <Weave/Support/crypto/WeaveCrypto.h> |
54 | | #include <Weave/Support/CodeUtils.h> |
55 | | |
56 | | #include <SystemLayer/SystemStats.h> |
57 | | |
58 | | namespace nl { |
59 | | namespace Weave { |
60 | | namespace System { |
61 | | |
62 | | // |
63 | | // Pool allocation for PacketBuffer objects (toll-free bridged with LwIP pbuf allocator if WEAVE_SYSTEM_CONFIG_USE_LWIP) |
64 | | // |
65 | | #if !WEAVE_SYSTEM_CONFIG_USE_LWIP |
66 | | #if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
67 | | |
68 | | static BufferPoolElement sBufferPool[WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC]; |
69 | | |
70 | | PacketBuffer* PacketBuffer::sFreeList = PacketBuffer::BuildFreeList(); |
71 | | |
72 | | #if !WEAVE_SYSTEM_CONFIG_NO_LOCKING |
73 | | static Mutex sBufferPoolMutex; |
74 | | |
75 | 56.2k | #define LOCK_BUF_POOL() do { sBufferPoolMutex.Lock(); } while (0) |
76 | 56.2k | #define UNLOCK_BUF_POOL() do { sBufferPoolMutex.Unlock(); } while (0) |
77 | | #endif // !WEAVE_SYSTEM_CONFIG_NO_LOCKING |
78 | | |
79 | | #endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
80 | | |
81 | | #ifndef LOCK_BUF_POOL |
82 | | #define LOCK_BUF_POOL() do { } while (0) |
83 | | #endif // !defined(LOCK_BUF_POOL) |
84 | | |
85 | | #ifndef UNLOCK_BUF_POOL |
86 | | #define UNLOCK_BUF_POOL() do { } while (0) |
87 | | #endif // !defined(UNLOCK_BUF_POOL) |
88 | | |
89 | | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
90 | | |
91 | | /** |
92 | | * Get pointer to start of data in buffer. |
93 | | * |
94 | | * @return pointer to the start of data. |
95 | | */ |
96 | | uint8_t* PacketBuffer::Start() const |
97 | 136k | { |
98 | 136k | return static_cast<uint8_t*>(this->payload); |
99 | 136k | } |
100 | | |
101 | | /** |
102 | | * Set the start data in buffer, adjusting length and total length accordingly. |
103 | | * |
104 | | * @note The data within the buffer is not moved, only accounting information is changed. The function is commonly used to either |
105 | | * strip or prepend protocol headers in a zero-copy way. |
106 | | * |
107 | | * @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 buffer. |
108 | | * |
109 | | * @param[in] aNewStart - A pointer to where the new payload should start. newStart will be adjusted internally to fall within |
110 | | * the boundaries of the first buffer in the PacketBuffer chain. |
111 | | */ |
112 | | void PacketBuffer::SetStart(uint8_t* aNewStart) |
113 | 0 | { |
114 | 0 | uint8_t* const kStart = reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE; |
115 | 0 | uint8_t* const kEnd = kStart + this->AllocSize(); |
116 | |
|
117 | 0 | if (aNewStart < kStart) |
118 | 0 | aNewStart = kStart; |
119 | 0 | else if (aNewStart > kEnd) |
120 | 0 | aNewStart = kEnd; |
121 | |
|
122 | 0 | ptrdiff_t lDelta = aNewStart - static_cast<uint8_t*>(this->payload); |
123 | 0 | if (lDelta > this->len) |
124 | 0 | lDelta = this->len; |
125 | |
|
126 | 0 | this->len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->len) - lDelta); |
127 | 0 | this->tot_len = static_cast<uint16_t>(static_cast<ptrdiff_t>(this->tot_len) - lDelta); |
128 | 0 | this->payload = aNewStart; |
129 | 0 | } |
130 | | |
131 | | /** |
132 | | * Get length, in bytes, of data in packet buffer. |
133 | | * |
134 | | * @return length, in bytes (current payload length). |
135 | | */ |
136 | | uint16_t PacketBuffer::DataLength() const |
137 | 49.3k | { |
138 | 49.3k | return this->len; |
139 | 49.3k | } |
140 | | |
141 | | /** |
142 | | * Set length, in bytes, of data in buffer, adjusting total length accordingly. |
143 | | * |
144 | | * The function sets the length, in bytes, of the data in the buffer, adjusting the total length appropriately. When the buffer |
145 | | * is not the head of the buffer chain (common case: the caller adds data to the last buffer in the PacketBuffer chain prior to |
146 | | * calling higher layers), the aChainHead __must__ be passed in to properly adjust the total lengths of each buffer ahead of the |
147 | | * current buffer. |
148 | | * |
149 | | * @param[in] aNewLen - new length, in bytes, of this buffer. |
150 | | * |
151 | | * @param[inout] aChainHead - the head of the buffer chain the current buffer belongs to. May be NULL if the current buffer is |
152 | | * the head of the buffer chain. |
153 | | */ |
154 | | void PacketBuffer::SetDataLength(uint16_t aNewLen, PacketBuffer* aChainHead) |
155 | 32.7k | { |
156 | 32.7k | const uint16_t kMaxDataLen = this->MaxDataLength(); |
157 | | |
158 | 32.7k | if (aNewLen > kMaxDataLen) |
159 | 64 | aNewLen = kMaxDataLen; |
160 | | |
161 | 32.7k | ptrdiff_t lDelta = static_cast<ptrdiff_t>(aNewLen) - static_cast<ptrdiff_t>(this->len); |
162 | | |
163 | 32.7k | this->len = aNewLen; |
164 | 32.7k | this->tot_len = (uint16_t) (this->tot_len + lDelta); |
165 | | |
166 | 32.7k | while (aChainHead != NULL && aChainHead != this) |
167 | 0 | { |
168 | 0 | aChainHead->tot_len = static_cast<uint16_t>(aChainHead->tot_len + lDelta); |
169 | 0 | aChainHead = static_cast<PacketBuffer*>(aChainHead->next); |
170 | 0 | } |
171 | 32.7k | } |
172 | | |
173 | | /** |
174 | | * Get total length of packet data in the buffer chain. |
175 | | * |
176 | | * @return total length, in octets. |
177 | | */ |
178 | | uint16_t PacketBuffer::TotalLength() const |
179 | 0 | { |
180 | 0 | return this->tot_len; |
181 | 0 | } |
182 | | |
183 | | /** |
184 | | * Get the maximum amount, in bytes, of data that will fit in the buffer given the current start position and buffer size. |
185 | | * |
186 | | * @return number of bytes that fits in the buffer given the current start position. |
187 | | */ |
188 | | uint16_t PacketBuffer::MaxDataLength() const |
189 | 82.3k | { |
190 | 82.3k | const uint8_t* const kStart = reinterpret_cast<const uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE; |
191 | 82.3k | const ptrdiff_t kDelta = static_cast<uint8_t*>(this->payload) - kStart; |
192 | 82.3k | return static_cast<uint16_t>(this->AllocSize() - kDelta); |
193 | 82.3k | } |
194 | | |
195 | | /** |
196 | | * Get the number of bytes of data that can be added to the current buffer given the current start position and data length. |
197 | | * |
198 | | * @return the length, in bytes, of data that will fit in the current buffer given the current start position and data length. |
199 | | */ |
200 | | uint16_t PacketBuffer::AvailableDataLength() const |
201 | 49.6k | { |
202 | 49.6k | return this->MaxDataLength() - this->len; |
203 | 49.6k | } |
204 | | |
205 | | /** |
206 | | * Get the number of bytes within the current buffer between the start of the buffer and the current data start position. |
207 | | * |
208 | | * @return the amount, in bytes, of space between the start of the buffer and the current data start position. |
209 | | */ |
210 | | uint16_t PacketBuffer::ReservedSize() const |
211 | 0 | { |
212 | 0 | const ptrdiff_t kDelta = static_cast<uint8_t*>(this->payload) - reinterpret_cast<const uint8_t*>(this); |
213 | 0 | return static_cast<uint16_t>(kDelta - WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE); |
214 | 0 | } |
215 | | |
216 | | /** |
217 | | * |
218 | | * Add the given packet buffer to the end of the buffer chain, adjusting the total length of each buffer in the chain accordingly. |
219 | | * |
220 | | * @note The current packet buffer must be the head of the buffer chain for the lengths to be adjusted properly. The caller MUST |
221 | | * NOT reference the given packet buffer afterwards. |
222 | | * |
223 | | * @param[in] aPacket - the packet buffer to be added to the end of the current chain. |
224 | | */ |
225 | | void PacketBuffer::AddToEnd(PacketBuffer* aPacket) |
226 | 0 | { |
227 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
228 | | pbuf_cat(this, aPacket); |
229 | | #else // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
230 | 0 | PacketBuffer* lCursor = this; |
231 | |
|
232 | 0 | while (true) |
233 | 0 | { |
234 | 0 | lCursor->tot_len += aPacket->tot_len; |
235 | 0 | if (lCursor->next == NULL) |
236 | 0 | { |
237 | 0 | lCursor->next = aPacket; |
238 | 0 | break; |
239 | 0 | } |
240 | | |
241 | 0 | lCursor = static_cast<PacketBuffer*>(lCursor->next); |
242 | 0 | } |
243 | 0 | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
244 | 0 | } |
245 | | |
246 | | /** |
247 | | * Detach the current buffer from its chain and return a pointer to the remaining buffers. The current buffer must be the head of |
248 | | * the chain. |
249 | | * |
250 | | * @return the tail of the current buffer chain or NULL if the current buffer is the only buffer in the chain. |
251 | | */ |
252 | | PacketBuffer* PacketBuffer::DetachTail() |
253 | 0 | { |
254 | 0 | PacketBuffer* lReturn = static_cast<PacketBuffer*>(this->next); |
255 | |
|
256 | 0 | this->next = NULL; |
257 | 0 | this->tot_len = this->len; |
258 | |
|
259 | 0 | return lReturn; |
260 | 0 | } |
261 | | |
262 | | /** |
263 | | * Move data from subsequent buffers in the chain into the current buffer until it is full. |
264 | | * |
265 | | * Only the current buffer is compacted: the data within the current buffer is moved to the front of the buffer, eliminating any |
266 | | * reserved space. The remaining available space is filled with data moved from subsequent buffers in the chain, until the |
267 | | * current buffer is full. If a subsequent buffer in the chain is moved into the current buffer in its entirety, it is removed |
268 | | * from the chain and freed. The method takes no parameters, returns no results and cannot fail. |
269 | | */ |
270 | | void PacketBuffer::CompactHead() |
271 | 0 | { |
272 | 0 | uint8_t* const kStart = reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE; |
273 | |
|
274 | 0 | if (this->payload != kStart) |
275 | 0 | { |
276 | 0 | memmove(kStart, this->payload, this->len); |
277 | 0 | this->payload = kStart; |
278 | 0 | } |
279 | |
|
280 | 0 | uint16_t lAvailLength = this->AvailableDataLength(); |
281 | |
|
282 | 0 | while (lAvailLength > 0 && this->next != NULL) |
283 | 0 | { |
284 | 0 | PacketBuffer& lNextPacket = *static_cast<PacketBuffer*>(this->next); |
285 | 0 | VerifyOrDieWithMsg(lNextPacket.ref == 1, WeaveSystemLayer, "next buffer %p is not exclusive to this chain", &lNextPacket); |
286 | | |
287 | 0 | uint16_t lMoveLength = lNextPacket.len; |
288 | 0 | if (lMoveLength > lAvailLength) |
289 | 0 | lMoveLength = lAvailLength; |
290 | |
|
291 | 0 | memcpy(static_cast<uint8_t*>(this->payload) + this->len, lNextPacket.payload, lMoveLength); |
292 | |
|
293 | 0 | lNextPacket.payload = (uint8_t *) lNextPacket.payload + lMoveLength; |
294 | 0 | this->len += lMoveLength; |
295 | 0 | lAvailLength -= lMoveLength; |
296 | 0 | lNextPacket.len -= lMoveLength; |
297 | 0 | lNextPacket.tot_len -= lMoveLength; |
298 | |
|
299 | 0 | if (lNextPacket.len == 0) |
300 | 0 | this->next = this->FreeHead(&lNextPacket); |
301 | 0 | } |
302 | 0 | } |
303 | | |
304 | | /** |
305 | | * Adjust the current buffer to indicate the amount of data consumed. |
306 | | * |
307 | | * Advance the data start position in the current buffer by the specified amount, in bytes, up to the length of data in the |
308 | | * buffer. Decrease the length and total length by the amount consumed. |
309 | | * |
310 | | * @param[in] aConsumeLen - number of bytes to consume from the current buffer. |
311 | | */ |
312 | | void PacketBuffer::ConsumeHead(uint16_t aConsumeLength) |
313 | 0 | { |
314 | 0 | if (aConsumeLength > this->len) |
315 | 0 | aConsumeLength = this->len; |
316 | 0 | this->payload = static_cast<uint8_t*>(this->payload) + aConsumeLength; |
317 | 0 | this->len -= aConsumeLength; |
318 | 0 | this->tot_len -= aConsumeLength; |
319 | 0 | } |
320 | | |
321 | | /** |
322 | | * Consume data in a chain of buffers. |
323 | | * |
324 | | * Consume data in a chain of buffers starting with the current buffer and proceeding through the remaining buffers in the chain. |
325 | | * Each buffer that is completely consumed is freed and the function returns the first buffer (if any) containing the remaining |
326 | | * data. The current buffer must be the head of the buffer chain. |
327 | | * |
328 | | * @param[in] aConsumeLength - number of bytes to consume from the current chain. |
329 | | * |
330 | | * @return the first buffer from the current chain that contains any remaining data. If no data remains, a NULL is returned. |
331 | | */ |
332 | | PacketBuffer* PacketBuffer::Consume(uint16_t aConsumeLength) |
333 | 0 | { |
334 | 0 | PacketBuffer* lPacket = this; |
335 | |
|
336 | 0 | while (lPacket != NULL && aConsumeLength > 0) |
337 | 0 | { |
338 | 0 | const uint16_t kLength = lPacket->DataLength(); |
339 | |
|
340 | 0 | if (aConsumeLength >= kLength) |
341 | 0 | { |
342 | 0 | lPacket = PacketBuffer::FreeHead(lPacket); |
343 | 0 | aConsumeLength -= kLength; |
344 | 0 | } |
345 | 0 | else |
346 | 0 | { |
347 | 0 | lPacket->ConsumeHead(aConsumeLength); |
348 | 0 | break; |
349 | 0 | } |
350 | 0 | } |
351 | |
|
352 | 0 | return lPacket; |
353 | 0 | } |
354 | | |
355 | | /** |
356 | | * Ensure the buffer has at least the specified amount of reserved space. |
357 | | * |
358 | | * Ensure the buffer has at least the specified amount of reserved space moving the data in the buffer forward to make room if |
359 | | * necessary. |
360 | | * |
361 | | * @param[in] aReservedSize - number of bytes desired for the headers. |
362 | | * |
363 | | * @return \c true if the requested reserved size is available, \c false if there's not enough room in the buffer. |
364 | | */ |
365 | | bool PacketBuffer::EnsureReservedSize(uint16_t aReservedSize) |
366 | 0 | { |
367 | 0 | const uint16_t kCurrentReservedSize = this->ReservedSize(); |
368 | 0 | if (aReservedSize <= kCurrentReservedSize) |
369 | 0 | return true; |
370 | | |
371 | 0 | if ((aReservedSize + this->len) > this->AllocSize()) |
372 | 0 | return false; |
373 | | |
374 | 0 | const uint16_t kMoveLength = aReservedSize - kCurrentReservedSize; |
375 | 0 | memmove(static_cast<uint8_t*>(this->payload) + kMoveLength, this->payload, this->len); |
376 | 0 | payload = static_cast<uint8_t*>(this->payload) + kMoveLength; |
377 | |
|
378 | 0 | return true; |
379 | 0 | } |
380 | | |
381 | | /** |
382 | | * Align the buffer payload on the specified bytes boundary. |
383 | | * |
384 | | * Moving the payload in the buffer forward if necessary. |
385 | | * |
386 | | * @param[in] aAlignBytes - specifies number of bytes alignment for the payload start pointer. |
387 | | * |
388 | | * @return \c true if alignment is successful, \c false if there's not enough room in the buffer. |
389 | | */ |
390 | | bool PacketBuffer::AlignPayload(uint16_t aAlignBytes) |
391 | 0 | { |
392 | 0 | if (aAlignBytes == 0) |
393 | 0 | return false; |
394 | | |
395 | 0 | const uint16_t kPayloadOffset = reinterpret_cast<uintptr_t>(this->payload) % aAlignBytes; |
396 | |
|
397 | 0 | if (kPayloadOffset == 0) |
398 | 0 | return true; |
399 | | |
400 | 0 | const uint16_t kPayloadShift = aAlignBytes - kPayloadOffset; |
401 | |
|
402 | 0 | return (this->EnsureReservedSize(this->ReservedSize() + kPayloadShift)); |
403 | 0 | } |
404 | | |
405 | | /** |
406 | | * Get pointer to next buffer in chain. |
407 | | * |
408 | | * @return a pointer to the next buffer in the chain. \c NULL is returned when there is no buffers in the chain. |
409 | | */ |
410 | | PacketBuffer* PacketBuffer::Next() const |
411 | 0 | { |
412 | 0 | return static_cast<PacketBuffer*>(this->next); |
413 | 0 | } |
414 | | |
415 | | /** |
416 | | * Increment the reference count of the current buffer. |
417 | | */ |
418 | | void PacketBuffer::AddRef() |
419 | 0 | { |
420 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
421 | | pbuf_ref(this); |
422 | | #else // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
423 | 0 | LOCK_BUF_POOL(); |
424 | 0 | ++this->ref; |
425 | 0 | UNLOCK_BUF_POOL(); |
426 | 0 | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
427 | 0 | } |
428 | | |
429 | | /** |
430 | | * Allocates a PacketBuffer object with at least \c aReservedSize bytes reserved in the payload for headers, and at least |
431 | | * \c aAllocSize bytes of space for additional data after the initial cursor pointer. |
432 | | * |
433 | | * @param[in] aReservedSize Number of octets to reserve behind the cursor. |
434 | | * @param[in] aAvailableSize Number of octets to allocate after the cursor. |
435 | | * |
436 | | * @return On success, a pointer to the PacketBuffer in the allocated block. On fail, \c NULL. |
437 | | */ |
438 | | PacketBuffer* PacketBuffer::NewWithAvailableSize(uint16_t aReservedSize, size_t aAvailableSize) |
439 | 24.1k | { |
440 | 24.1k | const size_t lReservedSize = static_cast<size_t>(aReservedSize); |
441 | 24.1k | const size_t lAllocSize = lReservedSize + aAvailableSize; |
442 | 24.1k | PacketBuffer* lPacket; |
443 | | |
444 | 24.1k | WEAVE_SYSTEM_FAULT_INJECT(FaultInjection::kFault_PacketBufferNew, return NULL); |
445 | | |
446 | 24.1k | if (lAllocSize > WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX) |
447 | 0 | { |
448 | 0 | WeaveLogError(WeaveSystemLayer, "PacketBuffer: allocation too large."); |
449 | 0 | return NULL; |
450 | 0 | } |
451 | | |
452 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
453 | | |
454 | | lPacket = static_cast<PacketBuffer*>(pbuf_alloc(PBUF_RAW, lAllocSize, PBUF_POOL)); |
455 | | |
456 | | SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS(); |
457 | | |
458 | | #else // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
459 | 24.1k | #if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
460 | | |
461 | 24.1k | LOCK_BUF_POOL(); |
462 | | |
463 | 24.1k | lPacket = sFreeList; |
464 | 24.1k | if (lPacket != NULL) |
465 | 24.1k | { |
466 | 24.1k | sFreeList = static_cast<PacketBuffer*>(lPacket->next); |
467 | 24.1k | SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs); |
468 | 24.1k | } |
469 | | |
470 | 24.1k | UNLOCK_BUF_POOL(); |
471 | | |
472 | | #else // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
473 | | |
474 | | const size_t lBlockSize = WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE + lAllocSize; |
475 | | |
476 | | lPacket = reinterpret_cast<PacketBuffer*>(malloc(lBlockSize)); |
477 | | SYSTEM_STATS_INCREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs); |
478 | | |
479 | | #endif // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
480 | 24.1k | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
481 | | |
482 | 24.1k | if (lPacket == NULL) |
483 | 0 | { |
484 | 0 | WeaveLogError(WeaveSystemLayer, "PacketBuffer: pool EMPTY."); |
485 | 0 | return NULL; |
486 | 0 | } |
487 | | |
488 | 24.1k | lPacket->payload = reinterpret_cast<uint8_t*>(lPacket) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE + lReservedSize; |
489 | 24.1k | lPacket->len = lPacket->tot_len = 0; |
490 | 24.1k | lPacket->next = NULL; |
491 | 24.1k | lPacket->ref = 1; |
492 | | #if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0 |
493 | | lPacket->alloc_size = lAllocSize; |
494 | | #endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0 |
495 | | |
496 | 24.1k | return lPacket; |
497 | 24.1k | } |
498 | | |
499 | | /** |
500 | | * Allocates a PacketBuffer with default reserved size (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) in the payload for headers, |
501 | | * and at least \c aAllocSize bytes of space for additional data after the initial cursor pointer. |
502 | | * |
503 | | * This usage is most appropriate when allocating a PacketBuffer for an application-layer message. |
504 | | * |
505 | | * @param[in] aAvailableSize Number of octets to allocate after the cursor. |
506 | | * |
507 | | * @return On success, a pointer to the PacketBuffer in the allocated block. On fail, \c NULL. * |
508 | | */ |
509 | | PacketBuffer* PacketBuffer::NewWithAvailableSize(size_t aAvailableSize) |
510 | 0 | { |
511 | 0 | return PacketBuffer::NewWithAvailableSize(WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE, aAvailableSize); |
512 | 0 | } |
513 | | |
514 | | /** |
515 | | * Allocates a single PacketBuffer of maximum total size with a specific header reserve size. |
516 | | * |
517 | | * The parameter passed in is the size reserved prior to the payload to accomodate packet headers from different stack layers, |
518 | | * __not__ the overall size of the buffer to allocate. The size of the buffer #WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX |
519 | | * and not, specified in the call. |
520 | | * |
521 | | * - `PacketBuffer::New(0)` : when called in this fashion, the buffer will be returned without any header reserved, consequently |
522 | | * the entire payload is usable by the caller. This pattern is particularly useful at the lower layers of networking stacks, |
523 | | * in cases where the user knows the payload will be copied out into the final message with appropriate header reserves or in |
524 | | * creating PacketBuffer that are appended to a chain of PacketBuffer via `PacketBuffer::AddToEnd()`. |
525 | | * |
526 | | * @param[in] aReservedSize amount of header space to reserve. |
527 | | * |
528 | | * @return On success, a pointer to the PacketBuffer, on failure \c NULL. |
529 | | */ |
530 | | PacketBuffer* PacketBuffer::New(uint16_t aReservedSize) |
531 | 24.1k | { |
532 | 24.1k | const size_t lReservedSize = static_cast<size_t>(aReservedSize); |
533 | | |
534 | 24.1k | const size_t lAvailableSize = |
535 | 24.1k | lReservedSize < WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX ? WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX - lReservedSize : 0; |
536 | | |
537 | 24.1k | return PacketBuffer::NewWithAvailableSize(aReservedSize, lAvailableSize); |
538 | 24.1k | } |
539 | | |
540 | | /** |
541 | | * Allocates a single PacketBuffer of default max size (#WEAVE_SYSTEM_CONFIG_PACKETBUFFER_CAPACITY_MAX) with default reserved size |
542 | | * (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) in the payload. |
543 | | * |
544 | | * The reserved size (#WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE) is large enough to hold transport layer headers as well as headers required by |
545 | | * \c WeaveMessageLayer and \c WeaveExchangeLayer. |
546 | | */ |
547 | | PacketBuffer* PacketBuffer::New(void) |
548 | 24.1k | { |
549 | 24.1k | return PacketBuffer::New(WEAVE_SYSTEM_CONFIG_HEADER_RESERVE_SIZE); |
550 | 24.1k | } |
551 | | |
552 | | /** |
553 | | * Free all packet buffers in a chain. |
554 | | * |
555 | | * Decrement the reference count to all the buffers in the current chain. If the reference count reaches 0, the respective buffers |
556 | | * are freed or returned to allocation pools as appropriate. As a rule, users should treat this method as an equivalent of |
557 | | * `free()` function and not use the argument after the call. |
558 | | * |
559 | | * @param[in] aPacket - packet buffer to be freed. |
560 | | */ |
561 | | void PacketBuffer::Free(PacketBuffer* aPacket) |
562 | 32.1k | { |
563 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
564 | | |
565 | | if (aPacket != NULL) |
566 | | { |
567 | | pbuf_free(aPacket); |
568 | | |
569 | | SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS(); |
570 | | } |
571 | | |
572 | | #else // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
573 | | |
574 | 32.1k | LOCK_BUF_POOL(); |
575 | | |
576 | 56.2k | while (aPacket != NULL) |
577 | 24.1k | { |
578 | 24.1k | PacketBuffer* lNextPacket = static_cast<PacketBuffer*>(aPacket->next); |
579 | | |
580 | 24.1k | VerifyOrDieWithMsg(aPacket->ref > 0, WeaveSystemLayer, "SystemPacketBuffer::Free: aPacket->ref = 0"); |
581 | | |
582 | 24.1k | aPacket->ref--; |
583 | 24.1k | if (aPacket->ref == 0) |
584 | 24.1k | { |
585 | 24.1k | SYSTEM_STATS_DECREMENT(nl::Weave::System::Stats::kSystemLayer_NumPacketBufs); |
586 | 24.1k | aPacket->Clear(); |
587 | 24.1k | #if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
588 | 24.1k | aPacket->next = sFreeList; |
589 | 24.1k | sFreeList = aPacket; |
590 | | #else // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
591 | | free(aPacket); |
592 | | #endif // !WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
593 | 24.1k | aPacket = lNextPacket; |
594 | 24.1k | } |
595 | 0 | else |
596 | 0 | { |
597 | 0 | aPacket = NULL; |
598 | 0 | } |
599 | 24.1k | } |
600 | | |
601 | 32.1k | UNLOCK_BUF_POOL(); |
602 | | |
603 | 32.1k | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
604 | 32.1k | } |
605 | | |
606 | | /** |
607 | | * Clear content of the packet buffer. |
608 | | * |
609 | | * This method is called by Free(), before the buffer is released to the free buffer pool. |
610 | | */ |
611 | | void PacketBuffer::Clear(void) |
612 | 24.1k | { |
613 | 24.1k | nl::Weave::Crypto::ClearSecretData(reinterpret_cast<uint8_t*>(this) + WEAVE_SYSTEM_PACKETBUFFER_HEADER_SIZE, this->AllocSize()); |
614 | 24.1k | tot_len = 0; |
615 | 24.1k | len = 0; |
616 | | #if WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0 |
617 | | alloc_size = 0; |
618 | | #endif // WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC == 0 |
619 | 24.1k | } |
620 | | |
621 | | /** |
622 | | * Free the first buffer in a chain, returning a pointer to the remaining buffers. |
623 | | `* |
624 | | * @note When the buffer chain is referenced by multiple callers, `FreeHead()` will detach the head, but will not forcibly |
625 | | * deallocate the head buffer. |
626 | | * |
627 | | * @param[in] aPacket - buffer chain. |
628 | | * |
629 | | * @return packet buffer chain consisting of the tail of the input buffer (may be \c NULL). |
630 | | */ |
631 | | PacketBuffer* PacketBuffer::FreeHead(PacketBuffer* aPacket) |
632 | 0 | { |
633 | 0 | PacketBuffer* lNextPacket = static_cast<PacketBuffer*>(aPacket->next); |
634 | 0 | aPacket->next = NULL; |
635 | 0 | PacketBuffer::Free(aPacket); |
636 | 0 | return lNextPacket; |
637 | 0 | } |
638 | | |
639 | | /** |
640 | | * Copy the given buffer to a right-sized buffer if applicable. |
641 | | * This function is a no-op for sockets. |
642 | | * |
643 | | * @param[in] aPacket - buffer or buffer chain. |
644 | | * |
645 | | * @return new packet buffer or the original buffer |
646 | | */ |
647 | | PacketBuffer* PacketBuffer::RightSize(PacketBuffer *aPacket) |
648 | 0 | { |
649 | 0 | PacketBuffer *lNewPacket = aPacket; |
650 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP && LWIP_PBUF_FROM_CUSTOM_POOLS |
651 | | lNewPacket = static_cast<PacketBuffer *>(pbuf_rightsize((struct pbuf *)aPacket, -1)); |
652 | | if (lNewPacket != aPacket) |
653 | | { |
654 | | SYSTEM_STATS_UPDATE_LWIP_PBUF_COUNTS(); |
655 | | |
656 | | WeaveLogProgress(WeaveSystemLayer, "PacketBuffer: RightSize Copied"); |
657 | | } |
658 | | #endif |
659 | 0 | return lNewPacket; |
660 | 0 | } |
661 | | |
662 | | #if !WEAVE_SYSTEM_CONFIG_USE_LWIP && WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
663 | | |
664 | | PacketBuffer* PacketBuffer::BuildFreeList() |
665 | 12 | { |
666 | 12 | PacketBuffer* lHead = NULL; |
667 | | |
668 | 3.61k | for (int i = 0; i < WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC; i++) |
669 | 3.60k | { |
670 | 3.60k | PacketBuffer* lCursor = &sBufferPool[i].Header; |
671 | 3.60k | lCursor->next = lHead; |
672 | 3.60k | lCursor->ref = 0; |
673 | 3.60k | lHead = lCursor; |
674 | 3.60k | } |
675 | | |
676 | 12 | Mutex::Init(sBufferPoolMutex); |
677 | | |
678 | 12 | return lHead; |
679 | 12 | } |
680 | | |
681 | | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP && WEAVE_SYSTEM_CONFIG_PACKETBUFFER_MAXALLOC |
682 | | |
683 | | } // namespace System |
684 | | } // namespace Weave |
685 | | } // namespace nl |