libcoap 4.3.2rc2

coap_subscribe.c
Go to the documentation of this file.
1/* coap_subscribe.c -- subscription handling for CoAP
2 * see RFC7641
3 *
4 * Copyright (C) 2010-2019,2022-2023 Olaf Bergmann <bergmann@tzi.org>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * This file is part of the CoAP library libcoap. Please see
9 * README for terms of use.
10 */
11
17#include "coap3/coap_internal.h"
18
19#ifndef min
20#define min(a,b) ((a) < (b) ? (a) : (b))
21#endif
22
23#if COAP_SERVER_SUPPORT
24 void
25 coap_subscription_init(coap_subscription_t *s) {
26 assert(s);
27 memset(s, 0, sizeof(coap_subscription_t));
28}
29
30 void
31 coap_persist_track_funcs(coap_context_t *context,
32 coap_observe_added_t observe_added,
33 coap_observe_deleted_t observe_deleted,
34 coap_track_observe_value_t track_observe_value,
35 coap_dyn_resource_added_t dyn_resource_added,
36 coap_resource_deleted_t resource_deleted,
37 uint32_t save_freq,
38 void *user_data) {
39 context->observe_added = observe_added;
40 context->observe_deleted = observe_deleted;
41 context->observe_user_data = user_data;
42 context->observe_save_freq = save_freq ? save_freq : 1;
43 context->track_observe_value = track_observe_value;
44 context->dyn_resource_added = dyn_resource_added;
45 context->resource_deleted = resource_deleted;
46}
47
48 coap_subscription_t *
49 coap_persist_observe_add(coap_context_t *context,
50 coap_proto_t e_proto,
51 const coap_address_t *e_listen_addr,
52 const coap_addr_tuple_t *s_addr_info,
53 const coap_bin_const_t *raw_packet,
54 const coap_bin_const_t *oscore_info) {
55 coap_session_t *session = NULL;
56 const uint8_t *data;
57 size_t data_len;
58 coap_pdu_t *pdu = NULL;
59#if COAP_CONSTRAINED_STACK
60 /* e_packet protected by mutex m_persist_add */
61 static coap_packet_t e_packet;
62#else /* ! COAP_CONSTRAINED_STACK */
63 coap_packet_t e_packet;
64#endif /* ! COAP_CONSTRAINED_STACK */
65 coap_packet_t *packet = &e_packet;
66 coap_tick_t now;
67 coap_string_t *uri_path = NULL;
68 coap_opt_iterator_t opt_iter;
69 coap_opt_t *observe;
70 int observe_action;
71 coap_resource_t *r;
72 coap_subscription_t *s;
73 coap_endpoint_t *ep;
74
75 if (e_listen_addr == NULL || s_addr_info == NULL || packet == NULL)
76 return NULL;
77
78 /* Will be creating a local 'open' session */
79 if (e_proto != COAP_PROTO_UDP)
80 return NULL;
81
82 ep = context->endpoint;
83 while (ep) {
84 if (ep->proto == e_proto &&
85 memcmp(e_listen_addr, &ep->bind_addr, sizeof(ep->bind_addr)) == 0)
86 break;
87 ep = ep->next;
88 }
89 if (!ep)
90 return NULL;
91
92#if COAP_CONSTRAINED_STACK
93 coap_mutex_lock(&m_persist_add);
94#endif /* COAP_CONSTRAINED_STACK */
95
96 /* Build up packet */
97 memcpy(&packet->addr_info, s_addr_info, sizeof(packet->addr_info));
98 packet->ifindex = 0;
99 memcpy(&packet->payload, &raw_packet->s, sizeof(packet->payload));
100 packet->length = raw_packet->length;
101
102 data = raw_packet->s;
103 data_len = raw_packet->length;
104 if (data_len < 4)
105 goto malformed;
106
107 /* Get the session */
108
109 coap_ticks(&now);
110 session = coap_endpoint_get_session(ep, packet, now);
111 if (session == NULL)
112 goto fail;
113 /* Need max space incase PDU is updated with updated token, huge size etc. */
114 pdu = coap_pdu_init(0, 0, 0, 0);
115 if (!pdu)
116 goto fail;
117
118 if (!coap_pdu_parse(session->proto, data, data_len, pdu)) {
119 goto malformed;
120 }
121 pdu->max_size = pdu->used_size;
122
123 if (pdu->code != COAP_REQUEST_CODE_GET &&
124 pdu->code != COAP_REQUEST_CODE_FETCH)
125 goto malformed;
126
127 observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
128 if (observe == NULL)
129 goto malformed;
130 observe_action = coap_decode_var_bytes(coap_opt_value(observe),
131 coap_opt_length(observe));
132 if (observe_action != COAP_OBSERVE_ESTABLISH)
133 goto malformed;
134
135 /* Get the resource */
136
137 uri_path = coap_get_uri_path(pdu);
138 if (!uri_path)
139 goto malformed;
140
141 r = coap_get_resource_from_uri_path(session->context,
142 (coap_str_const_t *)uri_path);
143 if (r == NULL) {
144 coap_log_warn("coap_persist_observe_add: resource '%s' not defined\n",
145 uri_path->s);
146 goto fail;
147 }
148 if (!r->observable) {
149 coap_log_warn("coap_persist_observe_add: resource '%s' not observable\n",
150 uri_path->s);
151 goto fail;
152 }
153 coap_delete_string(uri_path);
154 uri_path = NULL;
155
156 /* Create / update subscription for observing */
157 /* Now set up the subscription */
158 s = coap_add_observer(r, session, &pdu->actual_token, pdu);
159 if (s == NULL)
160 goto fail;
161
162#if COAP_OSCORE_SUPPORT
163 if (oscore_info) {
164 coap_log_debug("persist: OSCORE association being updated\n");
165 /*
166 * Need to track the association used for tracking this observe, done as
167 * a CBOR array. Written in coap_add_observer().
168 *
169 * If an entry is null, then use nil, else a set of bytes
170 *
171 * Currently tracking 5 items
172 * recipient_id
173 * id_context
174 * aad (from oscore_association_t)
175 * partial_iv (from oscore_association_t)
176 * nonce (from oscore_association_t)
177 */
178 oscore_ctx_t *osc_ctx;
179 const uint8_t *info_buf = oscore_info->s;
180 size_t info_buf_len = oscore_info->length;
181 size_t ret = 0;
182 coap_bin_const_t oscore_key_id;
183 coap_bin_const_t partial_iv;
184 coap_bin_const_t aad;
185 coap_bin_const_t id_context;
186 coap_bin_const_t nonce;
187 int have_aad = 0;
188 int have_partial_iv = 0;
189 int have_id_context = 0;
190 int have_nonce = 0;
191
192 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
193 if (ret != CBOR_ARRAY)
194 goto oscore_fail;
195 if (oscore_cbor_get_element_size(&info_buf, &info_buf_len) != 5)
196 goto oscore_fail;
197
198 /* recipient_id */
199 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
200 if (ret != CBOR_BYTE_STRING)
201 goto oscore_fail;
202 oscore_key_id.length = oscore_cbor_get_element_size(&info_buf,
203 &info_buf_len);
204 oscore_key_id.s = info_buf;
205 info_buf += oscore_key_id.length;
206
207 /* id_context */
208 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
209 if (ret == CBOR_BYTE_STRING) {
210 id_context.length = oscore_cbor_get_element_size(&info_buf,
211 &info_buf_len);
212 id_context.s = info_buf;
213 info_buf += id_context.length;
214 have_id_context = 1;
215 } else if (ret == CBOR_SIMPLE_VALUE &&
216 oscore_cbor_get_element_size(&info_buf,
217 &info_buf_len) == CBOR_NULL) {
218 } else
219 goto oscore_fail;
220
221 /* aad */
222 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
223 if (ret == CBOR_BYTE_STRING) {
224 aad.length = oscore_cbor_get_element_size(&info_buf, &info_buf_len);
225 aad.s = info_buf;
226 info_buf += aad.length;
227 have_aad = 1;
228 } else if (ret == CBOR_SIMPLE_VALUE &&
229 oscore_cbor_get_element_size(&info_buf,
230 &info_buf_len) == CBOR_NULL) {
231 } else
232 goto oscore_fail;
233
234 /* partial_iv */
235 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
236 if (ret == CBOR_BYTE_STRING) {
237 partial_iv.length = oscore_cbor_get_element_size(&info_buf,
238 &info_buf_len);
239 partial_iv.s = info_buf;
240 info_buf += partial_iv.length;
241 have_partial_iv = 1;
242 } else if (ret == CBOR_SIMPLE_VALUE &&
243 oscore_cbor_get_element_size(&info_buf,
244 &info_buf_len) == CBOR_NULL) {
245 } else
246 goto oscore_fail;
247
248 /* nonce */
249 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
250 if (ret == CBOR_BYTE_STRING) {
251 nonce.length = oscore_cbor_get_element_size(&info_buf,
252 &info_buf_len);
253 nonce.s = info_buf;
254 info_buf += nonce.length;
255 have_nonce = 1;
256 } else if (ret == CBOR_SIMPLE_VALUE &&
257 oscore_cbor_get_element_size(&info_buf,
258 &info_buf_len) == CBOR_NULL) {
259 } else
260 goto oscore_fail;
261
262 osc_ctx = oscore_find_context(session->context, oscore_key_id,
263 have_id_context ? &id_context : NULL, NULL,
264 &session->recipient_ctx);
265 if (osc_ctx) {
266 session->oscore_encryption = 1;
267 oscore_new_association(session, pdu, &pdu->actual_token,
268 session->recipient_ctx,
269 have_aad ? &aad : NULL,
270 have_nonce ? &nonce : NULL,
271 have_partial_iv ? &partial_iv : NULL,
272 1);
273 coap_log_debug("persist: OSCORE association added\n");
274 oscore_log_hex_value(COAP_LOG_OSCORE, "partial_iv",
275 have_partial_iv ? &partial_iv : NULL);
276 }
277 }
278oscore_fail:
279#else /* ! COAP_OSCORE_SUPPORT */
280 (void)oscore_info;
281#endif /* ! COAP_OSCORE_SUPPORT */
282 coap_delete_pdu(pdu);
283#if COAP_CONSTRAINED_STACK
284 coap_mutex_unlock(&m_persist_add);
285#endif /* COAP_CONSTRAINED_STACK */
286 return s;
287
288malformed:
289 coap_log_warn("coap_persist_observe_add: discard malformed PDU\n");
290fail:
291#if COAP_CONSTRAINED_STACK
292 coap_mutex_unlock(&m_persist_add);
293#endif /* COAP_CONSTRAINED_STACK */
294 coap_delete_string(uri_path);
295 coap_delete_pdu(pdu);
296 return NULL;
297}
298
299#if COAP_WITH_OBSERVE_PERSIST
300#include <stdio.h>
301
302/*
303 * read in active observe entry.
304 */
305 static int
306coap_op_observe_read(FILE *fp, coap_subscription_t **observe_key,
307 coap_proto_t *e_proto, coap_address_t *e_listen_addr,
308 coap_addr_tuple_t *s_addr_info,
309 coap_bin_const_t **raw_packet, coap_bin_const_t **oscore_info) {
310 ssize_t size;
311 coap_binary_t *scratch = NULL;
312
313 *raw_packet = NULL;
314 *oscore_info = NULL;
315
316 if (fread(observe_key, sizeof(*observe_key), 1, fp) == 1) {
317 /* New record 'key proto listen addr_info len raw_packet len oscore' */
318 if (fread(e_proto, sizeof(*e_proto), 1, fp) != 1)
319 goto fail;
320 if (fread(e_listen_addr, sizeof(*e_listen_addr), 1, fp) != 1)
321 goto fail;
322 if (fread(s_addr_info, sizeof(*s_addr_info), 1, fp) != 1)
323 goto fail;
324 if (fread(&size, sizeof(size), 1, fp) != 1)
325 goto fail;
326 if (size < 0 || size > 0x10000)
327 goto fail;
328 scratch = coap_new_binary(size);
329 if ((scratch) == NULL)
330 goto fail;
331 if (fread(scratch->s, scratch->length, 1, fp) != 1)
332 goto fail;
333 *raw_packet = (coap_bin_const_t *)scratch;
334 if (fread(&size, sizeof(size), 1, fp) != 1)
335 goto fail;
336 if (size == -1)
337 return 1;
338 else if (size < 0 || size > 0x10000)
339 goto fail;
340 else {
341 scratch = coap_new_binary(size);
342 if (scratch == NULL)
343 goto fail;
344 if (fread(scratch->s, scratch->length, 1, fp) != 1)
345 goto fail;
346 *oscore_info = (coap_bin_const_t *)scratch;
347 }
348 return 1;
349 }
350fail:
351 coap_delete_binary(scratch);
352 *raw_packet = NULL;
353 return 0;
354}
355
356/*
357 * write out active observe entry.
358 */
359 static int
360coap_op_observe_write(FILE *fp, coap_subscription_t *observe_key,
361 coap_proto_t e_proto, coap_address_t e_listen_addr,
362 coap_addr_tuple_t s_addr_info,
363 coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info) {
364 if (fwrite(&observe_key, sizeof(observe_key), 1, fp) != 1)
365 goto fail;
366 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
367 goto fail;
368 if (fwrite(&e_listen_addr, sizeof(e_listen_addr),
369 1, fp) != 1)
370 goto fail;
371 if (fwrite(&s_addr_info, sizeof(s_addr_info), 1, fp) != 1)
372 goto fail;
373 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
374 goto fail;
375 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
376 goto fail;
377 if (oscore_info) {
378 if (fwrite(&oscore_info->length, sizeof(oscore_info->length), 1, fp) != 1)
379 goto fail;
380 if (fwrite(oscore_info->s, oscore_info->length, 1, fp) != 1)
381 goto fail;
382 } else {
383 ssize_t not_defined = -1;
384
385 if (fwrite(&not_defined, sizeof(not_defined), 1, fp) != 1)
386 goto fail;
387 }
388 return 1;
389fail:
390 return 0;
391}
392
393/*
394 * This should be called before coap_persist_track_funcs() to prevent
395 * coap_op_observe_added() getting unnecessarily called.
396 * It should be called after init_resources() and coap_op_resource_load_disk()
397 * so that all the resources are in place.
398 */
399 static void
400coap_op_observe_load_disk(coap_context_t *ctx) {
401 FILE *fp_orig = fopen((const char *)ctx->observe_save_file->s, "r");
402 FILE *fp_new = NULL;
403 coap_subscription_t *observe_key = NULL;
404 coap_proto_t e_proto;
405 coap_address_t e_listen_addr;
406 coap_addr_tuple_t s_addr_info;
407 coap_bin_const_t *raw_packet = NULL;
408 coap_bin_const_t *oscore_info = NULL;
409 char *new = NULL;
410
411 if (fp_orig == NULL)
412 goto fail;
413 new = coap_malloc_type(COAP_STRING, ctx->observe_save_file->length + 5);
414 if (!new)
415 goto fail;
416
417 strcpy(new, (const char *)ctx->observe_save_file->s);
418 strcat(new, ".tmp");
419 fp_new = fopen(new, "w+");
420 if (fp_new == NULL)
421 goto fail;
422
423 /* Go through and load oscore entry, updating key on the way */
424 while (1) {
425 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
426 &s_addr_info, &raw_packet, &oscore_info))
427 break;
428 coap_log_debug("persist: New session/observe being created\n");
429 observe_key = coap_persist_observe_add(ctx, e_proto,
430 &e_listen_addr,
431 &s_addr_info,
432 raw_packet,
433 oscore_info);
434 if (observe_key) {
435 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
436 s_addr_info, raw_packet, oscore_info))
437 goto fail;
438 coap_delete_bin_const(raw_packet);
439 raw_packet = NULL;
440 coap_delete_bin_const(oscore_info);
441 oscore_info = NULL;
442 }
443 }
444 coap_delete_bin_const(raw_packet);
445 raw_packet = NULL;
446 coap_delete_bin_const(oscore_info);
447 oscore_info = NULL;
448
449 if (fflush(fp_new) == EOF)
450 goto fail;
451 fclose(fp_new);
452 fclose(fp_orig);
453 /* Either old or new is in place */
454 (void)rename(new, (const char *)ctx->observe_save_file->s);
455 coap_free_type(COAP_STRING, new);
456 return;
457
458fail:
459 coap_delete_bin_const(raw_packet);
460 coap_delete_bin_const(oscore_info);
461 if (fp_new)
462 fclose(fp_new);
463 if (fp_orig)
464 fclose(fp_orig);
465 if (new) {
466 (void)remove(new);
467 }
468 coap_free_type(COAP_STRING, new);
469 return;
470}
471
472/*
473 * client has registered a new observe subscription request.
474 */
475 static int
476coap_op_observe_added(coap_session_t *session,
477 coap_subscription_t *a_observe_key,
478 coap_proto_t a_e_proto, coap_address_t *a_e_listen_addr,
479 coap_addr_tuple_t *a_s_addr_info,
480 coap_bin_const_t *a_raw_packet,
481 coap_bin_const_t *a_oscore_info, void *user_data) {
482 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
483 "r");
484 FILE *fp_new = NULL;
485 coap_subscription_t *observe_key = NULL;
486 coap_proto_t e_proto;
487 coap_address_t e_listen_addr;
488 coap_addr_tuple_t s_addr_info;
489 coap_bin_const_t *raw_packet = NULL;
490 coap_bin_const_t *oscore_info = NULL;
491 char *new = NULL;
492
493 (void)user_data;
494
495 new = coap_malloc_type(COAP_STRING,
496 session->context->observe_save_file->length + 5);
497 if (!new)
498 goto fail;
499
500 strcpy(new, (const char *)session->context->observe_save_file->s);
501 strcat(new, ".tmp");
502 fp_new = fopen(new, "w+");
503 if (fp_new == NULL)
504 goto fail;
505
506 /* Go through and delete observe entry if it exists */
507 while (fp_orig) {
508 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
509 &s_addr_info, &raw_packet, &oscore_info))
510 break;
511 if (observe_key != a_observe_key) {
512 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
513 s_addr_info, raw_packet, oscore_info))
514 goto fail;
515 }
516 coap_delete_bin_const(raw_packet);
517 raw_packet = NULL;
518 coap_delete_bin_const(oscore_info);
519 oscore_info = NULL;
520 }
521 coap_delete_bin_const(raw_packet);
522 raw_packet = NULL;
523 coap_delete_bin_const(oscore_info);
524 oscore_info = NULL;
525
526 /* Add in new entry to the end */
527 if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
528 *a_s_addr_info, a_raw_packet, a_oscore_info))
529 goto fail;
530
531 if (fflush(fp_new) == EOF)
532 goto fail;
533 fclose(fp_new);
534 if (fp_orig)
535 fclose(fp_orig);
536 /* Either old or new is in place */
537 (void)rename(new, (const char *)session->context->observe_save_file->s);
538 coap_free_type(COAP_STRING, new);
539 return 1;
540
541fail:
542 coap_delete_bin_const(raw_packet);
543 coap_delete_bin_const(oscore_info);
544 if (fp_new)
545 fclose(fp_new);
546 if (fp_orig)
547 fclose(fp_orig);
548 if (new) {
549 (void)remove(new);
550 }
551 coap_free_type(COAP_STRING, new);
552 return 0;
553}
554
555/*
556 * client has de-registered a observe subscription request.
557 */
558 static int
559coap_op_observe_deleted(coap_session_t *session,
560 coap_subscription_t *d_observe_key,
561 void *user_data) {
562 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
563 "r");
564 FILE *fp_new = NULL;
565 coap_subscription_t *observe_key = NULL;
566 coap_proto_t e_proto;
567 coap_address_t e_listen_addr;
568 coap_addr_tuple_t s_addr_info;
569 coap_bin_const_t *raw_packet = NULL;
570 coap_bin_const_t *oscore_info = NULL;
571 char *new = NULL;
572
573 (void)user_data;
574
575 if (fp_orig == NULL)
576 goto fail;
577 new = coap_malloc_type(COAP_STRING,
578 session->context->observe_save_file->length + 5);
579 if (!new)
580 goto fail;
581
582 strcpy(new, (const char *)session->context->observe_save_file->s);
583 strcat(new, ".tmp");
584 fp_new = fopen(new, "w+");
585 if (fp_new == NULL)
586 goto fail;
587
588 /* Go through and locate observe entry to delete and not copy it across */
589 while (1) {
590 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
591 &s_addr_info, &raw_packet, &oscore_info))
592 break;
593 if (observe_key != d_observe_key) {
594 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
595 s_addr_info, (coap_bin_const_t *)raw_packet,
596 (coap_bin_const_t *)oscore_info))
597 goto fail;
598 }
599 coap_delete_bin_const(raw_packet);
600 raw_packet = NULL;
601 coap_delete_bin_const(oscore_info);
602 oscore_info = NULL;
603 }
604 coap_delete_bin_const(raw_packet);
605 raw_packet = NULL;
606 coap_delete_bin_const(oscore_info);
607 oscore_info = NULL;
608
609 if (fflush(fp_new) == EOF)
610 goto fail;
611 fclose(fp_new);
612 fclose(fp_orig);
613 /* Either old or new is in place */
614 (void)rename(new, (const char *)session->context->observe_save_file->s);
615 coap_free_type(COAP_STRING, new);
616 return 1;
617
618fail:
619 coap_delete_bin_const(raw_packet);
620 coap_delete_bin_const(oscore_info);
621 if (fp_new)
622 fclose(fp_new);
623 if (fp_orig)
624 fclose(fp_orig);
625 if (new) {
626 (void)remove(new);
627 }
628 coap_free_type(COAP_STRING, new);
629 return 0;
630}
631
632/*
633 * This should be called before coap_persist_track_funcs() to prevent
634 * coap_op_obs_cnt_track_observe() getting unnecessarily called.
635 * Should be called after coap_op_dyn_resource_load_disk() to make sure that
636 * all the resources are in the right place.
637 */
638 static void
639coap_op_obs_cnt_load_disk(coap_context_t *context) {
640 FILE *fp = fopen((const char *)context->obs_cnt_save_file->s, "r");
641 char buf[1500];
642
643 if (fp == NULL)
644 return;
645
646 while (fgets(buf, sizeof(buf), fp) != NULL) {
647 char *cp = strchr(buf, ' ');
648 coap_str_const_t resource_key;
649 uint32_t observe_num;
650 coap_resource_t *r;
651
652 if (!cp)
653 break;
654
655 *cp = '\000';
656 cp++;
657 observe_num = atoi(cp);
658 /*
659 * Need to assume 0 .. (context->observe_save_freq-1) have in addition
660 * been sent so need to round up to latest possible send value
661 */
662 observe_num = ((observe_num + context->observe_save_freq) /
663 context->observe_save_freq) *
664 context->observe_save_freq - 1;
665 resource_key.s = (uint8_t *)buf;
666 resource_key.length = strlen(buf);
667 r = coap_get_resource_from_uri_path(context, &resource_key);
668 if (r) {
669 coap_log_debug("persist: Initial observe number being updated\n");
670 coap_persist_set_observe_num(r, observe_num);
671 }
672 }
673 fclose(fp);
674}
675
676/*
677 * Called when the observe value of a resource has been changed, but limited
678 * to be called every context->context->observe_save_freq to reduce update
679 * overheads.
680 */
681 static int
682coap_op_obs_cnt_track_observe(coap_context_t *context,
683 coap_str_const_t *resource_name,
684 uint32_t n_observe_num,
685 void *user_data) {
686 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
687 FILE *fp_new = NULL;
688 char buf[1500];
689 char *new = NULL;
690
691 (void)user_data;
692
693 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
694 if (!new)
695 goto fail;
696
697 strcpy(new, (const char *)context->obs_cnt_save_file->s);
698 strcat(new, ".tmp");
699 fp_new = fopen(new, "w+");
700 if (fp_new == NULL)
701 goto fail;
702
703 /* Go through and locate resource entry to update */
704 while (fp_orig && fgets(buf, sizeof(buf), fp_orig) != NULL) {
705 char *cp = strchr(buf, ' ');
706 uint32_t observe_num;
707 coap_bin_const_t resource_key;
708
709 if (!cp)
710 break;
711
712 *cp = '\000';
713 cp++;
714 observe_num = atoi(cp);
715 resource_key.s = (uint8_t *)buf;
716 resource_key.length = strlen(buf);
717 if (!coap_binary_equal(resource_name, &resource_key)) {
718 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
719 goto fail;
720 }
721 }
722 if (fprintf(fp_new, "%s %u\n", resource_name->s, n_observe_num) < 0)
723 goto fail;
724 if (fflush(fp_new) == EOF)
725 goto fail;
726 fclose(fp_new);
727 if (fp_orig)
728 fclose(fp_orig);
729 /* Either old or new is in place */
730 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
731 coap_free_type(COAP_STRING, new);
732 return 1;
733
734fail:
735 if (fp_new)
736 fclose(fp_new);
737 if (fp_orig)
738 fclose(fp_orig);
739 if (new) {
740 (void)remove(new);
741 }
742 coap_free_type(COAP_STRING, new);
743 return 0;
744}
745
746/*
747 * Called when a resource has been deleted.
748 */
749 static int
750coap_op_obs_cnt_deleted(coap_context_t *context,
751 coap_str_const_t *resource_name) {
752 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
753 FILE *fp_new = NULL;
754 char buf[1500];
755 char *new = NULL;
756
757 if (fp_orig == NULL)
758 goto fail;
759 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
760 if (!new)
761 goto fail;
762
763 strcpy(new, (const char *)context->obs_cnt_save_file->s);
764 strcat(new, ".tmp");
765 fp_new = fopen(new, "w+");
766 if (fp_new == NULL)
767 goto fail;
768
769 /* Go through and locate resource entry to delete */
770 while (fgets(buf, sizeof(buf), fp_orig) != NULL) {
771 char *cp = strchr(buf, ' ');
772 uint32_t observe_num;
773 coap_bin_const_t resource_key;
774
775 if (!cp)
776 break;
777
778 *cp = '\000';
779 cp++;
780 observe_num = atoi(cp);
781 resource_key.s = (uint8_t *)buf;
782 resource_key.length = strlen(buf);
783 if (!coap_binary_equal(resource_name, &resource_key)) {
784 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
785 goto fail;
786 }
787 }
788 if (fflush(fp_new) == EOF)
789 goto fail;
790 fclose(fp_new);
791 fclose(fp_orig);
792 /* Either old or new is in place */
793 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
794 coap_free_type(COAP_STRING, new);
795 return 1;
796
797fail:
798 if (fp_new)
799 fclose(fp_new);
800 if (fp_orig)
801 fclose(fp_orig);
802 if (new) {
803 (void)remove(new);
804 }
805 coap_free_type(COAP_STRING, new);
806 return 0;
807}
808
809/*
810 * read in dynamic resource entry, allocating name & raw_packet
811 * which need to be freed off by caller.
812 */
813 static int
814coap_op_dyn_resource_read(FILE *fp, coap_proto_t *e_proto,
815 coap_string_t **name,
816 coap_binary_t **raw_packet) {
817 ssize_t size;
818
819 *name = NULL;
820 *raw_packet = NULL;
821
822 if (fread(e_proto, sizeof(*e_proto), 1, fp) == 1) {
823 /* New record 'proto len resource_name len raw_packet' */
824 if (fread(&size, sizeof(size), 1, fp) != 1)
825 goto fail;
826 if (size < 0 || size > 0x10000)
827 goto fail;
828 *name = coap_new_string(size);
829 if (!(*name))
830 goto fail;
831 if (fread((*name)->s, size, 1, fp) != 1)
832 goto fail;
833 if (fread(&size, sizeof(size), 1, fp) != 1)
834 goto fail;
835 if (size < 0 || size > 0x10000)
836 goto fail;
837 *raw_packet = coap_new_binary(size);
838 if (!(*raw_packet))
839 goto fail;
840 if (fread((*raw_packet)->s, size, 1, fp) != 1)
841 goto fail;
842 return 1;
843 }
844fail:
845 return 0;
846}
847
848/*
849 * write out dynamic resource entry.
850 */
851 static int
852coap_op_dyn_resource_write(FILE *fp, coap_proto_t e_proto,
853 coap_str_const_t *name,
854 coap_bin_const_t *raw_packet) {
855 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
856 goto fail;
857 if (fwrite(&name->length, sizeof(name->length), 1, fp) != 1)
858 goto fail;
859 if (fwrite(name->s, name->length, 1, fp) != 1)
860 goto fail;
861 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
862 goto fail;
863 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
864 goto fail;
865 return 1;
866fail:
867 return 0;
868}
869
870/*
871 * This should be called before coap_persist_track_funcs() to prevent
872 * coap_op_dyn_resource_added() getting unnecessarily called.
873 *
874 * Each record 'proto len resource_name len raw_packet'
875 */
876 static void
877coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
878 FILE *fp_orig = NULL;
879 coap_proto_t e_proto;
880 coap_string_t *name = NULL;
881 coap_binary_t *raw_packet = NULL;
882 coap_resource_t *r;
883 coap_session_t *session = NULL;
884 coap_pdu_t *request = NULL;
885 coap_pdu_t *response = NULL;
886 coap_string_t *query = NULL;
887
888 if (!ctx->unknown_resource)
889 return;
890
891 fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
892 if (fp_orig == NULL)
893 return;
894 session = (coap_session_t *)coap_malloc_type(COAP_SESSION,
895 sizeof(coap_session_t));
896 if (!session)
897 goto fail;
898 memset(session, 0, sizeof(coap_session_t));
899 session->context = ctx;
900
901 /* Go through and create each dynamic resource if it does not exist*/
902 while (1) {
903 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
904 break;
905 r = coap_get_resource_from_uri_path(ctx, (coap_str_const_t *)name);
906 if (!r) {
907 /* Create the new resource using the application logic */
908
909 coap_log_debug("persist: dynamic resource being re-created\n");
910 /*
911 * Need max space incase PDU is updated with updated token,
912 * huge size etc.
913 * */
914 request = coap_pdu_init(0, 0, 0, 0);
915 if (!request)
916 goto fail;
917
918 session->proto = e_proto;
919 if (!coap_pdu_parse(session->proto, raw_packet->s,
920 raw_packet->length, request)) {
921 goto fail;
922 }
923 if (!ctx->unknown_resource->handler[request->code-1])
924 goto fail;
925 response = coap_pdu_init(0, 0, 0, 0);
926 if (!response)
927 goto fail;
928 query = coap_get_query(request);
929 /* Call the application handler to set up this dynamic resource */
930 ctx->unknown_resource->handler[request->code-1](ctx->unknown_resource,
931 session, request,
932 query, response);
933 coap_delete_string(query);
934 query = NULL;
935 coap_delete_pdu(request);
936 request = NULL;
937 coap_delete_pdu(response);
938 response = NULL;
939 }
940 coap_delete_string(name);
941 coap_delete_binary(raw_packet);
942 }
943fail:
944 coap_delete_string(name);
945 coap_delete_binary(raw_packet);
946 coap_delete_string(query);
947 coap_delete_pdu(request);
948 coap_delete_pdu(response);
949 fclose(fp_orig);
950 coap_free_type(COAP_SESSION, session);
951}
952
953/*
954 * Server has set up a new dynamic resource agains a request for an unknown
955 * resource.
956 */
957 static int
958coap_op_dyn_resource_added(coap_session_t *session,
959 coap_str_const_t *resource_name,
960 coap_bin_const_t *packet,
961 void *user_data) {
962 FILE *fp_orig;
963 FILE *fp_new = NULL;
964 char *new = NULL;
965 coap_context_t *context = session->context;
966 coap_string_t *name = NULL;
967 coap_binary_t *raw_packet = NULL;
968 coap_proto_t e_proto;
969
970 (void)user_data;
971
972 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "a");
973 if (fp_orig == NULL)
974 return 0;
975
976 new = coap_malloc_type(COAP_STRING,
977 context->dyn_resource_save_file->length + 5);
978 if (!new)
979 goto fail;
980
981 strcpy(new, (const char *)context->dyn_resource_save_file->s);
982 strcat(new, ".tmp");
983 fp_new = fopen(new, "w+");
984 if (fp_new == NULL)
985 goto fail;
986
987 /* Go through and locate duplicate resource to delete */
988 while (1) {
989 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
990 break;
991 if (!coap_string_equal(resource_name, name)) {
992 /* Copy across non-matching entry */
993 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
994 (coap_bin_const_t *)raw_packet))
995 break;
996 }
997 coap_delete_string(name);
998 name = NULL;
999 coap_delete_binary(raw_packet);
1000 raw_packet = NULL;
1001 }
1002 coap_delete_string(name);
1003 coap_delete_binary(raw_packet);
1004 /* Add new entry to the end */
1005 if (!coap_op_dyn_resource_write(fp_new, session->proto,
1006 resource_name, packet))
1007 goto fail;
1008
1009 if (fflush(fp_new) == EOF)
1010 goto fail;
1011 fclose(fp_new);
1012 fclose(fp_orig);
1013 /* Either old or new is in place */
1014 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1015 coap_free_type(COAP_STRING, new);
1016 return 1;
1017
1018fail:
1019 if (fp_new)
1020 fclose(fp_new);
1021 if (fp_orig)
1022 fclose(fp_orig);
1023 if (new) {
1024 (void)remove(new);
1025 }
1026 coap_free_type(COAP_STRING, new);
1027 return 0;
1028}
1029
1030/*
1031 * Server has deleted a resource
1032 */
1033 static int
1034coap_op_resource_deleted(coap_context_t *context,
1035 coap_str_const_t *resource_name,
1036 void *user_data) {
1037 FILE *fp_orig = NULL;
1038 FILE *fp_new = NULL;
1039 char *new = NULL;
1040 coap_proto_t e_proto;
1041 coap_string_t *name = NULL;
1042 coap_binary_t *raw_packet = NULL;
1043 (void)user_data;
1044
1045 coap_op_obs_cnt_deleted(context, resource_name);
1046
1047 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "r");
1048 if (fp_orig == NULL)
1049 return 1;
1050
1051 new = coap_malloc_type(COAP_STRING,
1052 context->dyn_resource_save_file->length + 5);
1053 if (!new)
1054 goto fail;
1055
1056 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1057 strcat(new, ".tmp");
1058 fp_new = fopen(new, "w+");
1059 if (fp_new == NULL)
1060 goto fail;
1061
1062 /* Go through and locate resource to delete and not copy it across */
1063 while (1) {
1064 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1065 break;
1066 if (!coap_string_equal(resource_name, name)) {
1067 /* Copy across non-matching entry */
1068 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1069 (coap_bin_const_t *)raw_packet))
1070 break;
1071 }
1072 coap_delete_string(name);
1073 name = NULL;
1074 coap_delete_binary(raw_packet);
1075 raw_packet = NULL;
1076 }
1077 coap_delete_string(name);
1078 coap_delete_binary(raw_packet);
1079
1080 if (fflush(fp_new) == EOF)
1081 goto fail;
1082 fclose(fp_new);
1083 fclose(fp_orig);
1084 /* Either old or new is in place */
1085 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1086 coap_free_type(COAP_STRING, new);
1087 return 1;
1088
1089fail:
1090 if (fp_new)
1091 fclose(fp_new);
1092 if (fp_orig)
1093 fclose(fp_orig);
1094 if (new) {
1095 (void)remove(new);
1096 }
1097 coap_free_type(COAP_STRING, new);
1098 return 0;
1099}
1100
1101 int
1102 coap_persist_startup(coap_context_t *context,
1103 const char *dyn_resource_save_file,
1104 const char *observe_save_file,
1105 const char *obs_cnt_save_file,
1106 uint32_t save_freq) {
1107 if (dyn_resource_save_file) {
1108 context->dyn_resource_save_file =
1109 coap_new_bin_const((const uint8_t *)dyn_resource_save_file,
1110 strlen(dyn_resource_save_file));
1111 if (!context->dyn_resource_save_file)
1112 return 0;
1113 coap_op_dyn_resource_load_disk(context);
1114 context->dyn_resource_added = coap_op_dyn_resource_added;
1115 context->resource_deleted = coap_op_resource_deleted;
1116 }
1117 if (obs_cnt_save_file) {
1118 context->obs_cnt_save_file =
1119 coap_new_bin_const((const uint8_t *)obs_cnt_save_file,
1120 strlen(obs_cnt_save_file));
1121 if (!context->obs_cnt_save_file)
1122 return 0;
1123 context->observe_save_freq = save_freq ? save_freq : 1;
1124 coap_op_obs_cnt_load_disk(context);
1125 context->track_observe_value = coap_op_obs_cnt_track_observe;
1126 context->resource_deleted = coap_op_resource_deleted;
1127 }
1128 if (observe_save_file) {
1129 context->observe_save_file =
1130 coap_new_bin_const((const uint8_t *)observe_save_file,
1131 strlen(observe_save_file));
1132 if (!context->observe_save_file)
1133 return 0;
1134 coap_op_observe_load_disk(context);
1135 context->observe_added = coap_op_observe_added;
1136 context->observe_deleted = coap_op_observe_deleted;
1137 }
1138 return 1;
1139}
1140
1141 void
1142 coap_persist_cleanup(coap_context_t *context) {
1143 coap_delete_bin_const(context->dyn_resource_save_file);
1144 coap_delete_bin_const(context->obs_cnt_save_file);
1145 coap_delete_bin_const(context->observe_save_file);
1146 context->dyn_resource_save_file = NULL;
1147 context->obs_cnt_save_file = NULL;
1148 context->observe_save_file = NULL;
1149
1150 /* Close down any tracking */
1151 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1152 NULL, 0, NULL);
1153}
1154
1155 void
1156 coap_persist_stop(coap_context_t *context) {
1157 if (context == NULL)
1158 return;
1159 context->observe_no_clear = 1;
1160 coap_persist_cleanup(context);
1161}
1162#else /* ! COAP_WITH_OBSERVE_PERSIST */
1163 int
1164 coap_persist_startup(coap_context_t *context,
1165 const char *dyn_resource_save_file,
1166 const char *observe_save_file,
1167 const char *obs_cnt_save_file,
1168 uint32_t save_freq) {
1169 (void)context;
1170 (void)dyn_resource_save_file;
1171 (void)observe_save_file;
1172 (void)obs_cnt_save_file;
1173 (void)save_freq;
1174 return 0;
1175}
1176
1177 void
1178 coap_persist_stop(coap_context_t *context) {
1179 context->observe_no_clear = 1;
1180 /* Close down any tracking */
1181 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1182 NULL, 0, NULL);
1183}
1184
1185#endif /* ! COAP_WITH_OBSERVE_PERSIST */
1186
1187#endif /* COAP_SERVER_SUPPORT */
coap_internal.h
Pulls together all the internal only header files.
COAP_SESSION
@ COAP_SESSION
Definition: coap_mem.h:50
COAP_STRING
@ COAP_STRING
Definition: coap_mem.h:38
coap_malloc_type
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
coap_free_type
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
coap_opt_t
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: coap_option.h:26
coap_tick_t
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:144
coap_get_resource_from_uri_path
coap_resource_t * coap_get_resource_from_uri_path(coap_context_t *context, coap_str_const_t *uri_path)
Returns the resource identified by the unique string uri_path.
coap_ticks
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
coap_decode_var_bytes
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition: coap_encode.c:38
coap_log_debug
#define coap_log_debug(...)
Definition: coap_debug.h:120
coap_log_warn
#define coap_log_warn(...)
Definition: coap_debug.h:102
COAP_LOG_OSCORE
@ COAP_LOG_OSCORE
Definition: coap_debug.h:59
coap_dyn_resource_added_t
int(* coap_dyn_resource_added_t)(coap_session_t *session, coap_str_const_t *resource_name, coap_bin_const_t *raw_packet, void *user_data)
Callback handler definition called when a dynamic resource is getting created, as defined in coap_per...
Definition: coap_subscribe.h:141
coap_persist_stop
void coap_persist_stop(coap_context_t *context)
Stop tracking persist information, leaving the current persist information in the files defined in co...
coap_persist_set_observe_num
void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t observe_num)
Sets the current observe number value.
coap_resource_deleted_t
int(* coap_resource_deleted_t)(coap_context_t *context, coap_str_const_t *resource_name, void *user_data)
Callback handler definition called when resource is removed, as defined in coap_persist_track_funcs()...
Definition: coap_subscribe.h:160
coap_observe_added_t
int(* coap_observe_added_t)(coap_session_t *session, coap_subscription_t *observe_key, coap_proto_t e_proto, coap_address_t *e_listen_addr, coap_addr_tuple_t *s_addr_info, coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info, void *user_data)
Callback handler definition called when a new observe has been set up, as defined in coap_persist_tra...
Definition: coap_subscribe.h:84
COAP_OBSERVE_ESTABLISH
#define COAP_OBSERVE_ESTABLISH
The value COAP_OBSERVE_ESTABLISH in a GET/FETCH request option COAP_OPTION_OBSERVE indicates a new ob...
Definition: coap_subscribe.h:33
coap_persist_track_funcs
void coap_persist_track_funcs(coap_context_t *context, coap_observe_added_t observe_added, coap_observe_deleted_t observe_deleted, coap_track_observe_value_t track_observe_value, coap_dyn_resource_added_t dyn_resource_added, coap_resource_deleted_t resource_deleted, uint32_t save_freq, void *user_data)
Set up callbacks to handle persist tracking so on a coap-server inadvertent restart,...
coap_track_observe_value_t
int(* coap_track_observe_value_t)(coap_context_t *context, coap_str_const_t *resource_name, uint32_t observe_num, void *user_data)
Callback handler definition called when an observe unsolicited response is being sent,...
Definition: coap_subscribe.h:123
coap_observe_deleted_t
int(* coap_observe_deleted_t)(coap_session_t *session, coap_subscription_t *observe_key, void *user_data)
Callback handler definition called when an observe is being removed, as defined in coap_persist_track...
Definition: coap_subscribe.h:104
coap_persist_startup
int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq)
Start up persist tracking using the libcoap module.
coap_persist_observe_add
coap_subscription_t * coap_persist_observe_add(coap_context_t *context, coap_proto_t e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info)
Set up an active subscription for an observe that was previously active over a coap-server inadvertan...
coap_opt_length
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: coap_option.c:212
coap_check_option
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition: coap_option.c:199
coap_opt_value
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: coap_option.c:249
CBOR_BYTE_STRING
#define CBOR_BYTE_STRING
Definition: oscore_cbor.h:62
oscore_cbor_get_element_size
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len)
Definition: oscore_cbor.c:237
CBOR_NULL
#define CBOR_NULL
Definition: oscore_cbor.h:72
CBOR_SIMPLE_VALUE
#define CBOR_SIMPLE_VALUE
Definition: oscore_cbor.h:67
oscore_cbor_get_next_element
uint8_t oscore_cbor_get_next_element(const uint8_t **buffer, size_t *buf_len)
Definition: oscore_cbor.c:224
CBOR_ARRAY
#define CBOR_ARRAY
Definition: oscore_cbor.h:64
oscore_new_association
int oscore_new_association(coap_session_t *session, coap_pdu_t *sent_pdu, coap_bin_const_t *token, oscore_recipient_ctx_t *recipient_ctx, coap_bin_const_t *aad, coap_bin_const_t *nonce, coap_bin_const_t *partial_iv, int is_observe)
Definition: oscore_context.c:686
oscore_log_hex_value
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
Definition: oscore_context.c:235
oscore_find_context
oscore_ctx_t * oscore_find_context(const coap_context_t *c_context, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
Definition: oscore_context.c:185
coap_delete_pdu
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: coap_pdu.c:163
coap_proto_t
coap_proto_t
CoAP protocol types.
Definition: coap_pdu.h:304
coap_pdu_parse
int coap_pdu_parse(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition: coap_pdu.c:1382
coap_pdu_init
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition: coap_pdu.c:97
COAP_OPTION_OBSERVE
#define COAP_OPTION_OBSERVE
Definition: coap_pdu.h:119
COAP_PROTO_UDP
@ COAP_PROTO_UDP
Definition: coap_pdu.h:306
COAP_REQUEST_CODE_GET
@ COAP_REQUEST_CODE_GET
Definition: coap_pdu.h:321
COAP_REQUEST_CODE_FETCH
@ COAP_REQUEST_CODE_FETCH
Definition: coap_pdu.h:325
coap_endpoint_get_session
coap_session_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Lookup the server session for the packet received on an endpoint, or create a new one.
coap_delete_bin_const
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition: coap_str.c:120
coap_new_binary
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition: coap_str.c:77
coap_new_bin_const
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition: coap_str.c:110
coap_delete_binary
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition: coap_str.c:105
coap_binary_equal
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition: coap_str.h:203
coap_string_equal
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition: coap_str.h:189
coap_new_string
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition: coap_str.c:21
coap_delete_string
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition: coap_str.c:46
coap_persist_cleanup
void coap_persist_cleanup(coap_context_t *context)
Close down persist tracking, releasing any memory used.
coap_subscription_init
void coap_subscription_init(coap_subscription_t *)
coap_add_observer
coap_subscription_t * coap_add_observer(coap_resource_t *resource, coap_session_t *session, const coap_bin_const_t *token, const coap_pdu_t *pdu)
Adds the specified peer as observer for resource.
coap_get_uri_path
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition: coap_uri.c:769
coap_get_query
coap_string_t * coap_get_query(const coap_pdu_t *request)
Extract query string from request PDU according to escape rules in 6.5.8.
Definition: coap_uri.c:718
coap_addr_tuple_t
Definition: coap_io.h:55
coap_address_t
Multi-purpose address abstraction.
Definition: coap_address.h:109
coap_bin_const_t
CoAP binary data definition with const data.
Definition: coap_str.h:64
coap_bin_const_t::length
size_t length
length of binary data
Definition: coap_str.h:65
coap_bin_const_t::s
const uint8_t * s
read-only binary data
Definition: coap_str.h:66
coap_binary_t
CoAP binary data definition.
Definition: coap_str.h:56
coap_binary_t::length
size_t length
length of binary data
Definition: coap_str.h:57
coap_binary_t::s
uint8_t * s
binary data
Definition: coap_str.h:58
coap_context_t
The CoAP stack's global state is stored in a coap_context_t object.
Definition: coap_net_internal.h:49
coap_context_t::observe_added
coap_observe_added_t observe_added
Called when there is a new observe subscription request.
Definition: coap_net_internal.h:109
coap_context_t::dyn_resource_added
coap_dyn_resource_added_t dyn_resource_added
Callback to save dynamic resource when created.
Definition: coap_net_internal.h:118
coap_context_t::observe_user_data
void * observe_user_data
App provided data for use in observe_added or observe_deleted.
Definition: coap_net_internal.h:113
coap_context_t::track_observe_value
coap_track_observe_value_t track_observe_value
Callback to save observe value when updated.
Definition: coap_net_internal.h:116
coap_context_t::endpoint
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: coap_net_internal.h:75
coap_context_t::observe_save_freq
uint32_t observe_save_freq
How frequently to update observe value.
Definition: coap_net_internal.h:115
coap_context_t::observe_no_clear
uint8_t observe_no_clear
Observe 4.04 not to be sent on deleting resource.
Definition: coap_net_internal.h:186
coap_context_t::observe_deleted
coap_observe_deleted_t observe_deleted
Called when there is a observe subscription de-register request.
Definition: coap_net_internal.h:111
coap_context_t::unknown_resource
coap_resource_t * unknown_resource
can be used for handling unknown resources
Definition: coap_net_internal.h:54
coap_context_t::resource_deleted
coap_resource_deleted_t resource_deleted
Invoked when resource is deleted.
Definition: coap_net_internal.h:120
coap_endpoint_t
Abstraction of virtual endpoint that can be attached to coap_context_t.
Definition: coap_session_internal.h:219
coap_endpoint_t::next
struct coap_endpoint_t * next
Definition: coap_session_internal.h:220
coap_endpoint_t::bind_addr
coap_address_t bind_addr
local interface address
Definition: coap_session_internal.h:226
coap_endpoint_t::proto
coap_proto_t proto
protocol used on this interface
Definition: coap_session_internal.h:222
coap_opt_iterator_t
Iterator to run through PDU options.
Definition: coap_option.h:168
coap_packet_t
Definition: coap_io_internal.h:207
coap_packet_t::length
size_t length
length of payload
Definition: coap_io_internal.h:210
coap_packet_t::addr_info
coap_addr_tuple_t addr_info
local and remote addresses
Definition: coap_io_internal.h:208
coap_packet_t::payload
unsigned char * payload
payload
Definition: coap_io_internal.h:211
coap_packet_t::ifindex
int ifindex
the interface index
Definition: coap_io_internal.h:209
coap_pdu_t
structure for CoAP PDUs
Definition: coap_pdu_internal.h:119
coap_pdu_t::max_size
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
Definition: coap_pdu_internal.h:137
coap_pdu_t::code
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
Definition: coap_pdu_internal.h:121
coap_pdu_t::actual_token
coap_bin_const_t actual_token
Actual token in pdu.
Definition: coap_pdu_internal.h:132
coap_pdu_t::used_size
size_t used_size
used bytes of storage for token, options and payload
Definition: coap_pdu_internal.h:135
coap_resource_t
Abstraction of resource that can be attached to coap_context_t.
Definition: coap_resource_internal.h:53
coap_resource_t::handler
coap_method_handler_t handler[7]
Used to store handlers for the seven coap methods GET, POST, PUT, DELETE, FETCH, PATCH and IPATCH.
Definition: coap_resource_internal.h:69
coap_resource_t::observable
unsigned int observable
can be observed
Definition: coap_resource_internal.h:57
coap_session_t
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
Definition: coap_session_internal.h:68
coap_session_t::proto
coap_proto_t proto
protocol used
Definition: coap_session_internal.h:69
coap_session_t::context
coap_context_t * context
session's context
Definition: coap_session_internal.h:86
coap_str_const_t
CoAP string data definition with const data.
Definition: coap_str.h:46
coap_str_const_t::s
const uint8_t * s
read-only string data
Definition: coap_str.h:48
coap_str_const_t::length
size_t length
length of string
Definition: coap_str.h:47
coap_string_t
CoAP string data definition.
Definition: coap_str.h:38
coap_string_t::s
uint8_t * s
string data
Definition: coap_str.h:40
coap_subscription_t
Number of notifications that may be sent non-confirmable before a confirmable message is sent to dete...
Definition: coap_subscribe_internal.h:57
oscore_ctx_t
Definition: oscore_context.h:84