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