1 /* coap_mem.c -- CoAP memory handling
2 *
3 * Copyright (C) 2014--2015,2019--2023 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
11 /**
12 * @file coap_mem.c
13 * @brief Memory handling functions
14 */
15
16 #include "coap3/coap_internal.h"
17
18 #if defined(RIOT_VERSION) && defined(MODULE_MEMARRAY)
19 #include <memarray.h>
20
21 #undef PACKAGE_NAME
22 #undef PACKAGE_STRING
23 #undef PACKAGE_TARNAME
24 #undef PACKAGE_VERSION
25 #include <coap3/coap_session.h>
26 #undef PACKAGE_NAME
27 #undef PACKAGE_STRING
28 #undef PACKAGE_TARNAME
29 #undef PACKAGE_VERSION
30
31 #include "coap3/coap_session.h"
32 #include "coap3/coap_net.h"
33 #include "coap3/coap_pdu.h"
34 #include "coap3/coap_resource.h"
35
36 /**
37 * The maximum size of a string on platforms that allocate fixed-size
38 * memory blocks.
39 */
40 #ifndef COAP_MAX_STRING_SIZE
41 #define COAP_MAX_STRING_SIZE (64U)
42 #endif /* COAP_MAX_STRING_SIZE */
43
44 /**
45 * The maximum number of strings on platforms that allocate
46 * fixed-size memory blocks.
47 */
48 #ifndef COAP_MAX_STRINGS
49 #define COAP_MAX_STRINGS (16U)
50 #endif /* COAP_MAX_STRINGS */
51
52 /**
53 * The maximum number of endpoints on platforms that allocate
54 * fixed-size memory blocks.
55 */
56 #ifndef COAP_MAX_ENDPOINTS
57 #define COAP_MAX_ENDPOINTS (4U)
58 #endif /* COAP_MAX_ENDPOINTS */
59
60 /**
61 * The maximum number of resources on platforms that allocate
62 * fixed-size memory blocks.
63 */
64 #ifndef COAP_MAX_RESOURCES
65 #define COAP_MAX_RESOURCES (8U)
66 #endif /* COAP_MAX_RESOURCES */
67
68 /**
69 * The maximum number of attributes on platforms that allocate
70 * fixed-size memory blocks. Default is #COAP_MAX_RESOURCES * 4.
71 */
72 #ifndef COAP_MAX_ATTRIBUTES
73 #define COAP_MAX_ATTRIBUTES \
74 ((COAP_MAX_RESOURCES) * 4U)
75 #endif /* COAP_MAX_ATTRIBUTE_STRINGS */
76
77 /**
78 * The maximum number of a strings that are used for attribute names
79 * and values on platforms that allocate fixed-size memory blocks.
80 * Default is #COAP_MAX_ATTRIBUTES, i.e. every attribute can have a
81 * dynamic value.
82 */
83 #ifndef COAP_MAX_ATTRIBUTE_STRINGS
84 #define COAP_MAX_ATTRIBUTE_STRINGS (COAP_MAX_ATTRIBUTES)
85 #endif /* COAP_MAX_ATTRIBUTE_STRINGS */
86
87 /**
88 * The maximum size of attribute names or values and values on
89 * platforms that allocate fixed-size memory blocks.
90 */
91 #ifndef COAP_MAX_ATTRIBUTE_SIZE
92 #define COAP_MAX_ATTRIBUTE_SIZE (16U)
93 #endif /* COAP_MAX_ATTRIBUTE_SIZE */
94
95 /**
96 * The maximum number of processed packets on platforms that allocate
97 * fixed-size memory blocks.
98 */
99 #ifndef COAP_MAX_PACKETS
100 #define COAP_MAX_PACKETS (4U)
101 #endif /* COAP_MAX_PACKETS */
102
103 /**
104 * The maximum number of nodes in retransmission queue on platforms
105 * that allocate fixed-size memory blocks. The default value is
106 * #COAP_MAX_ENDPOINTS * #COAP_MAX_PACKETS.
107 */
108 #ifndef COAP_MAX_NODES
109 #define COAP_MAX_NODES \
110 ((COAP_MAX_ENDPOINTS) * (COAP_MAX_PACKETS))
111 #endif /* COAP_MAX_NODES */
112
113 /**
114 * The maximum number of CoAP contexts on platforms that allocate
115 * fixed-size memory blocks. Default is 1.
116 */
117 #ifndef COAP_MAX_CONTEXTS
118 #define COAP_MAX_CONTEXTS (1U)
119 #endif /* COAP_MAX_CONTEXTS */
120
121 /**
122 * The maximum number of CoAP PDUs processed in parallel on platforms
123 * that allocate fixed-size memory blocks. Default is
124 * #COAP_MAX_ENDPOINTS * 4.
125 */
126 #ifndef COAP_MAX_PDUS
127 #define COAP_MAX_PDUS ((COAP_MAX_ENDPOINTS) * 4U)
128 #endif /* COAP_MAX_PDUS */
129
130 /**
131 * The maximum number of DTLS sessions on platforms that allocate
132 * fixed-size memory blocks.
133 */
134 #ifndef COAP_MAX_DTLS_SESSIONS
135 #define COAP_MAX_DTLS_SESSIONS (2U)
136 #endif /* COAP_MAX_CONTEXTS */
137
138 /**
139 * The maximum number of DTLS sessions on platforms that allocate
140 * fixed-size memory blocks. Default is #COAP_MAX_ENDPOINTS.
141 */
142 #ifndef COAP_MAX_SESSIONS
143 #define COAP_MAX_SESSIONS (COAP_MAX_ENDPOINTS)
144 #endif /* COAP_MAX_CONTEXTS */
145
146 /**
147 * The maximum number of optlist entries on platforms that allocate
148 * fixed-size memory blocks.
149 */
150 #ifndef COAP_MAX_OPTIONS
151 #define COAP_MAX_OPTIONS (16U)
152 #endif /* COAP_MAX_CONTEXTS */
153
154 /**
155 * The maximum size of option values on platforms that allocate
156 * fixed-size memory blocks.
157 */
158 #ifndef COAP_MAX_OPTION_SIZE
159 #define COAP_MAX_OPTION_SIZE (16U)
160 #endif /* COAP_MAX_OPTION_SIZE */
161
162 /**
163 * The maximum number of cache-key entries that allocate
164 * fixed-size memory blocks.
165 */
166 #ifndef COAP_MAX_CACHE_KEYS
167 #define COAP_MAX_CACHE_KEYS (2U)
168 #endif /* COAP_MAX_CACHE_KEYS */
169
170 /**
171 * The maximum number of cache-entry entries that allocate
172 * fixed-size memory blocks.
173 */
174 #ifndef COAP_MAX_CACHE_ENTRIES
175 #define COAP_MAX_CACHE_ENTRIES (2U)
176 #endif /* COAP_MAX_CACHE_ENTRIES */
177
178 /**
179 * The maximum number lg_crcv entries that allocate
180 * fixed-size memory blocks.
181 */
182 #ifndef COAP_MAX_LG_CRCVS
183 #if COAP_CLIENT_SUPPORT
184 #define COAP_MAX_LG_CRCVS (1U)
185 #else /* ! COAP_CLIENT_SUPPORT */
186 #define COAP_MAX_LG_CRCVS (0U)
187 #endif /* ! COAP_CLIENT_SUPPORT */
188 #endif /* COAP_MAX_LG_CRCVS */
189
190 /**
191 * The maximum number lg_srcv entries that allocate
192 * fixed-size memory blocks.
193 */
194 #ifndef COAP_MAX_LG_SRCVS
195 #if COAP_SERVER_SUPPORT
196 #define COAP_MAX_LG_SRCVS (2U)
197 #else /* ! COAP_SERVER_SUPPORT */
198 #define COAP_MAX_LG_SRCVS (0U)
199 #endif /* ! COAP_SERVER_SUPPORT */
200 #endif /* COAP_MAX_LG_SRCVS */
201
202 /**
203 * The maximum number lg_xmit entries that allocate
204 * fixed-size memory blocks.
205 */
206 #ifndef COAP_MAX_LG_XMITS
207 #if COAP_SERVER_SUPPORT
208 #define COAP_MAX_LG_XMITS (2U)
209 #else /* ! COAP_SERVER_SUPPORT */
210 #define COAP_MAX_LG_XMITS (1U)
211 #endif /* ! COAP_SERVER_SUPPORT */
212 #endif /* COAP_MAX_LG_XMITS */
213
214 /* The memstr is the storage for holding coap_string_t structure
215 * together with its contents. */
216 union memstr_t {
217 coap_string_t s;
218 char buf[sizeof(coap_string_t) + COAP_MAX_STRING_SIZE];
219 };
220
221 /* The attrstr is the storage for holding coap_string_t structures to
222 * serve as attribute names or values. As these are typically short,
223 * they are stored in a different arena than generic strings. */
224 union attrstr_t {
225 coap_string_t s;
226 char buf[sizeof(coap_string_t) + COAP_MAX_ATTRIBUTE_SIZE];
227 };
228
229 static union memstr_t string_storage_data[COAP_MAX_STRINGS];
230 static memarray_t string_storage;
231
232 #if COAP_SERVER_SUPPORT
233 static coap_endpoint_t endpoint_storage_data[COAP_MAX_ENDPOINTS];
234 static memarray_t endpoint_storage;
235
236 static union attrstr_t attr_storage_data[COAP_MAX_ATTRIBUTE_STRINGS];
237 static memarray_t attr_storage;
238
239 static coap_attr_t resattr_storage_data[COAP_MAX_ATTRIBUTES];
240 static memarray_t resattr_storage;
241 #endif /* COAP_SERVER_SUPPORT */
242
243 static coap_packet_t pkt_storage_data[COAP_MAX_PACKETS];
244 static memarray_t pkt_storage;
245
246 static coap_queue_t node_storage_data[COAP_MAX_NODES];
247 static memarray_t node_storage;
248
249 static coap_context_t context_storage_data[COAP_MAX_CONTEXTS];
250 static memarray_t context_storage;
251
252 static coap_pdu_t pdu_storage_data[COAP_MAX_PDUS];
253 static memarray_t pdu_storage;
254
255 /* The pdubuf is the storage for holding the (assembled) PDU data in a
256 * coap_pdu_t structure. */
257 union pdubuf_t {
258 void *p; /* try to convince the compiler to word-align this structure */
259 char buf[COAP_DEFAULT_MAX_PDU_RX_SIZE];
260 };
261
262 static union pdubuf_t pdubuf_storage_data[COAP_MAX_PDUS];
263 static memarray_t pdubuf_storage;
264
265 #if COAP_SERVER_SUPPORT
266 static coap_resource_t resource_storage_data[COAP_MAX_RESOURCES];
267 static memarray_t resource_storage;
268 #endif /* COAP_SERVER_SUPPORT */
269
270 #ifdef COAP_WITH_LIBTINYDTLS
271 #undef PACKAGE_BUGREPORT
272 #include <session.h>
273 static session_t dtls_storage_data[COAP_MAX_DTLS_SESSIONS];
274 static memarray_t dtls_storage;
275 #endif /* COAP_WITH_LIBTINYDTLS */
276
277 static coap_session_t session_storage_data[COAP_MAX_SESSIONS];
278 static memarray_t session_storage;
279
280 /* The optbuf_t is the storage for holding optlist nodes. */
281 struct optbuf_t {
282 coap_optlist_t optlist;
283 char optbuf[COAP_MAX_OPTION_SIZE];
284 };
285 static struct optbuf_t option_storage_data[COAP_MAX_OPTIONS];
286 static memarray_t option_storage;
287
288 #if COAP_SERVER_SUPPORT
289 static coap_cache_key_t cache_key_storage_data[COAP_MAX_CACHE_KEYS];
290 static memarray_t cache_key_storage;
291
292 static coap_cache_entry_t cache_entry_storage_data[COAP_MAX_CACHE_ENTRIES];
293 static memarray_t cache_entry_storage;
294 #endif /* COAP_SERVER_SUPPORT */
295
296 #if COAP_CLIENT_SUPPORT
297 static coap_lg_crcv_t cache_lg_crcv_storage_data[COAP_MAX_LG_CRCVS];
298 static memarray_t cache_lg_crcv_storage;
299 #endif /* COAP_CLIENT_SUPPORT */
300
301 #if COAP_SERVER_SUPPORT
302 static coap_lg_srcv_t cache_lg_srcv_storage_data[COAP_MAX_LG_SRCVS];
303 static memarray_t cache_lg_srcv_storage;
304
305 static coap_lg_xmit_t cache_lg_xmit_storage_data[COAP_MAX_LG_XMITS];
306 static memarray_t cache_lg_xmit_storage;
307 #endif /* COAP_SERVER_SUPPORT */
308
309 #define INIT_STORAGE(Storage, Count) \
310 memarray_init(&(Storage ## _storage), (Storage ## _storage_data), sizeof(Storage ## _storage_data[0]), (Count));
311
312 #define STORAGE_PTR(Storage) (&(Storage ## _storage))
313
314 void
coap_memory_init(void)315 coap_memory_init(void) {
316 INIT_STORAGE(string, COAP_MAX_STRINGS);
317 #if COAP_SERVER_SUPPORT
318 INIT_STORAGE(endpoint, COAP_MAX_ENDPOINTS);
319 INIT_STORAGE(attr, COAP_MAX_ATTRIBUTE_STRINGS);
320 #endif /* COAP_SERVER_SUPPORT */
321 INIT_STORAGE(pkt, COAP_MAX_PACKETS);
322 INIT_STORAGE(node, COAP_MAX_NODES);
323 INIT_STORAGE(context, COAP_MAX_CONTEXTS);
324 INIT_STORAGE(pdu, COAP_MAX_PDUS);
325 INIT_STORAGE(pdubuf, COAP_MAX_PDUS);
326 #if COAP_SERVER_SUPPORT
327 INIT_STORAGE(resource, COAP_MAX_RESOURCES);
328 INIT_STORAGE(resattr, COAP_MAX_ATTRIBUTES);
329 #endif /* COAP_SERVER_SUPPORT */
330 #ifdef COAP_WITH_LIBTINYDTLS
331 INIT_STORAGE(dtls, COAP_MAX_DTLS_SESSIONS);
332 #endif
333 INIT_STORAGE(session, COAP_MAX_SESSIONS);
334 INIT_STORAGE(option, COAP_MAX_OPTIONS);
335 #if COAP_SERVER_SUPPORT
336 INIT_STORAGE(cache_key, COAP_MAX_CACHE_KEYS);
337 INIT_STORAGE(cache_entry, COAP_MAX_CACHE_ENTRIES);
338 #endif /* COAP_SERVER_SUPPORT */
339 #if COAP_CLIENT_SUPPORT
340 INIT_STORAGE(cache_lg_crcv, COAP_MAX_LG_CRCVS);
341 #endif /* COAP_SERVER_SUPPORT */
342 #if COAP_SERVER_SUPPORT
343 INIT_STORAGE(cache_lg_srcv, COAP_MAX_LG_SRCVS);
344 INIT_STORAGE(cache_lg_xmit, COAP_MAX_LG_XMITS);
345 #endif /* COAP_SERVER_SUPPORT */
346 }
347
348 static memarray_t *
get_container(coap_memory_tag_t type)349 get_container(coap_memory_tag_t type) {
350 switch (type) {
351 #if COAP_SERVER_SUPPORT
352 case COAP_ATTRIBUTE_NAME:
353 /* fall through */
354 case COAP_ATTRIBUTE_VALUE:
355 return &attr_storage;
356 #endif /* COAP_SERVER_SUPPORT */
357 case COAP_PACKET:
358 return &pkt_storage;
359 case COAP_NODE:
360 return &node_storage;
361 case COAP_CONTEXT:
362 return STORAGE_PTR(context);
363 #if COAP_SERVER_SUPPORT
364 case COAP_ENDPOINT:
365 return &endpoint_storage;
366 #endif /* COAP_SERVER_SUPPORT */
367 case COAP_PDU:
368 return &pdu_storage;
369 case COAP_PDU_BUF:
370 return &pdubuf_storage;
371 #if COAP_SERVER_SUPPORT
372 case COAP_RESOURCE:
373 return &resource_storage;
374 case COAP_RESOURCEATTR:
375 return &resattr_storage;
376 #endif /* COAP_SERVER_SUPPORT */
377 #ifdef COAP_WITH_LIBTINYDTLS
378 case COAP_DTLS_SESSION:
379 return &dtls_storage;
380 #endif
381 case COAP_SESSION:
382 return &session_storage;
383 case COAP_OPTLIST:
384 return &option_storage;
385 #if COAP_SERVER_SUPPORT
386 case COAP_CACHE_KEY:
387 return &cache_key_storage;
388 case COAP_CACHE_ENTRY:
389 return &cache_entry_storage;
390 #endif /* COAP_SERVER_SUPPORT */
391 #if COAP_CLIENT_SUPPORT
392 case COAP_LG_CRCV:
393 return &cache_lg_crcv_storage;
394 #endif /* COAP_CLIENT_SUPPORT */
395 #if COAP_SERVER_SUPPORT
396 case COAP_LG_SRCV:
397 return &cache_lg_srcv_storage;
398 case COAP_LG_XMIT:
399 return &cache_lg_xmit_storage;
400 #endif /* COAP_SERVER_SUPPORT */
401 case COAP_STRING:
402 /* fall through */
403 default:
404 return &string_storage;
405 }
406 }
407
408 void *
coap_malloc_type(coap_memory_tag_t type,size_t size)409 coap_malloc_type(coap_memory_tag_t type, size_t size) {
410 memarray_t *container = get_container(type);
411 void *ptr;
412 assert(container);
413
414 if (size > container->size) {
415 coap_log_warn("coap_malloc_type: Requested memory exceeds maximum object "
416 "size (type %d, size %zu, max %d)\n",
417 type, size, container->size);
418 return NULL;
419 }
420
421 ptr = memarray_alloc(container);
422 if (!ptr)
423 coap_log_warn("coap_malloc_type: Failure (no free blocks) for type %d\n",
424 type);
425 return ptr;
426 }
427
428 void
coap_free_type(coap_memory_tag_t type,void * object)429 coap_free_type(coap_memory_tag_t type, void *object) {
430 if (object != NULL)
431 memarray_free(get_container(type), object);
432 }
433
434 void *
coap_realloc_type(coap_memory_tag_t type,void * p,size_t size)435 coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) {
436 memarray_t *container = get_container(type);
437
438 assert(container);
439 /* The fixed container is all we have to work with */
440 if (p) {
441 if (size > container->size) {
442 coap_log_warn("coap_realloc_type: Requested memory exceeds maximum object "
443 "size (type %d, size %zu, max %d)\n",
444 type, size, container->size);
445 return NULL;
446 }
447 if (size == 0) {
448 coap_free_type(type, p);
449 return NULL;
450 }
451 return p;
452 }
453 return coap_malloc_type(type, size);
454 }
455 #else /* ! RIOT_VERSION */
456
457 #if defined(HAVE_MALLOC) || defined(__MINGW32__)
458 #include <stdlib.h>
459
460 void
coap_memory_init(void)461 coap_memory_init(void) {
462 }
463
464 void *
coap_malloc_type(coap_memory_tag_t type,size_t size)465 coap_malloc_type(coap_memory_tag_t type, size_t size) {
466 (void)type;
467 return malloc(size);
468 }
469
470 void *
coap_realloc_type(coap_memory_tag_t type,void * p,size_t size)471 coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) {
472 (void)type;
473 return realloc(p, size);
474 }
475
476 void
coap_free_type(coap_memory_tag_t type,void * p)477 coap_free_type(coap_memory_tag_t type, void *p) {
478 (void)type;
479 free(p);
480 }
481
482 #else /* ! HAVE_MALLOC && !__MINGW32__ */
483
484 #ifdef WITH_CONTIKI
485 #include "lib/heapmem.h"
486
487 void
coap_memory_init(void)488 coap_memory_init(void) {
489 }
490
491 void *
coap_malloc_type(coap_memory_tag_t type,size_t size)492 coap_malloc_type(coap_memory_tag_t type, size_t size) {
493 return heapmem_alloc(size);
494 }
495
496 void *
coap_realloc_type(coap_memory_tag_t type,void * p,size_t size)497 coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) {
498 return heapmem_realloc(p, size);
499 }
500
501 void
coap_free_type(coap_memory_tag_t type,void * ptr)502 coap_free_type(coap_memory_tag_t type, void *ptr) {
503 heapmem_free(ptr);
504 }
505 #endif /* WITH_CONTIKI */
506
507 #endif /* ! HAVE_MALLOC */
508
509 #endif /* ! RIOT_VERSION */
510