libcoap 4.3.5-develop-3f4d08f
Loading...
Searching...
No Matches
coap_net.c
Go to the documentation of this file.
1/* coap_net.c -- CoAP context inteface
2 *
3 * Copyright (C) 2010--2026 Olaf Bergmann <bergmann@tzi.org> and others
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
18
19#include <ctype.h>
20#include <stdio.h>
21#ifdef HAVE_LIMITS_H
22#include <limits.h>
23#endif
24
25#ifndef __ZEPHYR__
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#else
29#ifdef HAVE_SYS_UNISTD_H
30#include <sys/unistd.h>
31#endif
32#endif
33#ifdef HAVE_SYS_TYPES_H
34#include <sys/types.h>
35#endif
36#ifdef HAVE_SYS_SOCKET_H
37#include <sys/socket.h>
38#endif
39#ifdef HAVE_SYS_IOCTL_H
40#include <sys/ioctl.h>
41#endif
42#ifdef HAVE_NETINET_IN_H
43#include <netinet/in.h>
44#endif
45#ifdef HAVE_ARPA_INET_H
46#include <arpa/inet.h>
47#endif
48#ifdef HAVE_NET_IF_H
49#include <net/if.h>
50#endif
51#ifdef COAP_EPOLL_SUPPORT
52#include <sys/epoll.h>
53#include <sys/timerfd.h>
54#endif /* COAP_EPOLL_SUPPORT */
55#ifdef HAVE_WS2TCPIP_H
56#include <ws2tcpip.h>
57#endif
58
59#ifdef HAVE_NETDB_H
60#include <netdb.h>
61#endif
62#endif /* !__ZEPHYR__ */
63
64#ifdef WITH_LWIP
65#include <lwip/pbuf.h>
66#include <lwip/udp.h>
67#include <lwip/timeouts.h>
68#include <lwip/tcpip.h>
69#endif
70
71#ifndef INET6_ADDRSTRLEN
72#define INET6_ADDRSTRLEN 40
73#endif
74
75#ifndef min
76#define min(a,b) ((a) < (b) ? (a) : (b))
77#endif
78
83#define FRAC_BITS 6
84
89#define MAX_BITS 8
90
91#if FRAC_BITS > 8
92#error FRAC_BITS must be less or equal 8
93#endif
94
96#define Q(frac,fval) ((uint16_t)(((1 << (frac)) * fval.integer_part) + \
97 ((1 << (frac)) * fval.fractional_part + 500)/1000))
98
100#define ACK_RANDOM_FACTOR \
101 Q(FRAC_BITS, session->ack_random_factor)
102
104#define ACK_TIMEOUT Q(FRAC_BITS, session->ack_timeout)
105
110
115
116unsigned int
118 unsigned int result = 0;
120
121 if (ctx->sendqueue) {
122 /* delta < 0 means that the new time stamp is before the old. */
123 if (delta <= 0) {
124 ctx->sendqueue->t = (coap_tick_diff_t)ctx->sendqueue->t - delta;
125 } else {
126 /* This case is more complex: The time must be advanced forward,
127 * thus possibly leading to timed out elements at the queue's
128 * start. For every element that has timed out, its relative
129 * time is set to zero and the result counter is increased. */
130
131 coap_queue_t *q = ctx->sendqueue;
132 coap_tick_t t = 0;
133 while (q && (t + q->t < (coap_tick_t)delta)) {
134 t += q->t;
135 q->t = 0;
136 result++;
137 q = q->next;
138 }
139
140 /* finally adjust the first element that has not expired */
141 if (q) {
142 q->t = (coap_tick_t)delta - t;
143 }
144 }
145 }
146
147 /* adjust basetime */
149
150 return result;
151}
152
153int
155 coap_queue_t *p, *q;
156 if (!queue || !node)
157 return 0;
158
159 /* set queue head if empty */
160 if (!*queue) {
161 *queue = node;
162 return 1;
163 }
164
165 /* replace queue head if PDU's time is less than head's time */
166 q = *queue;
167 if (node->t < q->t) {
168 node->next = q;
169 *queue = node;
170 q->t -= node->t; /* make q->t relative to node->t */
171 return 1;
172 }
173
174 /* search for right place to insert */
175 do {
176 node->t -= q->t; /* make node-> relative to q->t */
177 p = q;
178 q = q->next;
179 } while (q && q->t <= node->t);
180
181 /* insert new item */
182 if (q) {
183 q->t -= node->t; /* make q->t relative to node->t */
184 }
185 node->next = q;
186 p->next = node;
187 return 1;
188}
189
190COAP_API int
192 int ret;
193#if COAP_THREAD_SAFE
194 coap_context_t *context;
195#endif /* COAP_THREAD_SAFE */
196
197 if (!node)
198 return 0;
199 if (!node->session)
200 return coap_delete_node_lkd(node);
201
202#if COAP_THREAD_SAFE
203 /* Keep copy as node will be going away */
204 context = node->session->context;
205 (void)context;
206#endif /* COAP_THREAD_SAFE */
207 coap_lock_lock(return 0);
208 ret = coap_delete_node_lkd(node);
210 return ret;
211}
212
213int
215 if (!node)
216 return 0;
217
219 if (node->session) {
220 /*
221 * Need to remove out of context->sendqueue as added in by coap_wait_ack()
222 */
223 if (node->session->context->sendqueue) {
224 LL_DELETE(node->session->context->sendqueue, node);
225 }
227 }
228 coap_free_node(node);
229
230 return 1;
231}
232
233void
235 if (!queue)
236 return;
237
238 coap_delete_all(queue->next);
240}
241
244 coap_queue_t *node;
245 node = coap_malloc_node();
246
247 if (!node) {
248 coap_log_warn("coap_new_node: malloc failed\n");
249 return NULL;
250 }
251
252 memset(node, 0, sizeof(*node));
253 return node;
254}
255
258 if (!context || !context->sendqueue)
259 return NULL;
260
261 return context->sendqueue;
262}
263
266 coap_queue_t *next;
267
268 if (!context || !context->sendqueue)
269 return NULL;
270
271 next = context->sendqueue;
272 context->sendqueue = context->sendqueue->next;
273 if (context->sendqueue) {
274 context->sendqueue->t += next->t;
275 }
276 next->next = NULL;
277 return next;
278}
279
280#if COAP_CLIENT_SUPPORT
281const coap_bin_const_t *
283
284 if (session->psk_key) {
285 return session->psk_key;
286 }
287 if (session->cpsk_setup_data.psk_info.key.length)
288 return &session->cpsk_setup_data.psk_info.key;
289
290 /* Not defined in coap_new_client_session_psk2() */
291 return NULL;
292}
293
294const coap_bin_const_t *
296
297 if (session->psk_identity) {
298 return session->psk_identity;
299 }
301 return &session->cpsk_setup_data.psk_info.identity;
302
303 /* Not defined in coap_new_client_session_psk2() */
304 return NULL;
305}
306#endif /* COAP_CLIENT_SUPPORT */
307
308#if COAP_SERVER_SUPPORT
309const coap_bin_const_t *
311
312 if (session->psk_key)
313 return session->psk_key;
314
315 if (session->context->spsk_setup_data.psk_info.key.length)
316 return &session->context->spsk_setup_data.psk_info.key;
317
318 /* Not defined in coap_context_set_psk2() */
319 return NULL;
320}
321
322const coap_bin_const_t *
324
325 if (session->psk_hint)
326 return session->psk_hint;
327
328 if (session->context->spsk_setup_data.psk_info.hint.length)
329 return &session->context->spsk_setup_data.psk_info.hint;
330
331 /* Not defined in coap_context_set_psk2() */
332 return NULL;
333}
334
335COAP_API int
337 const char *hint,
338 const uint8_t *key,
339 size_t key_len) {
340 int ret;
341
342 coap_lock_lock(return 0);
343 ret = coap_context_set_psk_lkd(ctx, hint, key, key_len);
345 return ret;
346}
347
348int
350 const char *hint,
351 const uint8_t *key,
352 size_t key_len) {
353 coap_dtls_spsk_t setup_data;
354
356 memset(&setup_data, 0, sizeof(setup_data));
357 if (hint) {
358 setup_data.psk_info.hint.s = (const uint8_t *)hint;
359 setup_data.psk_info.hint.length = strlen(hint);
360 }
361
362 if (key && key_len > 0) {
363 setup_data.psk_info.key.s = key;
364 setup_data.psk_info.key.length = key_len;
365 }
366
367 return coap_context_set_psk2_lkd(ctx, &setup_data);
368}
369
370COAP_API int
372 int ret;
373
374 coap_lock_lock(return 0);
375 ret = coap_context_set_psk2_lkd(ctx, setup_data);
377 return ret;
378}
379
380int
382 if (!setup_data)
383 return 0;
384
386 ctx->spsk_setup_data = *setup_data;
387
389 return coap_dtls_context_set_spsk(ctx, setup_data);
390 }
391 return 0;
392}
393
394COAP_API int
396 const coap_dtls_pki_t *setup_data) {
397 int ret;
398
399 coap_lock_lock(return 0);
400 ret = coap_context_set_pki_lkd(ctx, setup_data);
402 return ret;
403}
404
405int
407 const coap_dtls_pki_t *setup_data) {
409 if (!setup_data)
410 return 0;
411 if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
412 coap_log_err("coap_context_set_pki: Wrong version of setup_data\n");
413 return 0;
414 }
416 return coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_SERVER);
417 }
418 return 0;
419}
420#endif /* ! COAP_SERVER_SUPPORT */
421
422COAP_API int
424 const char *ca_file,
425 const char *ca_dir) {
426 int ret;
427
428 coap_lock_lock(return 0);
429 ret = coap_context_set_pki_root_cas_lkd(ctx, ca_file, ca_dir);
431 return ret;
432}
433
434int
436 const char *ca_file,
437 const char *ca_dir) {
439 return coap_dtls_context_set_pki_root_cas(ctx, ca_file, ca_dir);
440 }
441 return 0;
442}
443
444COAP_API int
446 int ret;
447
448 coap_lock_lock(return 0);
451 return ret;
452}
453
454int
461
462
463void
464coap_context_set_keepalive(coap_context_t *context, unsigned int seconds) {
465 context->ping_timeout = seconds;
466}
467
468int
470#if COAP_CLIENT_SUPPORT
471 return coap_dtls_set_cid_tuple_change(context, every);
472#else /* ! COAP_CLIENT_SUPPORT */
473 (void)context;
474 (void)every;
475 return 0;
476#endif /* ! COAP_CLIENT_SUPPORT */
477}
478
479void
481 uint64_t rate_limit_ppm) {
482 if (rate_limit_ppm) {
483 context->rl_ticks_per_packet = (60ULL * COAP_TICKS_PER_SECOND) / rate_limit_ppm;
484 } else {
485 context->rl_ticks_per_packet = 0;
486 }
487}
488
489void
491 uint32_t max_body_size) {
492 assert(max_body_size == 0 || max_body_size > 1024);
493 if (max_body_size == 0 || max_body_size > 1024) {
494 context->max_body_size = max_body_size;
495 }
496}
497
498void
500 size_t max_token_size) {
501 assert(max_token_size >= COAP_TOKEN_DEFAULT_MAX &&
502 max_token_size <= COAP_TOKEN_EXT_MAX);
503 if (max_token_size >= COAP_TOKEN_DEFAULT_MAX &&
504 max_token_size <= COAP_TOKEN_EXT_MAX) {
505 context->max_token_size = (uint32_t)max_token_size;
506 }
507}
508
509void
511 unsigned int max_idle_sessions) {
512 context->max_idle_sessions = max_idle_sessions;
513}
514
515unsigned int
517 return context->max_idle_sessions;
518}
519
520void
522 unsigned int max_handshake_sessions) {
523 context->max_handshake_sessions = max_handshake_sessions;
524}
525
526unsigned int
530
531static unsigned int s_csm_timeout = 30;
532
533void
535 unsigned int csm_timeout) {
536 s_csm_timeout = csm_timeout;
537 coap_context_set_csm_timeout_ms(context, csm_timeout * 1000);
538}
539
540unsigned int
542 (void)context;
543 return s_csm_timeout;
544}
545
546void
548 unsigned int csm_timeout_ms) {
549 if (csm_timeout_ms < 10)
550 csm_timeout_ms = 10;
551 if (csm_timeout_ms > 10000)
552 csm_timeout_ms = 10000;
553 context->csm_timeout_ms = csm_timeout_ms;
554}
555
556unsigned int
558 return context->csm_timeout_ms;
559}
560
561void
563 uint32_t csm_max_message_size) {
564 assert(csm_max_message_size >= 64);
565 if (csm_max_message_size > COAP_DEFAULT_MAX_PDU_RX_SIZE) {
566 csm_max_message_size = COAP_DEFAULT_MAX_PDU_RX_SIZE;
567 coap_log_debug("Restricting CSM Max-Message-Size size to %" PRIu32 "\n",
568 csm_max_message_size);
569 }
570
571 context->csm_max_message_size = csm_max_message_size;
572}
573
574uint32_t
578
579void
581 unsigned int session_timeout) {
582 context->session_timeout = session_timeout;
583}
584
585void
587 unsigned int reconnect_time) {
588 coap_context_set_session_reconnect_time2(context, reconnect_time, 0);
589}
590
591void
593 unsigned int reconnect_time,
594 uint8_t retry_count) {
595#if COAP_CLIENT_SUPPORT
596 context->reconnect_time = reconnect_time;
597 context->retry_count = retry_count;
598#else /* ! COAP_CLIENT_SUPPORT */
599 (void)context;
600 (void)reconnect_time;
601 (void)retry_count;
602#endif /* ! COAP_CLIENT_SUPPORT */
603}
604
605unsigned int
607 return context->session_timeout;
608}
609
610void
612#if COAP_SERVER_SUPPORT
613 context->shutdown_no_send_observe = 1;
614#else /* ! COAP_SERVER_SUPPORT */
615 (void)context;
616#endif /* ! COAP_SERVER_SUPPORT */
617}
618
619int
621#if COAP_EPOLL_SUPPORT
622 return context->epfd;
623#else /* ! COAP_EPOLL_SUPPORT */
624 (void)context;
625 return -1;
626#endif /* ! COAP_EPOLL_SUPPORT */
627}
628
629int
631#if COAP_EPOLL_SUPPORT
632 return 1;
633#else /* ! COAP_EPOLL_SUPPORT */
634 return 0;
635#endif /* ! COAP_EPOLL_SUPPORT */
636}
637
638int
640#if COAP_THREAD_SAFE
641 return 1;
642#else /* ! COAP_THREAD_SAFE */
643 return 0;
644#endif /* ! COAP_THREAD_SAFE */
645}
646
647int
649#if COAP_IPV4_SUPPORT
650 return 1;
651#else /* ! COAP_IPV4_SUPPORT */
652 return 0;
653#endif /* ! COAP_IPV4_SUPPORT */
654}
655
656int
658#if COAP_IPV6_SUPPORT
659 return 1;
660#else /* ! COAP_IPV6_SUPPORT */
661 return 0;
662#endif /* ! COAP_IPV6_SUPPORT */
663}
664
665int
667#if COAP_CLIENT_SUPPORT
668 return 1;
669#else /* ! COAP_CLIENT_SUPPORT */
670 return 0;
671#endif /* ! COAP_CLIENT_SUPPORT */
672}
673
674int
676#if COAP_SERVER_SUPPORT
677 return 1;
678#else /* ! COAP_SERVER_SUPPORT */
679 return 0;
680#endif /* ! COAP_SERVER_SUPPORT */
681}
682
683int
685#if COAP_AF_UNIX_SUPPORT
686 return 1;
687#else /* ! COAP_AF_UNIX_SUPPORT */
688 return 0;
689#endif /* ! COAP_AF_UNIX_SUPPORT */
690}
691
692COAP_API void
693coap_context_set_app_data(coap_context_t *context, void *app_data) {
694 assert(context);
695 coap_lock_lock(return);
696 coap_context_set_app_data2_lkd(context, app_data, NULL);
698}
699
700void *
702 assert(context);
703 return context->app_data;
704}
705
706COAP_API void *
709 void *old_data;
710
711 coap_lock_lock(return NULL);
712 old_data = coap_context_set_app_data2_lkd(context, app_data, callback);
714 return old_data;
715}
716
717void *
720 void *old_data = context->app_data;
721
722 context->app_data = app_data;
723 context->app_cb = app_data ? callback : NULL;
724 return old_data;
725}
726
728coap_new_context(const coap_address_t *listen_addr) {
730
731#if ! COAP_SERVER_SUPPORT
732 (void)listen_addr;
733#endif /* COAP_SERVER_SUPPORT */
734
735 if (!coap_started) {
736 coap_startup();
737 coap_log_warn("coap_startup() should be called before any other "
738 "coap_*() functions are called\n");
739 }
740
742 if (!c) {
743 coap_log_emerg("coap_init: malloc: failed\n");
744 return NULL;
745 }
746 memset(c, 0, sizeof(coap_context_t));
747
749#ifdef COAP_EPOLL_SUPPORT
750 c->epfd = epoll_create1(0);
751 if (c->epfd == -1) {
752 coap_log_err("coap_new_context: Unable to epoll_create: %s (%d)\n",
754 errno);
755 goto onerror;
756 }
757 if (c->epfd != -1) {
758 c->eptimerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);
759 if (c->eptimerfd == -1) {
760 coap_log_err("coap_new_context: Unable to timerfd_create: %s (%d)\n",
762 errno);
763 goto onerror;
764 } else {
765 int ret;
766 struct epoll_event event;
767
768 /* Needed if running 32bit as ptr is only 32bit */
769 memset(&event, 0, sizeof(event));
770 event.events = EPOLLIN;
771 /* We special case this event by setting to NULL */
772 event.data.ptr = NULL;
773
774 ret = epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->eptimerfd, &event);
775 if (ret == -1) {
776 coap_log_err("%s: epoll_ctl ADD failed: %s (%d)\n",
777 "coap_new_context",
778 coap_socket_strerror(), errno);
779 goto onerror;
780 }
781 }
782 }
783#endif /* COAP_EPOLL_SUPPORT */
784
787 if (!c->dtls_context) {
788 coap_log_emerg("coap_init: no DTLS context available\n");
789 goto onerror;
790 }
791 }
792
793 /* set default CSM values */
794 c->csm_timeout_ms = 1000;
796
797#if COAP_SERVER_SUPPORT
798 if (listen_addr) {
799 coap_endpoint_t *endpoint = coap_new_endpoint_lkd(c, listen_addr, COAP_PROTO_UDP);
800 if (endpoint == NULL) {
801 goto onerror;
802 }
803 }
804#endif /* COAP_SERVER_SUPPORT */
805
806 c->max_token_size = COAP_TOKEN_DEFAULT_MAX; /* RFC8974 */
807
809 return c;
810
811onerror:
814 return NULL;
815}
816
817COAP_API void
818coap_set_app_data(coap_context_t *context, void *app_data) {
819 assert(context);
820 coap_lock_lock(return);
821 coap_context_set_app_data2_lkd(context, app_data, NULL);
823}
824
825void *
827 assert(ctx);
828 return ctx->app_data;
829}
830
831COAP_API void
833 if (!context)
834 return;
835 coap_lock_lock(return);
836 coap_free_context_lkd(context);
838}
839
840void
842 if (!context)
843 return;
844
846#if COAP_SERVER_SUPPORT
847 /* Removing a resource may cause a NON unsolicited observe to be sent */
848 context->context_going_away = 1;
849 if (context->shutdown_no_send_observe)
850 context->observe_no_clear = 1;
851 coap_delete_all_resources(context);
852#endif /* COAP_SERVER_SUPPORT */
853#if COAP_CLIENT_SUPPORT
854 /* Stop any attempts at reconnection */
855 context->reconnect_time = 0;
856#endif /* COAP_CLIENT_SUPPORT */
857
858 coap_delete_all(context->sendqueue);
859 context->sendqueue = NULL;
860
861#ifdef WITH_LWIP
862 if (context->timer_configured) {
863 LOCK_TCPIP_CORE();
864 sys_untimeout(coap_io_process_timeout, (void *)context);
865 UNLOCK_TCPIP_CORE();
866 context->timer_configured = 0;
867 }
868#endif /* WITH_LWIP */
869
870#if COAP_ASYNC_SUPPORT
871 coap_delete_all_async(context);
872#endif /* COAP_ASYNC_SUPPORT */
873
874#if COAP_OSCORE_SUPPORT
875 coap_delete_all_oscore(context);
876#endif /* COAP_OSCORE_SUPPORT */
877
878#if COAP_SERVER_SUPPORT
879 coap_cache_entry_t *cp, *ctmp;
880 coap_endpoint_t *ep, *tmp;
881
882 HASH_ITER(hh, context->cache, cp, ctmp) {
883 coap_delete_cache_entry(context, cp);
884 }
885 if (context->cache_ignore_count) {
886 coap_free_type(COAP_STRING, context->cache_ignore_options);
887 }
888
889 LL_FOREACH_SAFE(context->endpoint, ep, tmp) {
890 coap_free_endpoint_lkd(ep);
891 }
892#endif /* COAP_SERVER_SUPPORT */
893
894#if COAP_CLIENT_SUPPORT
895 coap_session_t *sp, *rtmp;
896
897 SESSIONS_ITER_SAFE(context->sessions, sp, rtmp) {
899 }
900#endif /* COAP_CLIENT_SUPPORT */
901
902 if (context->dtls_context)
904#ifdef COAP_EPOLL_SUPPORT
905 if (context->eptimerfd != -1) {
906 int ret;
907 struct epoll_event event;
908
909 /* Kernels prior to 2.6.9 expect non NULL event parameter */
910 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, context->eptimerfd, &event);
911 if (ret == -1) {
912 coap_log_err("%s: epoll_ctl DEL failed: %s (%d)\n",
913 "coap_free_context",
914 coap_socket_strerror(), errno);
915 }
916 close(context->eptimerfd);
917 context->eptimerfd = -1;
918 }
919 if (context->epfd != -1) {
920 close(context->epfd);
921 context->epfd = -1;
922 }
923#endif /* COAP_EPOLL_SUPPORT */
924#if COAP_SERVER_SUPPORT
925#if COAP_WITH_OBSERVE_PERSIST
926 coap_persist_cleanup(context);
927#endif /* COAP_WITH_OBSERVE_PERSIST */
928#endif /* COAP_SERVER_SUPPORT */
929#if COAP_PROXY_SUPPORT
930 coap_proxy_cleanup(context);
931#endif /* COAP_PROXY_SUPPORT */
932
933 if (context->app_cb) {
934 coap_lock_callback(context->app_cb(context->app_data));
935 }
936#if COAP_THREAD_SAFE && !WITH_LWIP
938#endif /* COAP_THREAD_SAFE && !WITH_LWIP */
941}
942
943int
945 coap_pdu_t *pdu,
946 coap_opt_filter_t *unknown) {
947 coap_context_t *ctx = session->context;
948 coap_opt_iterator_t opt_iter;
949 int ok = 1;
950 coap_option_num_t last_number = -1;
951
953
954 while (coap_option_next(&opt_iter)) {
955 /* Check for explicitely reserved option RFC 5272 12.2 Table 7 */
956 /* Need to check reserved options */
957 switch (opt_iter.number) {
958 case 0:
959 case 128:
960 case 132:
961 case 136:
962 case 140:
963 if (coap_option_filter_get(&ctx->known_options, opt_iter.number) <= 0) {
964 coap_log_debug("unknown reserved option %d\n", opt_iter.number);
965 ok = 0;
966
967 /* When opt_iter.number cannot be set in unknown, all of the appropriate
968 * slots have been used up and no more options can be tracked.
969 * Safe to break out of this loop as ok is already set. */
970 if (coap_option_filter_set(unknown, opt_iter.number) == 0) {
971 goto overflow;
972 }
973 }
974 break;
975 default:
976 break;
977 }
978 if (opt_iter.number & 0x01) {
979 /* first check the known built-in critical options */
980 switch (opt_iter.number) {
981#if COAP_Q_BLOCK_SUPPORT
984 if (!(ctx->block_mode & COAP_BLOCK_TRY_Q_BLOCK)) {
985 coap_log_debug("disabled support for critical option %u\n",
986 opt_iter.number);
987 ok = 0;
988 /* When opt_iter.number cannot be set in unknown, all of the appropriate
989 * slots have been used up and no more options can be tracked.
990 * Safe to break out of this loop as ok is already set. */
991 if (coap_option_filter_set(unknown, opt_iter.number) == 0) {
992 goto overflow;
993 }
994 }
995 break;
996#endif /* COAP_Q_BLOCK_SUPPORT */
1003 case COAP_OPTION_ACCEPT:
1006 case COAP_OPTION_BLOCK2:
1007 case COAP_OPTION_BLOCK1:
1008 break;
1009 case COAP_OPTION_OSCORE:
1010 /* Valid critical if doing OSCORE */
1011#if COAP_OSCORE_SUPPORT
1012 if (ctx->p_osc_ctx)
1013 break;
1014#endif /* COAP_OSCORE_SUPPORT */
1015 /* Fall Through */
1016 default:
1017 if (coap_option_filter_get(&ctx->known_options, opt_iter.number) <= 0) {
1018#if COAP_SERVER_SUPPORT
1019 if ((opt_iter.number & 0x02) == 0) {
1020 coap_opt_iterator_t t_iter;
1021
1022 /* Safe to forward - check if proxy pdu */
1023 if (session->proxy_session)
1024 break;
1025 if (COAP_PDU_IS_REQUEST(pdu) && ctx->proxy_uri_resource &&
1026 (coap_check_option(pdu, COAP_OPTION_PROXY_URI, &t_iter) ||
1028 pdu->crit_opt = 1;
1029 break;
1030 }
1031 if (COAP_PDU_IS_REQUEST(pdu) && ctx->unknown_resource &&
1032 ctx->unknown_resource->is_reverse_proxy) {
1033 pdu->crit_opt = 1;
1034 break;
1035 }
1036 }
1037#endif /* COAP_SERVER_SUPPORT */
1038 coap_log_debug("unknown critical option %d\n", opt_iter.number);
1039 ok = 0;
1040
1041 /* When opt_iter.number cannot be set in unknown, all of the appropriate
1042 * slots have been used up and no more options can be tracked.
1043 * Safe to break out of this loop as ok is already set. */
1044 if (coap_option_filter_set(unknown, opt_iter.number) == 0) {
1045 goto overflow;
1046 }
1047 }
1048 }
1049 }
1050 if (last_number == opt_iter.number) {
1051 /* Check for duplicated option RFC 5272 5.4.5 */
1052 if (!coap_option_check_repeatable(opt_iter.number)) {
1053 if (coap_option_filter_get(&ctx->known_options, opt_iter.number) <= 0) {
1054 ok = 0;
1055 if (coap_option_filter_set(unknown, opt_iter.number) == 0) {
1056 goto overflow;
1057 }
1058 }
1059 }
1060 } else if (opt_iter.number == COAP_OPTION_BLOCK2 &&
1061 COAP_PDU_IS_REQUEST(pdu)) {
1062 /* Check the M Bit is not set on a GET request RFC 7959 2.2 */
1063 coap_block_b_t block;
1064
1065 if (coap_get_block_b(session, pdu, opt_iter.number, &block)) {
1066 if (block.m) {
1067 size_t used_size = pdu->used_size;
1068 unsigned char buf[4];
1069
1070 coap_log_debug("Option Block2 has invalid set M bit - cleared\n");
1071 block.m = 0;
1072 coap_update_option(pdu, opt_iter.number,
1073 coap_encode_var_safe(buf, sizeof(buf),
1074 ((block.num << 4) |
1075 (block.m << 3) |
1076 block.aszx)),
1077 buf);
1078 if (used_size != pdu->used_size) {
1079 /* Unfortunately need to restart the scan */
1080 coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
1081 last_number = -1;
1082 continue;
1083 }
1084 }
1085 }
1086 }
1087 last_number = opt_iter.number;
1088 }
1089overflow:
1090 return ok;
1091}
1092
1094coap_send_rst(coap_session_t *session, const coap_pdu_t *request) {
1095 coap_mid_t mid;
1096
1098 mid = coap_send_rst_lkd(session, request);
1100 return mid;
1101}
1102
1105 return coap_send_message_type_lkd(session, request, COAP_MESSAGE_RST);
1106}
1107
1109coap_send_ack(coap_session_t *session, const coap_pdu_t *request) {
1110 coap_mid_t mid;
1111
1113 mid = coap_send_ack_lkd(session, request);
1115 return mid;
1116}
1117
1120 coap_pdu_t *response;
1122
1124 if (request && request->type == COAP_MESSAGE_CON &&
1125 COAP_PROTO_NOT_RELIABLE(session->proto)) {
1126 response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->mid, 0);
1127 if (response)
1128 result = coap_send_internal(session, response, NULL);
1129 }
1130 return result;
1131}
1132
1133ssize_t
1135 ssize_t bytes_written = -1;
1136 assert(pdu->hdr_size > 0);
1137
1138 /* Caller handles partial writes */
1139 bytes_written = session->sock.lfunc[COAP_LAYER_SESSION].l_write(session,
1140 pdu->token - pdu->hdr_size,
1141 pdu->used_size + pdu->hdr_size);
1143 return bytes_written;
1144}
1145
1146static ssize_t
1148 ssize_t bytes_written;
1149
1150 if (session->state == COAP_SESSION_STATE_NONE) {
1151#if ! COAP_CLIENT_SUPPORT
1152 return -1;
1153#else /* COAP_CLIENT_SUPPORT */
1154 if (session->type != COAP_SESSION_TYPE_CLIENT)
1155 return -1;
1156#endif /* COAP_CLIENT_SUPPORT */
1157 }
1158
1159 if (pdu->type == COAP_MESSAGE_CON &&
1160 (session->sock.flags & COAP_SOCKET_NOT_EMPTY) &&
1161 coap_is_mcast(&session->addr_info.remote)) {
1162 /* Violates RFC72522 8.1 */
1163 coap_log_err("Multicast requests cannot be Confirmable (RFC7252 8.1)\n");
1164 return -1;
1165 }
1166
1167 if (session->state != COAP_SESSION_STATE_ESTABLISHED ||
1168 (pdu->type == COAP_MESSAGE_CON &&
1169 session->con_active >= COAP_NSTART(session))) {
1170 return coap_session_delay_pdu(session, pdu, node);
1171 }
1172
1173 if ((session->sock.flags & COAP_SOCKET_NOT_EMPTY) &&
1174 (session->sock.flags & COAP_SOCKET_WANT_WRITE))
1175 return coap_session_delay_pdu(session, pdu, node);
1176
1177 bytes_written = coap_session_send_pdu(session, pdu);
1178 if (bytes_written >= 0 && pdu->type == COAP_MESSAGE_CON &&
1180 session->con_active++;
1181
1182 return bytes_written;
1183}
1184
1187 const coap_pdu_t *request,
1188 coap_pdu_code_t code,
1189 coap_opt_filter_t *opts) {
1190 coap_mid_t mid;
1191
1193 mid = coap_send_error_lkd(session, request, code, opts);
1195 return mid;
1196}
1197
1200 const coap_pdu_t *request,
1201 coap_pdu_code_t code,
1202 coap_opt_filter_t *opts) {
1203 coap_pdu_t *response;
1205
1206 assert(request);
1207 assert(session);
1208
1209 response = coap_new_error_response(request, code, opts);
1210 if (response)
1211 result = coap_send_internal(session, response, NULL);
1212
1213 return result;
1214}
1215
1218 coap_pdu_type_t type) {
1219 coap_mid_t mid;
1220
1222 mid = coap_send_message_type_lkd(session, request, type);
1224 return mid;
1225}
1226
1229 coap_pdu_type_t type) {
1230 coap_pdu_t *response;
1232
1234 if (request && COAP_PROTO_NOT_RELIABLE(session->proto)) {
1235 response = coap_pdu_init(type, 0, request->mid, 0);
1236 if (response)
1237 result = coap_send_internal(session, response, NULL);
1238 }
1239 return result;
1240}
1241
1255unsigned int
1256coap_calc_timeout(coap_session_t *session, unsigned char r) {
1257 unsigned int result;
1258
1259 /* The integer 1.0 as a Qx.FRAC_BITS */
1260#define FP1 Q(FRAC_BITS, ((coap_fixed_point_t){1,0}))
1261
1262 /* rounds val up and right shifts by frac positions */
1263#define SHR_FP(val,frac) (((val) + (1 << ((frac) - 1))) >> (frac))
1264
1265 /* Inner term: multiply ACK_RANDOM_FACTOR by Q0.MAX_BITS[r] and
1266 * make the result a rounded Qx.FRAC_BITS */
1267 result = SHR_FP((ACK_RANDOM_FACTOR - FP1) * r, MAX_BITS);
1268
1269 /* Add 1 to the inner term and multiply with ACK_TIMEOUT, then
1270 * make the result a rounded Qx.FRAC_BITS */
1271 result = SHR_FP(((result + FP1) * ACK_TIMEOUT), FRAC_BITS);
1272
1273 /* Multiply with COAP_TICKS_PER_SECOND to yield system ticks
1274 * (yields a Qx.FRAC_BITS) and shift to get an integer */
1275 return SHR_FP((COAP_TICKS_PER_SECOND * result), FRAC_BITS);
1276
1277#undef FP1
1278#undef SHR_FP
1279}
1280
1283 coap_queue_t *node) {
1284 coap_tick_t now;
1285
1286 node->session = coap_session_reference_lkd(session);
1287
1288 /* Set timer for pdu retransmission. If this is the first element in
1289 * the retransmission queue, the base time is set to the current
1290 * time and the retransmission time is node->timeout. If there is
1291 * already an entry in the sendqueue, we must check if this node is
1292 * to be retransmitted earlier. Therefore, node->timeout is first
1293 * normalized to the base time and then inserted into the queue with
1294 * an adjusted relative time.
1295 */
1296 coap_ticks(&now);
1297 if (context->sendqueue == NULL) {
1298 node->t = node->timeout << node->retransmit_cnt;
1299 context->sendqueue_basetime = now;
1300 } else {
1301 /* make node->t relative to context->sendqueue_basetime */
1302 node->t = (now - context->sendqueue_basetime) +
1303 (node->timeout << node->retransmit_cnt);
1304 }
1305 coap_address_copy(&node->remote, &session->addr_info.remote);
1306
1307 coap_insert_node(&context->sendqueue, node);
1308
1309 coap_log_debug("** %s: mid=0x%04x: added to retransmit queue (%ums)\n",
1310 coap_session_str(node->session), node->id,
1311 (unsigned)((node->timeout << node->retransmit_cnt) * 1000 /
1313
1314 coap_update_io_timer(context, node->t);
1315
1316 return node->id;
1317}
1318
1319#if COAP_CLIENT_SUPPORT
1320/*
1321 * Sent out a test PDU for Extended Token
1322 */
1323static coap_mid_t
1324coap_send_test_extended_token(coap_session_t *session) {
1325 coap_pdu_t *pdu;
1327 size_t i;
1328 coap_binary_t *token;
1329 coap_lg_crcv_t *lg_crcv;
1330
1331 coap_log_debug("Testing for Extended Token support\n");
1332 /* https://rfc-editor.org/rfc/rfc8974#section-2.2.2 */
1334 coap_new_message_id_lkd(session),
1336 if (!pdu)
1337 return COAP_INVALID_MID;
1338
1339 token = coap_new_binary(session->max_token_size);
1340 if (token == NULL) {
1342 return COAP_INVALID_MID;
1343 }
1344 for (i = 0; i < session->max_token_size; i++) {
1345 token->s[i] = (uint8_t)(i + 1);
1346 }
1347 coap_add_token(pdu, session->max_token_size, token->s);
1348 coap_delete_binary(token);
1349
1352 pdu->actual_token.length);
1353
1355
1356 session->max_token_checked = COAP_EXT_T_CHECKING; /* Checking out this one */
1357
1358 /* Need to track incase OSCORE / Echo etc. comes back after non-piggy-backed ACK */
1359 lg_crcv = coap_block_new_lg_crcv(session, pdu, NULL);
1360 if (lg_crcv) {
1361 LL_PREPEND(session->lg_crcv, lg_crcv);
1362 }
1363 mid = coap_send_internal(session, pdu, NULL);
1364 if (mid == COAP_INVALID_MID)
1365 return COAP_INVALID_MID;
1366 session->remote_test_mid = mid;
1367 return mid;
1368}
1369#endif /* COAP_CLIENT_SUPPORT */
1370
1371/*
1372 * Return: 0 Something failed
1373 * 1 Success
1374 */
1375int
1377#if COAP_CLIENT_SUPPORT
1378 if (session->type == COAP_SESSION_TYPE_CLIENT && session->doing_first) {
1379 int timeout_ms = 5000;
1380 coap_session_state_t current_state = session->state;
1381
1382 if (session->delay_recursive) {
1383 return 0;
1384 } else {
1385 session->delay_recursive = 1;
1386 }
1387 /*
1388 * Need to wait for first request to get out and response back before
1389 * continuing.. Response handler has to clear doing_first if not an error.
1390 */
1392 while (session->doing_first != 0) {
1393 int result = coap_io_process_lkd(session->context, 1000);
1394
1395 if (result < 0) {
1396 coap_reset_doing_first(session);
1397 session->delay_recursive = 0;
1398 coap_session_release_lkd(session);
1399 return 0;
1400 }
1401
1402 /* coap_io_process_lkd() may have updated session state */
1403 if (session->state == COAP_SESSION_STATE_CSM &&
1404 current_state != COAP_SESSION_STATE_CSM) {
1405 /* Update timeout and restart the clock for CSM timeout */
1406 current_state = COAP_SESSION_STATE_CSM;
1407 timeout_ms = session->context->csm_timeout_ms;
1408 result = 0;
1409 }
1410
1411 if (result < timeout_ms) {
1412 timeout_ms -= result;
1413 } else {
1414 if (session->doing_first == 1) {
1415 /* Timeout failure of some sort with first request */
1416 if (session->state == COAP_SESSION_STATE_CSM) {
1417 coap_log_debug("** %s: timeout waiting for CSM response\n",
1418 coap_session_str(session));
1419 session->csm_not_seen = 1;
1420 } else {
1421 coap_log_debug("** %s: timeout waiting for first response\n",
1422 coap_session_str(session));
1423 }
1424 coap_reset_doing_first(session);
1425 coap_session_connected(session);
1426 }
1427 }
1428 }
1429 session->delay_recursive = 0;
1430 coap_session_release_lkd(session);
1431 }
1432#else /* ! COAP_CLIENT_SUPPORT */
1433 (void)session;
1434#endif /* ! COAP_CLIENT_SUPPORT */
1435 return 1;
1436}
1437
1438/*
1439 * return 0 Invalid
1440 * 1 Valid
1441 */
1442int
1444
1445 /* Check validity of sending code */
1446 switch (COAP_RESPONSE_CLASS(pdu->code)) {
1447 case 0: /* Empty or request */
1448 case 2: /* Success */
1449 case 3: /* Reserved for future use */
1450 case 4: /* Client error */
1451 case 5: /* Server error */
1452 break;
1453 case 7: /* Reliable signalling */
1454 if (COAP_PROTO_RELIABLE(session->proto))
1455 break;
1456 /* Not valid if UDP */
1457 /* Fall through */
1458 case 1: /* Invalid */
1459 case 6: /* Invalid */
1460 default:
1461 return 0;
1462 }
1463 return 1;
1464}
1465
1466#if COAP_CLIENT_SUPPORT
1467/*
1468 * If type is CON and protocol is not reliable, there is no need to set up
1469 * lg_crcv if it can be built up based on sent PDU if there is a
1470 * (Q-)Block2 in the response. However, still need it for Observe, Oscore and
1471 * (Q-)Block1.
1472 */
1473static int
1474coap_check_send_need_lg_crcv(coap_session_t *session, coap_pdu_t *pdu) {
1475 coap_opt_iterator_t opt_iter;
1476
1477 if (!COAP_PDU_IS_REQUEST(pdu))
1478 return 0;
1479
1480 if (
1481#if COAP_OSCORE_SUPPORT
1482 session->oscore_encryption ||
1483#endif /* COAP_OSCORE_SUPPORT */
1484 pdu->type == COAP_MESSAGE_NON ||
1485 COAP_PROTO_RELIABLE(session->proto) ||
1486 coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter) ||
1487#if COAP_Q_BLOCK_SUPPORT
1488 coap_check_option(pdu, COAP_OPTION_Q_BLOCK1, &opt_iter) ||
1489#endif /* COAP_Q_BLOCK_SUPPORT */
1490 coap_check_option(pdu, COAP_OPTION_BLOCK1, &opt_iter)) {
1491 return 1;
1492 }
1493 return 0;
1494}
1495#endif /* COAP_CLIENT_SUPPORT */
1496
1499 coap_mid_t mid;
1500
1502 mid = coap_send_lkd(session, pdu);
1504 return mid;
1505}
1506
1510#if COAP_CLIENT_SUPPORT
1511 coap_lg_crcv_t *lg_crcv = NULL;
1512 coap_opt_iterator_t opt_iter;
1513 coap_block_b_t block;
1514 int observe_action = -1;
1515 int have_block1 = 0;
1516 coap_opt_t *opt;
1517#endif /* COAP_CLIENT_SUPPORT */
1518
1519 assert(pdu);
1520
1522
1523 /* Check validity of sending code */
1524 if (!coap_check_code_class(session, pdu)) {
1525 coap_log_err("coap_send: Invalid PDU code (%d.%02d)\n",
1527 pdu->code & 0x1f);
1528 goto error;
1529 }
1530 pdu->session = session;
1531#if COAP_CLIENT_SUPPORT
1532 if (session->type == COAP_SESSION_TYPE_CLIENT &&
1533 !coap_netif_available(session) && !session->session_failed) {
1534 coap_log_debug("coap_send: Socket closed\n");
1535 goto error;
1536 }
1537
1538 if (session->doing_first) {
1539 LL_APPEND(session->doing_first_pdu, pdu);
1541 coap_log_debug("** %s: mid=0x%04x: queued\n",
1542 coap_session_str(session), pdu->mid);
1543 return pdu->mid;
1544 }
1545
1546 /* Indicate support for Extended Tokens if appropriate */
1547 if (session->max_token_checked == COAP_EXT_T_NOT_CHECKED &&
1549 session->type == COAP_SESSION_TYPE_CLIENT &&
1550 COAP_PDU_IS_REQUEST(pdu)) {
1551 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
1552 /*
1553 * When the pass / fail response for Extended Token is received, this PDU
1554 * will get transmitted.
1555 */
1556 if (coap_send_test_extended_token(session) == COAP_INVALID_MID) {
1557 goto error;
1558 }
1559 }
1560 /*
1561 * For reliable protocols, this will get cleared after CSM exchanged
1562 * in coap_session_connected() where Token size support is indicated in the CSM.
1563 */
1564 session->doing_first = 1;
1565 coap_ticks(&session->doing_first_timeout);
1566 LL_PREPEND(session->doing_first_pdu, pdu);
1567 if (session->proto != COAP_PROTO_UDP) {
1568 /* In case the next handshake / CSM is already in */
1570 }
1571 /*
1572 * Once Extended Token support size is determined, coap_send_lkd(session, pdu)
1573 * will get called again.
1574 */
1576 coap_log_debug("** %s: mid=0x%04x: queued\n",
1577 coap_session_str(session), pdu->mid);
1578 return pdu->mid;
1579 }
1580#if COAP_Q_BLOCK_SUPPORT
1581 /* Indicate support for Q-Block if appropriate */
1582 if (session->block_mode & COAP_BLOCK_TRY_Q_BLOCK &&
1583 session->type == COAP_SESSION_TYPE_CLIENT &&
1584 COAP_PDU_IS_REQUEST(pdu)) {
1585 if (coap_block_test_q_block(session, pdu) == COAP_INVALID_MID) {
1586 goto error;
1587 }
1588 session->doing_first = 1;
1589 coap_ticks(&session->doing_first_timeout);
1590 LL_PREPEND(session->doing_first_pdu, pdu);
1591 if (session->proto != COAP_PROTO_UDP) {
1592 /* In case the next handshake / CSM is already in */
1594 }
1595 /*
1596 * Once Extended Token support size is determined, coap_send_lkd(session, pdu)
1597 * will get called again.
1598 */
1600 coap_log_debug("** %s: mid=0x%04x: queued\n",
1601 coap_session_str(session), pdu->mid);
1602 return pdu->mid;
1603 }
1604#endif /* COAP_Q_BLOCK_SUPPORT */
1605
1606 /*
1607 * Check validity of token length
1608 */
1609 if (COAP_PDU_IS_REQUEST(pdu) &&
1610 pdu->actual_token.length > session->max_token_size) {
1611 coap_log_warn("coap_send: PDU dropped as token too long (%" PRIuS " > %" PRIu32 ")\n",
1612 pdu->actual_token.length, session->max_token_size);
1613 goto error;
1614 }
1615
1616 /* A lot of the reliable code assumes type is CON */
1617 if (COAP_PROTO_RELIABLE(session->proto) && pdu->type != COAP_MESSAGE_CON)
1618 pdu->type = COAP_MESSAGE_CON;
1619
1620#if COAP_OSCORE_SUPPORT
1621 if (session->oscore_encryption) {
1622 if (session->recipient_ctx->initial_state == 1 &&
1623 !session->recipient_ctx->silent_server) {
1624 /*
1625 * Not sure if remote supports OSCORE, or is going to send us a
1626 * "4.01 + ECHO" etc. so need to hold off future coap_send()s until all
1627 * is OK. Continue sending current pdu to test things.
1628 */
1629 session->doing_first = 1;
1630 }
1631 /* Need to convert Proxy-Uri to Proxy-Scheme option if needed */
1633 goto error;
1634 }
1635 }
1636#endif /* COAP_OSCORE_SUPPORT */
1637
1638 if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) {
1639 return coap_send_internal(session, pdu, NULL);
1640 }
1641
1642 if (COAP_PDU_IS_REQUEST(pdu)) {
1643 uint8_t buf[4];
1644
1645 opt = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
1646
1647 if (opt) {
1648 observe_action = coap_decode_var_bytes(coap_opt_value(opt),
1649 coap_opt_length(opt));
1650 }
1651
1652 if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK1, &block) &&
1653 (block.m == 1 || block.bert == 1)) {
1654 have_block1 = 1;
1655 }
1656#if COAP_Q_BLOCK_SUPPORT
1657 if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block) &&
1658 (block.m == 1 || block.bert == 1)) {
1659 if (have_block1) {
1660 coap_log_warn("Block1 and Q-Block1 cannot be in the same request\n");
1662 }
1663 have_block1 = 1;
1664 }
1665#endif /* COAP_Q_BLOCK_SUPPORT */
1666 if (observe_action != COAP_OBSERVE_CANCEL) {
1667 /* Warn about re-use of tokens */
1668 if (session->last_token &&
1669 coap_binary_equal(&pdu->actual_token, session->last_token)) {
1671 char scratch[24];
1672 size_t size;
1673 size_t i;
1674
1675 scratch[0] = '\000';
1676 for (i = 0; i < pdu->actual_token.length; i++) {
1677 size = strlen(scratch);
1678 snprintf(&scratch[size], sizeof(scratch)-size,
1679 "%02x", pdu->actual_token.s[i]);
1680 }
1681 coap_log_debug("Token {%s} reused - see https://rfc-editor.org/rfc/rfc9175.html#section-4.2\n",
1682 scratch);
1683 }
1684 }
1687 pdu->actual_token.length);
1688 } else {
1689 /* observe_action == COAP_OBSERVE_CANCEL */
1690 coap_binary_t tmp;
1691 int ret;
1692
1693 coap_log_debug("coap_send: Using coap_cancel_observe() to do OBSERVE cancellation\n");
1694 /* Unfortunately need to change the ptr type to be r/w */
1695 memcpy(&tmp.s, &pdu->actual_token.s, sizeof(tmp.s));
1696 tmp.length = pdu->actual_token.length;
1697 ret = coap_cancel_observe_lkd(session, &tmp, pdu->type);
1698 if (ret == 1) {
1699 /* Observe Cancel successfully sent */
1701 return ret;
1702 }
1703 /* Some mismatch somewhere - continue to send original packet */
1704 }
1705 if (!coap_check_option(pdu, COAP_OPTION_RTAG, &opt_iter) &&
1706 (session->block_mode & COAP_BLOCK_NO_PREEMPTIVE_RTAG) == 0 &&
1710 coap_encode_var_safe(buf, sizeof(buf),
1711 ++session->tx_rtag),
1712 buf);
1713 } else {
1714 memset(&block, 0, sizeof(block));
1715 }
1716
1717#if COAP_Q_BLOCK_SUPPORT
1718 if (!(session->block_mode & COAP_BLOCK_HAS_Q_BLOCK))
1719#endif /* COAP_Q_BLOCK_SUPPORT */
1720 {
1721 /* Need to check if we need to reset Q-Block to Block */
1722 uint8_t buf[4];
1723
1724 if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2, &block)) {
1727 coap_encode_var_safe(buf, sizeof(buf),
1728 (block.num << 4) | (0 << 3) | block.szx),
1729 buf);
1730 coap_log_debug("Replaced option Q-Block2 with Block2\n");
1731 /* Need to update associated lg_xmit */
1732 coap_lg_xmit_t *lg_xmit;
1733
1734 LL_FOREACH(session->lg_xmit, lg_xmit) {
1735 if (COAP_PDU_IS_REQUEST(lg_xmit->sent_pdu) &&
1736 lg_xmit->b.b1.app_token &&
1737 coap_binary_equal(&pdu->actual_token, lg_xmit->b.b1.app_token)) {
1738 /* Update the skeletal PDU with the block1 option */
1741 coap_encode_var_safe(buf, sizeof(buf),
1742 (block.num << 4) | (0 << 3) | block.szx),
1743 buf);
1744 break;
1745 }
1746 }
1747 }
1748 if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block)) {
1751 coap_encode_var_safe(buf, sizeof(buf),
1752 (block.num << 4) | (block.m << 3) | block.szx),
1753 buf);
1754 coap_log_debug("Replaced option Q-Block1 with Block1\n");
1755 /* Need to update associated lg_xmit */
1756 coap_lg_xmit_t *lg_xmit;
1757
1758 LL_FOREACH(session->lg_xmit, lg_xmit) {
1759 if (COAP_PDU_IS_REQUEST(lg_xmit->sent_pdu) &&
1760 lg_xmit->b.b1.app_token &&
1761 coap_binary_equal(&pdu->actual_token, lg_xmit->b.b1.app_token)) {
1762 /* Update the skeletal PDU with the block1 option */
1765 coap_encode_var_safe(buf, sizeof(buf),
1766 (block.num << 4) |
1767 (block.m << 3) |
1768 block.szx),
1769 buf);
1770 /* Update as this is a Request */
1771 lg_xmit->option = COAP_OPTION_BLOCK1;
1772 break;
1773 }
1774 }
1775 }
1776 }
1777
1778#if COAP_Q_BLOCK_SUPPORT
1779 if (COAP_PDU_IS_REQUEST(pdu) &&
1780 coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2, &block)) {
1781 if (block.num == 0 && block.m == 0) {
1782 uint8_t buf[4];
1783
1784 /* M needs to be set as asking for all the blocks */
1786 coap_encode_var_safe(buf, sizeof(buf),
1787 (0 << 4) | (1 << 3) | block.szx),
1788 buf);
1789 }
1790 }
1791#endif /* COAP_Q_BLOCK_SUPPORT */
1792
1793 /*
1794 * If type is CON and protocol is not reliable, there is no need to set up
1795 * lg_crcv here as it can be built up based on sent PDU if there is a
1796 * (Q-)Block2 in the response. However, still need it for Observe, Oscore and
1797 * (Q-)Block1.
1798 */
1799 if (coap_check_send_need_lg_crcv(session, pdu)) {
1800 coap_lg_xmit_t *lg_xmit = NULL;
1801
1802 if (!session->lg_xmit && have_block1) {
1803 coap_log_debug("PDU presented by app\n");
1805 }
1806 /* See if this token is already in use for large body responses */
1807 LL_FOREACH(session->lg_crcv, lg_crcv) {
1808 if (coap_binary_equal(&pdu->actual_token, lg_crcv->app_token)) {
1809 /* Need to terminate and clean up previous response setup */
1810 LL_DELETE(session->lg_crcv, lg_crcv);
1811 coap_block_delete_lg_crcv(session, lg_crcv);
1812 break;
1813 }
1814 }
1815
1816 if (have_block1 && session->lg_xmit) {
1817 LL_FOREACH(session->lg_xmit, lg_xmit) {
1818 if (COAP_PDU_IS_REQUEST(lg_xmit->sent_pdu) &&
1819 lg_xmit->b.b1.app_token &&
1820 coap_binary_equal(&pdu->actual_token, lg_xmit->b.b1.app_token)) {
1821 break;
1822 }
1823 }
1824 }
1825 lg_crcv = coap_block_new_lg_crcv(session, pdu, lg_xmit);
1826 if (lg_crcv == NULL) {
1827 goto error;
1828 }
1829 if (lg_xmit) {
1830 /* Need to update the token as set up in the session->lg_xmit */
1831 lg_xmit->b.b1.state_token = lg_crcv->state_token;
1832 }
1833 }
1834 if (session->sock.flags & COAP_SOCKET_MULTICAST)
1835 coap_address_copy(&session->addr_info.remote, &session->sock.mcast_addr);
1836
1837#if COAP_Q_BLOCK_SUPPORT
1838 /* See if large xmit using Q-Block1 (but not testing Q-Block1) */
1839 if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block)) {
1840 mid = coap_send_q_block1(session, block, pdu, COAP_SEND_INC_PDU);
1841 } else
1842#endif /* COAP_Q_BLOCK_SUPPORT */
1843 mid = coap_send_internal(session, pdu, NULL);
1844#else /* !COAP_CLIENT_SUPPORT */
1845 mid = coap_send_internal(session, pdu, NULL);
1846#endif /* !COAP_CLIENT_SUPPORT */
1847#if COAP_CLIENT_SUPPORT
1848 if (lg_crcv) {
1849 if (mid != COAP_INVALID_MID) {
1850 LL_PREPEND(session->lg_crcv, lg_crcv);
1851 } else {
1852 coap_block_delete_lg_crcv(session, lg_crcv);
1853 }
1854 }
1855#endif /* COAP_CLIENT_SUPPORT */
1856 return mid;
1857
1858error:
1860 return COAP_INVALID_MID;
1861}
1862
1863#if COAP_SERVER_SUPPORT
1864static int
1865coap_pdu_cksum(const coap_pdu_t *pdu, coap_digest_t *digest_buffer) {
1866 coap_digest_ctx_t *digest_ctx = coap_digest_setup();
1867
1868 if (!digest_ctx || !pdu) {
1869 goto fail;
1870 }
1871 if (pdu->used_size && pdu->token) {
1872 if (!coap_digest_update(digest_ctx, pdu->token, pdu->used_size)) {
1873 goto fail;
1874 }
1875 }
1876 if (!coap_digest_update(digest_ctx, (const uint8_t *)&pdu->type, sizeof(pdu->type))) {
1877 goto fail;
1878 }
1879 if (!coap_digest_update(digest_ctx, (const uint8_t *)&pdu->code, sizeof(pdu->code))) {
1880 goto fail;
1881 }
1882 if (!coap_digest_update(digest_ctx, (const uint8_t *)&pdu->mid, sizeof(pdu->mid))) {
1883 goto fail;
1884 }
1885 if (!coap_digest_final(digest_ctx, digest_buffer))
1886 return 0;
1887
1888 return 1;
1889
1890fail:
1891 coap_digest_free(digest_ctx);
1892 return 0;
1893}
1894#endif /* COAP_SERVER_SUPPORT */
1895
1896static int
1898 char addr_str[INET6_ADDRSTRLEN + 8 + 1];
1899 coap_opt_t *opt;
1900 coap_opt_iterator_t opt_iter;
1901 size_t hop_limit;
1902
1903 addr_str[sizeof(addr_str)-1] = '\000';
1904 if (coap_print_addr(&session->addr_info.local, (uint8_t *)addr_str,
1905 sizeof(addr_str) - 1)) {
1906 char *cp;
1907 size_t len;
1908
1909 if (addr_str[0] == '[') {
1910 cp = strchr(addr_str, ']');
1911 if (cp)
1912 *cp = '\000';
1913 if (memcmp(&addr_str[1], "::ffff:", 7) == 0) {
1914 /* IPv4 embedded into IPv6 */
1915 cp = &addr_str[8];
1916 } else {
1917 cp = &addr_str[1];
1918 }
1919 } else {
1920 cp = strchr(addr_str, ':');
1921 if (cp)
1922 *cp = '\000';
1923 cp = addr_str;
1924 }
1925 len = strlen(cp);
1926
1927 /* See if Hop Limit option is being used in return path */
1928 opt = coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter);
1929 if (opt) {
1930 uint8_t buf[4];
1931
1932 hop_limit =
1934 if (hop_limit == 1) {
1935 coap_log_warn("Proxy loop detected '%s'\n",
1936 (char *)pdu->data);
1939 } else if (hop_limit < 1 || hop_limit > 255) {
1940 /* Something is bad - need to drop this pdu (TODO or delete option) */
1941 coap_log_warn("Proxy return has bad hop limit count '%" PRIuS "'\n",
1942 hop_limit);
1944 return 0;
1945 }
1946 hop_limit--;
1948 coap_encode_var_safe8(buf, sizeof(buf), hop_limit),
1949 buf);
1950 }
1951
1952 /* Need to check that we are not seeing this proxy in the return loop */
1953 if (pdu->data && opt == NULL) {
1954 char *a_match;
1955 size_t data_len;
1956
1957 if (pdu->used_size + 1 > pdu->max_size) {
1958 /* No space */
1960 return 0;
1961 }
1962 if (!coap_pdu_resize(pdu, pdu->used_size + 1)) {
1963 /* Internal error */
1965 return 0;
1966 }
1967 data_len = pdu->used_size - (pdu->data - pdu->token);
1968 pdu->data[data_len] = '\000';
1969 a_match = strstr((char *)pdu->data, cp);
1970 if (a_match && (a_match == (char *)pdu->data || a_match[-1] == ' ') &&
1971 ((size_t)(a_match - (char *)pdu->data + len) == data_len ||
1972 a_match[len] == ' ')) {
1973 coap_log_warn("Proxy loop detected '%s'\n",
1974 (char *)pdu->data);
1976 return 0;
1977 }
1978 }
1979 if (pdu->used_size + len + 1 <= pdu->max_size) {
1980 size_t old_size = pdu->used_size;
1981 if (coap_pdu_resize(pdu, pdu->used_size + len + 1)) {
1982 if (pdu->data == NULL) {
1983 /*
1984 * Set Hop Limit to max for return path. If this libcoap is in
1985 * a proxy loop path, it will always decrement hop limit in code
1986 * above and hence timeout / drop the response as appropriate
1987 */
1988 hop_limit = 255;
1990 (uint8_t *)&hop_limit);
1991 coap_add_data(pdu, len, (uint8_t *)cp);
1992 } else {
1993 /* prepend with space separator, leaving hop limit "as is" */
1994 memmove(pdu->data + len + 1, pdu->data,
1995 old_size - (pdu->data - pdu->token));
1996 memcpy(pdu->data, cp, len);
1997 pdu->data[len] = ' ';
1998 pdu->used_size += len + 1;
1999 }
2000 }
2001 }
2002 }
2003 return 1;
2004}
2005
2008 uint8_t r;
2009 ssize_t bytes_written;
2010
2011#if ! COAP_SERVER_SUPPORT
2012 (void)request_pdu;
2013#endif /* COAP_SERVER_SUPPORT */
2014 pdu->session = session;
2015#if COAP_CLIENT_SUPPORT
2016 if (session->session_failed) {
2017 coap_session_reconnect(session);
2018 if (session->session_failed)
2019 goto error;
2020 }
2021#endif /* COAP_CLIENT_SUPPORT */
2022 if (pdu->type == COAP_MESSAGE_NON && session->rl_ticks_per_packet) {
2023 coap_tick_t now;
2024
2025 if (!session->is_rate_limiting) {
2026 coap_ticks(&now);
2027 while (1) {
2028 uint32_t timeout_ms;
2029
2030 if (now - session->last_tx >= session->rl_ticks_per_packet) {
2031 break;
2032 }
2033 timeout_ms = (uint32_t)((session->rl_ticks_per_packet - (now - session->last_tx)) /
2034 (COAP_TICKS_PER_SECOND / 1000));
2035
2036 if (timeout_ms == 0) {
2037 timeout_ms = COAP_IO_NO_WAIT;
2038 }
2039 session->is_rate_limiting = 1;
2040 coap_io_process_lkd(session->context, timeout_ms);
2041 session->is_rate_limiting = 0;
2042 coap_ticks(&now);
2043 }
2044 session->last_tx = now;
2045 }
2046 }
2047#if COAP_PROXY_SUPPORT
2048 if (session->server_list) {
2049 /* Local session wanting to use proxy logic */
2050 return coap_proxy_local_write(session, pdu);
2051 }
2052#endif /* COAP_PROXY_SUPPORT */
2053 if (pdu->code == COAP_RESPONSE_CODE(508)) {
2054 /*
2055 * Need to prepend our IP identifier to the data as per
2056 * https://rfc-editor.org/rfc/rfc8768.html#section-4
2057 */
2058 if (!prepend_508_ip(session, pdu)) {
2060 }
2061 }
2062
2063 if (session->echo) {
2064 if (!coap_insert_option(pdu, COAP_OPTION_ECHO, session->echo->length,
2065 session->echo->s))
2066 goto error;
2067 coap_delete_bin_const(session->echo);
2068 session->echo = NULL;
2069 }
2070#if COAP_OSCORE_SUPPORT
2071 if (session->oscore_encryption) {
2072 /* Need to convert Proxy-Uri to Proxy-Scheme option if needed */
2074 goto error;
2075 }
2076#endif /* COAP_OSCORE_SUPPORT */
2077
2078 if (!coap_pdu_encode_header(pdu, session->proto)) {
2079 goto error;
2080 }
2081
2082#if !COAP_DISABLE_TCP
2083 if (COAP_PROTO_RELIABLE(session->proto) &&
2085 coap_opt_iterator_t opt_iter;
2086
2087 if (!session->csm_block_supported) {
2088 /*
2089 * Need to check that this instance is not sending any block options as
2090 * the remote end via CSM has not informed us that there is support
2091 * https://rfc-editor.org/rfc/rfc8323#section-5.3.2
2092 * This includes potential BERT blocks.
2093 */
2094 if (coap_check_option(pdu, COAP_OPTION_BLOCK1, &opt_iter) != NULL) {
2095 coap_log_debug("Remote end did not indicate CSM support for Block1 enabled\n");
2096 }
2097 if (coap_check_option(pdu, COAP_OPTION_BLOCK2, &opt_iter) != NULL) {
2098 coap_log_debug("Remote end did not indicate CSM support for Block2 enabled\n");
2099 }
2100 } else if (!session->csm_bert_rem_support) {
2101 coap_opt_t *opt;
2102
2103 opt = coap_check_option(pdu, COAP_OPTION_BLOCK1, &opt_iter);
2104 if (opt && COAP_OPT_BLOCK_SZX(opt) == 7) {
2105 coap_log_debug("Remote end did not indicate CSM support for BERT Block1\n");
2106 }
2107 opt = coap_check_option(pdu, COAP_OPTION_BLOCK2, &opt_iter);
2108 if (opt && COAP_OPT_BLOCK_SZX(opt) == 7) {
2109 coap_log_debug("Remote end did not indicate CSM support for BERT Block2\n");
2110 }
2111 }
2112 }
2113#endif /* !COAP_DISABLE_TCP */
2114
2115#if COAP_OSCORE_SUPPORT
2116 if (session->oscore_encryption &&
2117 pdu->type != COAP_MESSAGE_RST &&
2118 !(pdu->type == COAP_MESSAGE_ACK && pdu->code == COAP_EMPTY_CODE) &&
2119 !(COAP_PROTO_RELIABLE(session->proto) && pdu->code == COAP_SIGNALING_CODE_PONG)) {
2120 /* Refactor PDU as appropriate RFC8613 */
2121 coap_pdu_t *osc_pdu = coap_oscore_new_pdu_encrypted_lkd(session, pdu, NULL, 0);
2122
2123 if (osc_pdu == NULL) {
2124 coap_log_warn("OSCORE: PDU could not be encrypted\n");
2127 goto error;
2128 }
2129 bytes_written = coap_send_pdu(session, osc_pdu, NULL);
2131 pdu = osc_pdu;
2132 } else
2133#endif /* COAP_OSCORE_SUPPORT */
2134 bytes_written = coap_send_pdu(session, pdu, NULL);
2135
2136#if COAP_SERVER_SUPPORT
2137 if ((session->block_mode & COAP_BLOCK_CACHE_RESPONSE) &&
2138 session->cached_pdu != pdu &&
2139 request_pdu && COAP_PROTO_NOT_RELIABLE(session->proto) &&
2140 COAP_PDU_IS_REQUEST(request_pdu) &&
2141 COAP_PDU_IS_RESPONSE(pdu) && pdu->type == COAP_MESSAGE_ACK) {
2142 coap_delete_pdu_lkd(session->cached_pdu);
2143 session->cached_pdu = pdu;
2144 coap_pdu_reference_lkd(session->cached_pdu);
2145 coap_pdu_cksum(request_pdu, &session->cached_pdu_cksum);
2146 }
2147#endif /* COAP_SERVER_SUPPORT */
2148
2149 if (bytes_written == COAP_PDU_DELAYED) {
2150 /* do not free pdu as it is stored with session for later use */
2151 return pdu->mid;
2152 }
2153 if (bytes_written < 0) {
2155 goto error;
2156 }
2157
2158#if !COAP_DISABLE_TCP
2159 if (COAP_PROTO_RELIABLE(session->proto) &&
2160 (size_t)bytes_written < pdu->used_size + pdu->hdr_size) {
2161 if (coap_session_delay_pdu(session, pdu, NULL) == COAP_PDU_DELAYED) {
2162 session->partial_write = (size_t)bytes_written;
2163 /* do not free pdu as it is stored with session for later use */
2164 return pdu->mid;
2165 } else {
2166 goto error;
2167 }
2168 }
2169#endif /* !COAP_DISABLE_TCP */
2170
2171 if (pdu->type != COAP_MESSAGE_CON
2172 || COAP_PROTO_RELIABLE(session->proto)) {
2173 coap_mid_t id = pdu->mid;
2175 return id;
2176 }
2177
2178 coap_queue_t *node = coap_new_node();
2179 if (!node) {
2180 coap_log_debug("coap_wait_ack: insufficient memory\n");
2181 goto error;
2182 }
2183
2184 node->id = pdu->mid;
2185 node->pdu = pdu;
2186 coap_prng_lkd(&r, sizeof(r));
2187 /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
2188 node->timeout = coap_calc_timeout(session, r);
2189 return coap_wait_ack(session->context, session, node);
2190error:
2192 return COAP_INVALID_MID;
2193}
2194
2195static int send_recv_terminate = 0;
2196
2197void
2201
2202COAP_API int
2204 coap_pdu_t **response_pdu, uint32_t timeout_ms) {
2205 int ret;
2206
2207 coap_lock_lock(return 0);
2208 ret = coap_send_recv_lkd(session, request_pdu, response_pdu, timeout_ms);
2210 return ret;
2211}
2212
2213/*
2214 * Return 0 or +ve Time in function in ms after successful transfer
2215 * -1 Invalid timeout parameter
2216 * -2 Failed to transmit PDU
2217 * -3 Nack or Event handler invoked, cancelling request
2218 * -4 coap_io_process returned error (fail to re-lock or select())
2219 * -5 Response not received in the given time
2220 * -6 Terminated by user
2221 * -7 Client mode code not enabled
2222 */
2223int
2225 coap_pdu_t **response_pdu, uint32_t timeout_ms) {
2226#if COAP_CLIENT_SUPPORT
2228 uint32_t rem_timeout = timeout_ms;
2229 uint32_t block_mode = session->block_mode;
2230 int ret = 0;
2231 coap_tick_t now;
2232 coap_tick_t start;
2233 coap_tick_t ticks_so_far;
2234 uint32_t time_so_far_ms;
2235
2236 coap_ticks(&start);
2237 assert(request_pdu);
2238
2240
2241 session->resp_pdu = NULL;
2242 session->req_token = coap_new_bin_const(request_pdu->actual_token.s,
2243 request_pdu->actual_token.length);
2244
2245 if (timeout_ms == COAP_IO_NO_WAIT || timeout_ms == COAP_IO_WAIT) {
2246 ret = -1;
2247 goto fail;
2248 }
2249 if (session->state == COAP_SESSION_STATE_NONE) {
2250 ret = -3;
2251 goto fail;
2252 }
2253
2255 if (coap_is_mcast(&session->addr_info.remote))
2256 block_mode = session->block_mode;
2257
2258 session->doing_send_recv = 1;
2259 /* So the user needs to delete the PDU */
2260 coap_pdu_reference_lkd(request_pdu);
2261 mid = coap_send_lkd(session, request_pdu);
2262 if (mid == COAP_INVALID_MID) {
2263 if (!session->doing_send_recv)
2264 ret = -3;
2265 else
2266 ret = -2;
2267 goto fail;
2268 }
2269
2270 /* Wait for the response to come in */
2271 while (rem_timeout > 0 && session->doing_send_recv && !session->resp_pdu) {
2272 if (send_recv_terminate) {
2273 ret = -6;
2274 goto fail;
2275 }
2276 ret = coap_io_process_lkd(session->context, rem_timeout);
2277 if (ret < 0) {
2278 ret = -4;
2279 goto fail;
2280 }
2281 /* timeout_ms is for timeout between specific request and response */
2282 coap_ticks(&now);
2283 ticks_so_far = now - session->last_rx_tx;
2284 time_so_far_ms = (uint32_t)((ticks_so_far * 1000) / COAP_TICKS_PER_SECOND);
2285 if (time_so_far_ms >= timeout_ms) {
2286 rem_timeout = 0;
2287 } else {
2288 rem_timeout = timeout_ms - time_so_far_ms;
2289 }
2290 if (session->state != COAP_SESSION_STATE_ESTABLISHED) {
2291 /* To pick up on (D)TLS setup issues */
2292 coap_ticks(&now);
2293 ticks_so_far = now - start;
2294 time_so_far_ms = (uint32_t)((ticks_so_far * 1000) / COAP_TICKS_PER_SECOND);
2295 if (time_so_far_ms >= timeout_ms) {
2296 rem_timeout = 0;
2297 } else {
2298 rem_timeout = timeout_ms - time_so_far_ms;
2299 }
2300 }
2301 }
2302
2303 if (rem_timeout) {
2304 coap_ticks(&now);
2305 ticks_so_far = now - start;
2306 time_so_far_ms = (uint32_t)((ticks_so_far * 1000) / COAP_TICKS_PER_SECOND);
2307 ret = time_so_far_ms;
2308 /* Give PDU to user who will be calling coap_delete_pdu() */
2309 *response_pdu = session->resp_pdu;
2310 session->resp_pdu = NULL;
2311 if (*response_pdu == NULL) {
2312 ret = -3;
2313 }
2314 } else {
2315 /* If there is a resp_pdu, it will get cleared below */
2316 ret = -5;
2317 }
2318
2319fail:
2320 session->block_mode = block_mode;
2321 session->doing_send_recv = 0;
2322 /* delete referenced copy */
2323 coap_delete_pdu_lkd(session->resp_pdu);
2324 session->resp_pdu = NULL;
2325 coap_delete_bin_const(session->req_token);
2326 session->req_token = NULL;
2327 return ret;
2328
2329#else /* !COAP_CLIENT_SUPPORT */
2330
2331 (void)session;
2332 (void)timeout_ms;
2333 (void)request_pdu;
2334 coap_log_warn("coap_send_recv: Client mode not supported\n");
2335 *response_pdu = NULL;
2336 return -7;
2337
2338#endif /* ! COAP_CLIENT_SUPPORT */
2339}
2340
2343 if (!context || !node || !node->session)
2344 return COAP_INVALID_MID;
2345
2346#if COAP_CLIENT_SUPPORT
2347 if (node->session->session_failed) {
2348 /* Force failure */
2349 node->retransmit_cnt = (unsigned char)node->session->max_retransmit;
2350 }
2351#endif /* COAP_CLIENT_SUPPORT */
2352
2353 /* re-initialize timeout when maximum number of retransmissions are not reached yet */
2354 if (node->retransmit_cnt < node->session->max_retransmit) {
2355 ssize_t bytes_written;
2356 coap_tick_t now;
2357 coap_tick_t next_delay;
2358 coap_address_t remote;
2359
2360 node->retransmit_cnt++;
2362
2363 next_delay = (coap_tick_t)node->timeout << node->retransmit_cnt;
2364 if (context->ping_timeout &&
2365 context->ping_timeout * COAP_TICKS_PER_SECOND < next_delay) {
2366 uint8_t byte;
2367
2368 coap_prng_lkd(&byte, sizeof(byte));
2369 /* Don't exceed the ping timeout value */
2370 next_delay = context->ping_timeout * COAP_TICKS_PER_SECOND - 255 + byte;
2371 }
2372
2373 coap_ticks(&now);
2374 if (context->sendqueue == NULL) {
2375 node->t = next_delay;
2376 context->sendqueue_basetime = now;
2377 } else {
2378 /* make node->t relative to context->sendqueue_basetime */
2379 node->t = (now - context->sendqueue_basetime) + next_delay;
2380 }
2381 coap_insert_node(&context->sendqueue, node);
2382 coap_address_copy(&remote, &node->session->addr_info.remote);
2384
2385 if (node->is_mcast) {
2386 coap_log_debug("** %s: mid=0x%04x: mcast delayed transmission\n",
2387 coap_session_str(node->session), node->id);
2388 } else {
2389 coap_log_debug("** %s: mid=0x%04x: retransmission #%d (next %ums)\n",
2390 coap_session_str(node->session), node->id,
2391 node->retransmit_cnt,
2392 (unsigned)(next_delay * 1000 / COAP_TICKS_PER_SECOND));
2393 }
2394
2395 if (node->session->con_active)
2396 node->session->con_active--;
2397 bytes_written = coap_send_pdu(node->session, node->pdu, node);
2398
2399 if (bytes_written == COAP_PDU_DELAYED) {
2400 /* PDU was not retransmitted immediately because a new handshake is
2401 in progress. node was moved to the send queue of the session. */
2402 return node->id;
2403 }
2404
2405 coap_address_copy(&node->session->addr_info.remote, &remote);
2406 if (node->is_mcast) {
2409 return COAP_INVALID_MID;
2410 }
2411
2412 if (bytes_written < 0)
2413 return (int)bytes_written;
2414
2415 return node->id;
2416 }
2417
2418#if COAP_CLIENT_SUPPORT
2419 if (node->session->session_failed) {
2420 coap_log_info("** %s: mid=0x%04x: deleted due to reconnection issue\n",
2421 coap_session_str(node->session), node->id);
2422 } else {
2423#endif /* COAP_CLIENT_SUPPORT */
2424 /* no more retransmissions, remove node from system */
2425 coap_log_warn("** %s: mid=0x%04x: give up after %d attempts\n",
2426 coap_session_str(node->session), node->id, node->retransmit_cnt);
2427#if COAP_CLIENT_SUPPORT
2428 }
2429#endif /* COAP_CLIENT_SUPPORT */
2430
2431#if COAP_SERVER_SUPPORT
2432 /* Check if subscriptions exist that should be canceled after
2433 COAP_OBS_MAX_FAIL */
2434 if (COAP_RESPONSE_CLASS(node->pdu->code) >= 2 &&
2435 (node->session->ref_subscriptions || node->session->ref_proxy_subs)) {
2436 if (context->ping_timeout) {
2439 return COAP_INVALID_MID;
2440 } else {
2441 if (node->session->ref_subscriptions)
2442 coap_handle_failed_notify(context, node->session, &node->pdu->actual_token);
2443#if COAP_PROXY_SUPPORT
2444 /* Need to check is there is a proxy subscription active and delete it */
2445 if (node->session->ref_proxy_subs)
2446 coap_delete_proxy_subscriber(node->session, &node->pdu->actual_token,
2447 0, COAP_PROXY_SUBS_TOKEN);
2448#endif /* COAP_PROXY_SUPPORT */
2449 }
2450 }
2451#endif /* COAP_SERVER_SUPPORT */
2452 if (node->session->con_active) {
2453 node->session->con_active--;
2455 /*
2456 * As there may be another CON in a different queue entry on the same
2457 * session that needs to be immediately released,
2458 * coap_session_connected() is called.
2459 * However, there is the possibility coap_wait_ack() may be called for
2460 * this node (queue) and re-added to context->sendqueue.
2461 * coap_delete_node_lkd(node) called shortly will handle this and
2462 * remove it.
2463 */
2465 }
2466 }
2467
2468 if (node->pdu->type == COAP_MESSAGE_CON) {
2470 }
2471#if COAP_CLIENT_SUPPORT
2472 node->session->doing_send_recv = 0;
2473#endif /* COAP_CLIENT_SUPPORT */
2474 /* And finally delete the node */
2476 return COAP_INVALID_MID;
2477}
2478
2479static int
2481 uint8_t *data;
2482 size_t data_len;
2483 int result = -1;
2484
2485 coap_packet_get_memmapped(packet, &data, &data_len);
2486 if (session->proto == COAP_PROTO_DTLS) {
2487#if COAP_SERVER_SUPPORT
2488 if (session->type == COAP_SESSION_TYPE_HELLO)
2489 result = coap_dtls_hello(session, data, data_len);
2490 else
2491#endif /* COAP_SERVER_SUPPORT */
2492 if (session->tls)
2493 result = coap_dtls_receive(session, data, data_len);
2494 } else if (session->proto == COAP_PROTO_UDP) {
2495 result = coap_handle_dgram(ctx, session, data, data_len);
2496 }
2497 return result;
2498}
2499
2500#if COAP_CLIENT_SUPPORT
2501void
2503#if COAP_DISABLE_TCP
2504 (void)now;
2505
2507#else /* !COAP_DISABLE_TCP */
2508 if (coap_netif_strm_connect2(session)) {
2509 session->last_rx_tx = now;
2511 session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session);
2512 } else {
2515 }
2516#endif /* !COAP_DISABLE_TCP */
2517}
2518#endif /* COAP_CLIENT_SUPPORT */
2519
2520static void
2522 (void)ctx;
2523 assert(session->sock.flags & COAP_SOCKET_CONNECTED);
2524
2525 while (session->delayqueue) {
2526 ssize_t bytes_written;
2527 coap_queue_t *q = session->delayqueue;
2528
2529 coap_address_copy(&session->addr_info.remote, &q->remote);
2530 coap_log_debug("** %s: mid=0x%04x: transmitted after delay (1)\n",
2531 coap_session_str(session), (int)q->pdu->mid);
2532 assert(session->partial_write < q->pdu->used_size + q->pdu->hdr_size);
2533 bytes_written = session->sock.lfunc[COAP_LAYER_SESSION].l_write(session,
2534 q->pdu->token - q->pdu->hdr_size + session->partial_write,
2535 q->pdu->used_size + q->pdu->hdr_size - session->partial_write);
2536 if (bytes_written > 0)
2537 session->last_rx_tx = now;
2538 if (bytes_written <= 0 ||
2539 (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size - session->partial_write) {
2540 if (bytes_written > 0)
2541 session->partial_write += (size_t)bytes_written;
2542 break;
2543 }
2544 session->delayqueue = q->next;
2545 session->partial_write = 0;
2547 }
2548}
2549
2550void
2552#if COAP_CONSTRAINED_STACK
2553 /* payload and packet can be protected by global_lock if needed */
2554 static unsigned char payload[COAP_RXBUFFER_SIZE];
2555 static coap_packet_t s_packet;
2556#else /* ! COAP_CONSTRAINED_STACK */
2557 unsigned char payload[COAP_RXBUFFER_SIZE];
2558 coap_packet_t s_packet;
2559#endif /* ! COAP_CONSTRAINED_STACK */
2560 coap_packet_t *packet = &s_packet;
2561
2563
2564 packet->length = sizeof(payload);
2565 packet->payload = payload;
2566
2567 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
2568 ssize_t bytes_read;
2569 coap_address_t remote;
2570
2571 coap_address_copy(&remote, &session->addr_info.remote);
2572 memcpy(&packet->addr_info, &session->addr_info, sizeof(packet->addr_info));
2573 bytes_read = coap_netif_dgrm_read(session, packet);
2574
2575 if (bytes_read < 0) {
2576 if (bytes_read == -2) {
2577 coap_address_copy(&session->addr_info.remote, &remote);
2578 /* Reset the session back to startup defaults */
2580 }
2581 } else if (bytes_read > 0) {
2582 session->last_rx_tx = now;
2583#if COAP_CLIENT_SUPPORT
2584 if (session->session_failed) {
2585 session->session_failed = 0;
2587 }
2588#endif /* COAP_CLIENT_SUPPORT */
2589 /* coap_netif_dgrm_read() updates session->addr_info from packet->addr_info */
2590 coap_handle_dgram_for_proto(ctx, session, packet);
2591 } else {
2592 coap_address_copy(&session->addr_info.remote, &remote);
2593 }
2594#if !COAP_DISABLE_TCP
2595 } else if (session->proto == COAP_PROTO_WS ||
2596 session->proto == COAP_PROTO_WSS) {
2597 ssize_t bytes_read = 0;
2598
2599 /* WebSocket layer passes us the whole packet */
2600 bytes_read = session->sock.lfunc[COAP_LAYER_SESSION].l_read(session,
2601 packet->payload,
2602 packet->length);
2603 if (bytes_read < 0) {
2605 } else if (bytes_read > 2) {
2606 coap_pdu_t *pdu;
2607
2608 session->last_rx_tx = now;
2609 /* Need max space incase PDU is updated with updated token etc. */
2610 pdu = coap_pdu_init(0, 0, 0, coap_session_max_pdu_rcv_size(session));
2611 if (!pdu) {
2612 return;
2613 }
2614
2615 if (!coap_pdu_parse(session->proto, packet->payload, bytes_read, pdu)) {
2617 coap_log_warn("discard malformed PDU\n");
2619 return;
2620 }
2621
2622 coap_dispatch(ctx, session, pdu);
2624 return;
2625 }
2626 } else {
2627 ssize_t bytes_read = 0;
2628 const uint8_t *p;
2629 int retry;
2630
2631 do {
2632 bytes_read = session->sock.lfunc[COAP_LAYER_SESSION].l_read(session,
2633 packet->payload,
2634 packet->length);
2635 if (bytes_read > 0) {
2636 session->last_rx_tx = now;
2637 }
2638 p = packet->payload;
2639 retry = bytes_read == (ssize_t)packet->length;
2640 while (bytes_read > 0) {
2641 if (session->partial_pdu) {
2642 size_t len = session->partial_pdu->used_size
2643 + session->partial_pdu->hdr_size
2644 - session->partial_read;
2645 size_t n = min(len, (size_t)bytes_read);
2646 memcpy(session->partial_pdu->token - session->partial_pdu->hdr_size
2647 + session->partial_read, p, n);
2648 p += n;
2649 bytes_read -= n;
2650 if (n == len) {
2651 coap_opt_filter_t error_opts;
2652 coap_pdu_t *pdu = session->partial_pdu;
2653
2654 session->partial_pdu = NULL;
2655 session->partial_read = 0;
2656
2657 coap_option_filter_clear(&error_opts);
2658 if (coap_pdu_parse_header(pdu, session->proto)
2659 && coap_pdu_parse_opt(pdu, &error_opts)) {
2660 coap_dispatch(ctx, session, pdu);
2661 } else if (error_opts.mask) {
2662 coap_pdu_t *response =
2664 COAP_RESPONSE_CODE(402), &error_opts);
2665 if (!response) {
2666 coap_log_warn("coap_read_session: cannot create error response\n");
2667 } else {
2668 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
2669 coap_log_warn("coap_read_session: error sending response\n");
2670 }
2671 }
2673 } else {
2674 session->partial_read += n;
2675 }
2676 } else if (session->partial_read > 0) {
2677 size_t hdr_size = coap_pdu_parse_header_size(session->proto,
2678 session->read_header);
2679 size_t tkl = session->read_header[0] & 0x0f;
2680 size_t tok_ext_bytes = tkl == COAP_TOKEN_EXT_1B_TKL ? 1 :
2681 tkl == COAP_TOKEN_EXT_2B_TKL ? 2 : 0;
2682 size_t len = hdr_size + tok_ext_bytes - session->partial_read;
2683 size_t n = min(len, (size_t)bytes_read);
2684 memcpy(session->read_header + session->partial_read, p, n);
2685 p += n;
2686 bytes_read -= n;
2687 if (n == len) {
2688 /* Header now all in */
2689 size_t size = coap_pdu_parse_size(session->proto, session->read_header,
2690 hdr_size + tok_ext_bytes);
2691 if (size > COAP_DEFAULT_MAX_PDU_RX_SIZE) {
2692 coap_log_warn("** %s: incoming PDU length too large (%" PRIuS " > %lu)\n",
2693 coap_session_str(session),
2695 bytes_read = -1;
2696 break;
2697 }
2698 /* Need max space incase PDU is updated with updated token etc. */
2699 session->partial_pdu = coap_pdu_init(0, 0, 0,
2701 if (session->partial_pdu == NULL) {
2702 bytes_read = -1;
2703 break;
2704 }
2705 if (session->partial_pdu->alloc_size < size && !coap_pdu_resize(session->partial_pdu, size)) {
2706 bytes_read = -1;
2707 break;
2708 }
2709 session->partial_pdu->hdr_size = (uint8_t)hdr_size;
2710 session->partial_pdu->used_size = size;
2711 memcpy(session->partial_pdu->token - hdr_size, session->read_header, hdr_size + tok_ext_bytes);
2712 session->partial_read = hdr_size + tok_ext_bytes;
2713 if (size == 0) {
2714 coap_pdu_t *pdu = session->partial_pdu;
2715
2716 session->partial_pdu = NULL;
2717 session->partial_read = 0;
2718 if (coap_pdu_parse_header(pdu, session->proto)) {
2719 coap_dispatch(ctx, session, pdu);
2720 }
2722 }
2723 } else {
2724 /* More of the header to go */
2725 session->partial_read += n;
2726 }
2727 } else {
2728 /* Get in first byte of the header */
2729 session->read_header[0] = *p++;
2730 bytes_read -= 1;
2731 if (!coap_pdu_parse_header_size(session->proto,
2732 session->read_header)) {
2733 bytes_read = -1;
2734 break;
2735 }
2736 session->partial_read = 1;
2737 }
2738 }
2739 } while (bytes_read == 0 && retry);
2740 if (bytes_read < 0)
2742#endif /* !COAP_DISABLE_TCP */
2743 }
2744}
2745
2746#if COAP_SERVER_SUPPORT
2747static int
2748coap_read_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, coap_tick_t now) {
2749 ssize_t bytes_read = -1;
2750 int result = -1; /* the value to be returned */
2751#if COAP_CONSTRAINED_STACK
2752 /* payload and e_packet can be protected by global_lock if needed */
2753 static unsigned char payload[COAP_RXBUFFER_SIZE];
2754 static coap_packet_t e_packet;
2755#else /* ! COAP_CONSTRAINED_STACK */
2756 unsigned char payload[COAP_RXBUFFER_SIZE];
2757 coap_packet_t e_packet;
2758#endif /* ! COAP_CONSTRAINED_STACK */
2759 coap_packet_t *packet = &e_packet;
2760
2761 assert(COAP_PROTO_NOT_RELIABLE(endpoint->proto));
2762 assert(endpoint->sock.flags & COAP_SOCKET_BOUND);
2763
2764 /* Need to do this as there may be holes in addr_info */
2765 memset(&packet->addr_info, 0, sizeof(packet->addr_info));
2766 packet->length = sizeof(payload);
2767 packet->payload = payload;
2769 coap_address_copy(&packet->addr_info.local, &endpoint->bind_addr);
2770
2771 bytes_read = coap_netif_dgrm_read_ep(endpoint, packet);
2772 if (bytes_read < 0) {
2773 if (errno != EAGAIN) {
2774 coap_log_warn("* %s: read failed\n", coap_endpoint_str(endpoint));
2775 }
2776 } else if (bytes_read > 0) {
2777 coap_session_t *session = coap_endpoint_get_session(endpoint, packet, now);
2778 if (session) {
2780 coap_log_debug("* %s: netif: recv %4" PRIdS " bytes\n",
2781 coap_session_str(session), bytes_read);
2782 result = coap_handle_dgram_for_proto(ctx, session, packet);
2783 if (endpoint->proto == COAP_PROTO_DTLS && session->type == COAP_SESSION_TYPE_HELLO && result == 1)
2784 coap_session_new_dtls_session(session, now);
2785 coap_session_release_lkd(session);
2786 }
2787 }
2788 return result;
2789}
2790
2791static int
2792coap_write_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, coap_tick_t now) {
2793 (void)ctx;
2794 (void)endpoint;
2795 (void)now;
2796 return 0;
2797}
2798
2799#if !COAP_DISABLE_TCP
2800static int
2801coap_accept_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint,
2802 coap_tick_t now, void *extra) {
2803 coap_session_t *session = coap_new_server_session(ctx, endpoint, extra);
2804 if (session)
2805 session->last_rx_tx = now;
2806 return session != NULL;
2807}
2808#endif /* !COAP_DISABLE_TCP */
2809#endif /* COAP_SERVER_SUPPORT */
2810
2811COAP_API void
2813 coap_lock_lock(return);
2814 coap_io_do_io_lkd(ctx, now);
2816}
2817
2818void
2820#ifdef COAP_EPOLL_SUPPORT
2821 (void)ctx;
2822 (void)now;
2823 coap_log_emerg("coap_io_do_io() requires libcoap not compiled for using epoll\n");
2824#else /* ! COAP_EPOLL_SUPPORT */
2825 coap_session_t *s, *rtmp;
2826
2828#if COAP_SERVER_SUPPORT
2829 coap_endpoint_t *ep, *tmp;
2830 LL_FOREACH_SAFE(ctx->endpoint, ep, tmp) {
2831 if ((ep->sock.flags & COAP_SOCKET_CAN_READ) != 0)
2832 coap_read_endpoint(ctx, ep, now);
2833 if ((ep->sock.flags & COAP_SOCKET_CAN_WRITE) != 0)
2834 coap_write_endpoint(ctx, ep, now);
2835#if !COAP_DISABLE_TCP
2836 if ((ep->sock.flags & COAP_SOCKET_CAN_ACCEPT) != 0)
2837 coap_accept_endpoint(ctx, ep, now, NULL);
2838#endif /* !COAP_DISABLE_TCP */
2839 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
2840 /* Make sure the session object is not deleted in one of the callbacks */
2842#if COAP_CLIENT_SUPPORT
2843 if (s->client_initiated && (s->sock.flags & COAP_SOCKET_CAN_CONNECT) != 0) {
2844 coap_connect_session(s, now);
2845 }
2846#endif /* COAP_CLIENT_SUPPORT */
2847 if ((s->sock.flags & COAP_SOCKET_CAN_READ) != 0) {
2848 coap_read_session(ctx, s, now);
2849 }
2850 if ((s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0) {
2851 coap_write_session(ctx, s, now);
2852 }
2854 }
2855 }
2856#endif /* COAP_SERVER_SUPPORT */
2857
2858#if COAP_CLIENT_SUPPORT
2859 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
2860 /* Make sure the session object is not deleted in one of the callbacks */
2862 if ((s->sock.flags & COAP_SOCKET_CAN_CONNECT) != 0) {
2863 coap_connect_session(s, now);
2864 }
2865 if ((s->sock.flags & COAP_SOCKET_CAN_READ) != 0 && s->ref > 1) {
2866 coap_read_session(ctx, s, now);
2867 }
2868 if ((s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0 && s->ref > 1) {
2869 coap_write_session(ctx, s, now);
2870 }
2872 }
2873#endif /* COAP_CLIENT_SUPPORT */
2874#endif /* ! COAP_EPOLL_SUPPORT */
2875}
2876
2877COAP_API void
2878coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents) {
2879 coap_lock_lock(return);
2880 coap_io_do_epoll_lkd(ctx, events, nevents);
2882}
2883
2884/*
2885 * While this code in part replicates coap_io_do_io_lkd(), doing the functions
2886 * directly saves having to iterate through the endpoints / sessions.
2887 */
2888void
2889coap_io_do_epoll_lkd(coap_context_t *ctx, struct epoll_event *events, size_t nevents) {
2890#ifndef COAP_EPOLL_SUPPORT
2891 (void)ctx;
2892 (void)events;
2893 (void)nevents;
2894 coap_log_emerg("coap_io_do_epoll() requires libcoap compiled for using epoll\n");
2895#else /* COAP_EPOLL_SUPPORT */
2896 coap_tick_t now;
2897 size_t j;
2898
2900 coap_ticks(&now);
2901 for (j = 0; j < nevents; j++) {
2902 coap_socket_t *sock = (coap_socket_t *)events[j].data.ptr;
2903
2904 /* Ignore 'timer trigger' ptr which is NULL */
2905 if (sock) {
2906#if COAP_SERVER_SUPPORT
2907 if (sock->endpoint) {
2908 coap_endpoint_t *endpoint = sock->endpoint;
2909 if ((sock->flags & COAP_SOCKET_WANT_READ) &&
2910 (events[j].events & EPOLLIN)) {
2911 sock->flags |= COAP_SOCKET_CAN_READ;
2912 coap_read_endpoint(endpoint->context, endpoint, now);
2913 }
2914
2915 if ((sock->flags & COAP_SOCKET_WANT_WRITE) &&
2916 (events[j].events & EPOLLOUT)) {
2917 /*
2918 * Need to update this to EPOLLIN as EPOLLOUT will normally always
2919 * be true causing epoll_wait to return early
2920 */
2921 coap_epoll_ctl_mod(sock, EPOLLIN, __func__);
2923 coap_write_endpoint(endpoint->context, endpoint, now);
2924 }
2925
2926#if !COAP_DISABLE_TCP
2927 if ((sock->flags & COAP_SOCKET_WANT_ACCEPT) &&
2928 (events[j].events & EPOLLIN)) {
2930 coap_accept_endpoint(endpoint->context, endpoint, now, NULL);
2931 }
2932#endif /* !COAP_DISABLE_TCP */
2933
2934 } else
2935#endif /* COAP_SERVER_SUPPORT */
2936 if (sock->session) {
2937 coap_session_t *session = sock->session;
2938
2939 /* Make sure the session object is not deleted
2940 in one of the callbacks */
2942#if COAP_CLIENT_SUPPORT
2943 if ((sock->flags & COAP_SOCKET_WANT_CONNECT) &&
2944 (events[j].events & (EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
2946 coap_connect_session(session, now);
2947 if (coap_netif_available(session) &&
2948 !(sock->flags & COAP_SOCKET_WANT_WRITE)) {
2949 coap_epoll_ctl_mod(sock, EPOLLIN, __func__);
2950 }
2951 }
2952#endif /* COAP_CLIENT_SUPPORT */
2953
2954 if ((sock->flags & COAP_SOCKET_WANT_READ) &&
2955 (events[j].events & (EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
2956 sock->flags |= COAP_SOCKET_CAN_READ;
2957 coap_read_session(session->context, session, now);
2958 }
2959
2960 if ((sock->flags & COAP_SOCKET_WANT_WRITE) &&
2961 (events[j].events & (EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
2962 /*
2963 * Need to update this to EPOLLIN as EPOLLOUT will normally always
2964 * be true causing epoll_wait to return early
2965 */
2966 coap_epoll_ctl_mod(sock, EPOLLIN, __func__);
2968 coap_write_session(session->context, session, now);
2969 }
2970 /* Now dereference session so it can go away if needed */
2971 coap_session_release_lkd(session);
2972 }
2973 } else if (ctx->eptimerfd != -1) {
2974 /*
2975 * 'timer trigger' must have fired. eptimerfd needs to be read to clear
2976 * it so that it does not set EPOLLIN in the next epoll_wait().
2977 */
2978 uint64_t count;
2979
2980 /* Check the result from read() to suppress the warning on
2981 * systems that declare read() with warn_unused_result. */
2982 if (read(ctx->eptimerfd, &count, sizeof(count)) == -1) {
2983 /* do nothing */;
2984 }
2985 }
2986 }
2987 /* And update eptimerfd as to when to next trigger */
2988 coap_ticks(&now);
2989 coap_io_prepare_epoll_lkd(ctx, now);
2990#endif /* COAP_EPOLL_SUPPORT */
2991}
2992
2993int
2995 uint8_t *msg, size_t msg_len) {
2996
2997 coap_pdu_t *pdu = NULL;
2998 coap_opt_filter_t error_opts;
2999
3000 assert(COAP_PROTO_NOT_RELIABLE(session->proto));
3001 if (msg_len < 4) {
3002 /* Minimum size of CoAP header - ignore runt */
3003 return -1;
3004 }
3005 if ((msg[0] >> 6) != COAP_DEFAULT_VERSION) {
3006 /*
3007 * As per https://datatracker.ietf.org/doc/html/rfc7252#section-3,
3008 * this MUST be silently ignored.
3009 */
3010 coap_log_debug("coap_handle_dgram: UDP version not supported\n");
3011 return -1;
3012 }
3013
3014 /* Need max space incase PDU is updated with updated token etc. */
3015 pdu = coap_pdu_init(0, 0, 0, coap_session_max_pdu_rcv_size(session));
3016 if (!pdu)
3017 goto error;
3018
3019 coap_option_filter_clear(&error_opts);
3020 if (!coap_pdu_parse2(session->proto, msg, msg_len, pdu, &error_opts)) {
3022 coap_log_warn("discard malformed PDU\n");
3023 if (error_opts.mask && COAP_PDU_IS_REQUEST(pdu)) {
3024 coap_pdu_t *response =
3026 COAP_RESPONSE_CODE(402), &error_opts);
3027 if (!response) {
3028 coap_log_warn("coap_handle_dgram: cannot create error response\n");
3029 } else {
3030 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
3031 coap_log_warn("coap_handle_dgram: error sending response\n");
3032 }
3034 return -1;
3035 } else {
3036 goto error;
3037 }
3038 }
3039
3040 coap_dispatch(ctx, session, pdu);
3042 return 0;
3043
3044error:
3045 /*
3046 * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST
3047 * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST
3048 */
3049 coap_send_rst_lkd(session, pdu);
3051 return -1;
3052}
3053
3054int
3056 coap_queue_t **node) {
3057 coap_queue_t *p, *q;
3058
3059 if (!queue || !*queue) {
3060 *node = NULL;
3061 return 0;
3062 }
3063
3064 /* replace queue head if PDU's time is less than head's time */
3065
3066 if (session == (*queue)->session && id == (*queue)->id) { /* found message id */
3067 *node = *queue;
3068 *queue = (*queue)->next;
3069 if (*queue) { /* adjust relative time of new queue head */
3070 (*queue)->t += (*node)->t;
3071 }
3072 (*node)->next = NULL;
3073 coap_log_debug("** %s: mid=0x%04x: removed (1)\n",
3074 coap_session_str(session), id);
3075 return 1;
3076 }
3077
3078 /* search message id in queue to remove (only first occurence will be removed) */
3079 q = *queue;
3080 do {
3081 p = q;
3082 q = q->next;
3083 } while (q && (session != q->session || id != q->id));
3084
3085 if (q) { /* found message id */
3086 p->next = q->next;
3087 if (p->next) { /* must update relative time of p->next */
3088 p->next->t += q->t;
3089 }
3090 q->next = NULL;
3091 *node = q;
3092 coap_log_debug("** %s: mid=0x%04x: removed (2)\n",
3093 coap_session_str(session), id);
3094 return 1;
3095 }
3096
3097 *node = NULL;
3098 return 0;
3099
3100}
3101
3102static int
3104 coap_bin_const_t *token, coap_queue_t **node) {
3105 coap_queue_t *p, *q;
3106
3107 if (!queue || !*queue)
3108 return 0;
3109
3110 /* replace queue head if PDU's time is less than head's time */
3111
3112 if (session == (*queue)->session &&
3113 (!token || coap_binary_equal(&(*queue)->pdu->actual_token, token))) { /* found token */
3114 *node = *queue;
3115 *queue = (*queue)->next;
3116 if (*queue) { /* adjust relative time of new queue head */
3117 (*queue)->t += (*node)->t;
3118 }
3119 (*node)->next = NULL;
3120 coap_log_debug("** %s: mid=0x%04x: removed (7)\n",
3121 coap_session_str(session), (*node)->id);
3122 if ((*node)->pdu->type == COAP_MESSAGE_CON && session->con_active) {
3123 session->con_active--;
3124 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
3125 /* Flush out any entries on session->delayqueue */
3126 coap_session_connected(session);
3127 }
3128 return 1;
3129 }
3130
3131 /* search token in queue to remove (only first occurence will be removed) */
3132 q = *queue;
3133 do {
3134 p = q;
3135 q = q->next;
3136 } while (q && (session != q->session ||
3137 !(!token || coap_binary_equal(&q->pdu->actual_token, token))));
3138
3139 if (q) { /* found token */
3140 p->next = q->next;
3141 if (p->next) { /* must update relative time of p->next */
3142 p->next->t += q->t;
3143 }
3144 q->next = NULL;
3145 *node = q;
3146 coap_log_debug("** %s: mid=0x%04x: removed (8)\n",
3147 coap_session_str(session), (*node)->id);
3148 if (q->pdu->type == COAP_MESSAGE_CON && session->con_active) {
3149 session->con_active--;
3150 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
3151 /* Flush out any entries on session->delayqueue */
3152 coap_session_connected(session);
3153 }
3154 return 1;
3155 }
3156
3157 return 0;
3158
3159}
3160
3161void
3163 coap_nack_reason_t reason) {
3164 coap_queue_t *p, *q;
3165
3166 while (context->sendqueue && context->sendqueue->session == session) {
3167 q = context->sendqueue;
3168 context->sendqueue = q->next;
3169 coap_log_debug("** %s: mid=0x%04x: removed (3)\n",
3170 coap_session_str(session), q->id);
3171 if (q->pdu->type == COAP_MESSAGE_CON) {
3172 coap_handle_nack(session, q->pdu, reason, q->id);
3173 }
3175 }
3176
3177 if (!context->sendqueue)
3178 return;
3179
3180 p = context->sendqueue;
3181 q = p->next;
3182
3183 while (q) {
3184 if (q->session == session) {
3185 p->next = q->next;
3186 coap_log_debug("** %s: mid=0x%04x: removed (4)\n",
3187 coap_session_str(session), q->id);
3188 if (q->pdu->type == COAP_MESSAGE_CON) {
3189 coap_handle_nack(session, q->pdu, reason, q->id);
3190 }
3192 q = p->next;
3193 } else {
3194 p = q;
3195 q = q->next;
3196 }
3197 }
3198}
3199
3200void
3202 coap_bin_const_t *token) {
3203 /* cancel all messages in sendqueue that belong to session
3204 * and use the specified token */
3205 coap_queue_t **p, *q;
3206
3207 if (!context->sendqueue)
3208 return;
3209
3210 p = &context->sendqueue;
3211 q = *p;
3212
3213 while (q) {
3214 if (q->session == session &&
3215 (!token || coap_binary_equal(&q->pdu->actual_token, token))) {
3216 *p = q->next;
3217 coap_log_debug("** %s: mid=0x%04x: removed (6)\n",
3218 coap_session_str(session), q->id);
3219 if (q->pdu->type == COAP_MESSAGE_CON && session->con_active) {
3220 session->con_active--;
3221 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
3222 /* Flush out any entries on session->delayqueue */
3223 coap_session_connected(session);
3224 }
3226 } else {
3227 p = &(q->next);
3228 }
3229 q = *p;
3230 }
3231}
3232
3233coap_pdu_t *
3235 coap_opt_filter_t *opts) {
3236 coap_opt_iterator_t opt_iter;
3237 coap_pdu_t *response;
3238 unsigned char type;
3239
3240#if COAP_ERROR_PHRASE_LENGTH > 0
3241 const char *phrase;
3242 if (code != COAP_RESPONSE_CODE(508)) {
3243 phrase = coap_response_phrase(code);
3244 } else {
3245 phrase = NULL;
3246 }
3247#endif
3248
3249 assert(request);
3250
3251 /* cannot send ACK if original request was not confirmable */
3252 type = request->type == COAP_MESSAGE_CON ?
3254
3255 /* Now create the response and fill with options and payload data. */
3256 response = coap_pdu_init(type, code, request->mid,
3257 request->session ?
3258 coap_session_max_pdu_size_lkd(request->session) : 512);
3259 if (response) {
3260 /* copy token */
3261 if (request->actual_token.length &&
3262 !coap_add_token(response, request->actual_token.length,
3263 request->actual_token.s)) {
3264 coap_log_debug("cannot add token to error response\n");
3265 coap_delete_pdu_lkd(response);
3266 return NULL;
3267 }
3268 if (response->code == COAP_RESPONSE_CODE(402)) {
3269 char buf[128];
3270 int first = 1;
3271
3272#if COAP_ERROR_PHRASE_LENGTH > 0
3273 snprintf(buf, sizeof(buf), "%s", phrase ? phrase : "");
3274#else
3275 buf[0] = '\000';
3276#endif
3277 /* copy all options into diagnostic message */
3278 coap_option_iterator_init(request, &opt_iter, opts);
3279 while (coap_option_next(&opt_iter)) {
3280 size_t len = strlen(buf);
3281
3282 snprintf(&buf[len], sizeof(buf) - len, "%s%d", first ? " " : ",", opt_iter.number);
3283 first = 0;
3284 }
3285 coap_add_data(response, (size_t)strlen(buf), (const uint8_t *)buf);
3286 } else if (opts && opts->mask) {
3287 coap_opt_t *option;
3288
3289 /* copy all options */
3290 coap_option_iterator_init(request, &opt_iter, opts);
3291 while ((option = coap_option_next(&opt_iter))) {
3292 coap_add_option_internal(response, opt_iter.number,
3293 coap_opt_length(option),
3294 coap_opt_value(option));
3295 }
3296#if COAP_ERROR_PHRASE_LENGTH > 0
3297 if (phrase)
3298 coap_add_data(response, (size_t)strlen(phrase), (const uint8_t *)phrase);
3299 } else {
3300 /* note that diagnostic messages do not need a Content-Format option. */
3301 if (phrase)
3302 coap_add_data(response, (size_t)strlen(phrase), (const uint8_t *)phrase);
3303#endif
3304 }
3305 }
3306
3307 return response;
3308}
3309
3310#if COAP_SERVER_SUPPORT
3311#define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4)))
3312
3313static void
3314free_wellknown_response(coap_session_t *session COAP_UNUSED, void *app_ptr) {
3315 coap_delete_string(app_ptr);
3316}
3317
3318/*
3319 * Caution: As this handler is in libcoap space, it is called with
3320 * context locked.
3321 */
3322static void
3323hnd_get_wellknown_lkd(coap_resource_t *resource,
3324 coap_session_t *session,
3325 const coap_pdu_t *request,
3326 const coap_string_t *query,
3327 coap_pdu_t *response) {
3328 size_t len = 0;
3329 coap_string_t *data_string = NULL;
3330 coap_print_status_t result = 0;
3331 size_t wkc_len = 0;
3332 uint8_t buf[4];
3333
3334 /*
3335 * Quick hack to determine the size of the resource descriptions for
3336 * .well-known/core.
3337 */
3338 result = coap_print_wellknown_lkd(session->context, buf, &wkc_len, UINT_MAX, query);
3339 if (result & COAP_PRINT_STATUS_ERROR) {
3340 coap_log_warn("cannot determine length of /.well-known/core\n");
3341 goto error;
3342 }
3343
3344 if (wkc_len > 0) {
3345 data_string = coap_new_string(wkc_len);
3346 if (!data_string)
3347 goto error;
3348
3349 len = wkc_len;
3350 result = coap_print_wellknown_lkd(session->context, data_string->s, &len, 0, query);
3351 if ((result & COAP_PRINT_STATUS_ERROR) != 0) {
3352 coap_log_debug("coap_print_wellknown failed\n");
3353 goto error;
3354 }
3355 assert(len <= (size_t)wkc_len);
3356 data_string->length = len;
3357
3358 if (!(session->block_mode & COAP_BLOCK_USE_LIBCOAP)) {
3360 coap_encode_var_safe(buf, sizeof(buf),
3362 goto error;
3363 }
3364 if (response->used_size + len + 1 > response->max_size) {
3365 /*
3366 * Data does not fit into a packet and no libcoap block support
3367 * +1 for end of options marker
3368 */
3369 coap_log_debug(".well-known/core: truncating data length to %" PRIuS " from %" PRIuS "\n",
3370 len, response->max_size - response->used_size - 1);
3371 len = response->max_size - response->used_size - 1;
3372 }
3373 if (!coap_add_data(response, len, data_string->s)) {
3374 goto error;
3375 }
3376 free_wellknown_response(session, data_string);
3377 } else if (!coap_add_data_large_response_lkd(resource, session, request,
3378 response, query,
3380 -1, 0, data_string->length,
3381 data_string->s,
3382 free_wellknown_response,
3383 data_string)) {
3384 goto error_released;
3385 }
3386 } else {
3388 coap_encode_var_safe(buf, sizeof(buf),
3390 goto error;
3391 }
3392 }
3393 response->code = COAP_RESPONSE_CODE(205);
3394 return;
3395
3396error:
3397 free_wellknown_response(session, data_string);
3398error_released:
3399 if (response->code == 0) {
3400 /* set error code 5.03 and remove all options and data from response */
3401 response->code = COAP_RESPONSE_CODE(503);
3402 response->used_size = response->e_token_length;
3403 response->data = NULL;
3404 }
3405}
3406#endif /* COAP_SERVER_SUPPORT */
3407
3418static int
3420 int num_cancelled = 0; /* the number of observers cancelled */
3421
3422#ifndef COAP_SERVER_SUPPORT
3423 (void)sent;
3424#endif /* ! COAP_SERVER_SUPPORT */
3425 (void)context;
3426
3427#if COAP_SERVER_SUPPORT
3428 /* remove observer for this resource, if any
3429 * Use token from sent and try to find a matching resource. Uh!
3430 */
3431 RESOURCES_ITER(context->resources, r) {
3432 coap_cancel_all_messages(context, sent->session, &sent->pdu->actual_token);
3433 num_cancelled += coap_delete_observer(r, sent->session, &sent->pdu->actual_token);
3434 }
3435#endif /* COAP_SERVER_SUPPORT */
3436
3437 return num_cancelled;
3438}
3439
3440#if COAP_SERVER_SUPPORT
3445enum respond_t { RESPONSE_DEFAULT, RESPONSE_DROP, RESPONSE_SEND };
3446
3447/*
3448 * Checks for No-Response option in given @p request and
3449 * returns @c RESPONSE_DROP if @p response should be suppressed
3450 * according to RFC 7967.
3451 *
3452 * If the response is a confirmable piggybacked response and RESPONSE_DROP,
3453 * change it to an empty ACK and @c RESPONSE_SEND so the client does not keep
3454 * on retrying.
3455 *
3456 * Checks if the response code is 0.00 and if either the session is reliable or
3457 * non-confirmable, @c RESPONSE_DROP is also returned.
3458 *
3459 * Multicast response checking is also carried out.
3460 *
3461 * NOTE: It is the responsibility of the application to determine whether
3462 * a delayed separate response should be sent as the original requesting packet
3463 * containing the No-Response option has long since gone.
3464 *
3465 * The value of the No-Response option is encoded as
3466 * follows:
3467 *
3468 * @verbatim
3469 * +-------+-----------------------+-----------------------------------+
3470 * | Value | Binary Representation | Description |
3471 * +-------+-----------------------+-----------------------------------+
3472 * | 0 | <empty> | Interested in all responses. |
3473 * +-------+-----------------------+-----------------------------------+
3474 * | 2 | 00000010 | Not interested in 2.xx responses. |
3475 * +-------+-----------------------+-----------------------------------+
3476 * | 8 | 00001000 | Not interested in 4.xx responses. |
3477 * +-------+-----------------------+-----------------------------------+
3478 * | 16 | 00010000 | Not interested in 5.xx responses. |
3479 * +-------+-----------------------+-----------------------------------+
3480 * @endverbatim
3481 *
3482 * @param request The CoAP request to check for the No-Response option.
3483 * This parameter must not be NULL.
3484 * @param response The response that is potentially suppressed.
3485 * This parameter must not be NULL.
3486 * @param session The session this request/response are associated with.
3487 * This parameter must not be NULL.
3488 * @return RESPONSE_DEFAULT when no special treatment is requested,
3489 * RESPONSE_DROP when the response must be discarded, or
3490 * RESPONSE_SEND when the response must be sent.
3491 */
3492static enum respond_t
3493no_response(coap_pdu_t *request, coap_pdu_t *response,
3494 coap_session_t *session, coap_resource_t *resource) {
3495 coap_opt_t *nores;
3496 coap_opt_iterator_t opt_iter;
3497 unsigned int val = 0;
3498
3499 assert(request);
3500 assert(response);
3501
3502 if (COAP_RESPONSE_CLASS(response->code) > 0) {
3503 nores = coap_check_option(request, COAP_OPTION_NORESPONSE, &opt_iter);
3504
3505 if (nores) {
3507
3508 /* The response should be dropped when the bit corresponding to
3509 * the response class is set (cf. table in function
3510 * documentation). When a No-Response option is present and the
3511 * bit is not set, the sender explicitly indicates interest in
3512 * this response. */
3513 if (((1 << (COAP_RESPONSE_CLASS(response->code) - 1)) & val) > 0) {
3514 /* Should be dropping the response */
3515 if (response->type == COAP_MESSAGE_ACK &&
3516 COAP_PROTO_NOT_RELIABLE(session->proto)) {
3517 /* Still need to ACK the request */
3518 response->code = 0;
3519 /* Remove token/data from piggybacked acknowledgment PDU */
3520 response->actual_token.length = 0;
3521 response->e_token_length = 0;
3522 response->used_size = 0;
3523 response->data = NULL;
3524 return RESPONSE_SEND;
3525 } else {
3526 return RESPONSE_DROP;
3527 }
3528 } else {
3529 /* True for mcast as well RFC7967 2.1 */
3530 return RESPONSE_SEND;
3531 }
3532 } else if (resource && session->context->mcast_per_resource &&
3533 coap_is_mcast(&session->addr_info.local)) {
3534 /* Handle any mcast suppression specifics if no NoResponse option */
3535 if ((resource->flags &
3537 COAP_RESPONSE_CLASS(response->code) == 2) {
3538 return RESPONSE_DROP;
3539 } else if ((resource->flags &
3541 response->code == COAP_RESPONSE_CODE(205)) {
3542 if (response->data == NULL)
3543 return RESPONSE_DROP;
3544 } else if ((resource->flags &
3546 COAP_RESPONSE_CLASS(response->code) == 4) {
3547 return RESPONSE_DROP;
3548 } else if ((resource->flags &
3550 COAP_RESPONSE_CLASS(response->code) == 5) {
3551 return RESPONSE_DROP;
3552 }
3553 }
3554 } else if (COAP_PDU_IS_EMPTY(response) &&
3555 (response->type == COAP_MESSAGE_NON ||
3556 COAP_PROTO_RELIABLE(session->proto))) {
3557 /* response is 0.00, and this is reliable or non-confirmable */
3558 return RESPONSE_DROP;
3559 }
3560
3561 /*
3562 * Do not send error responses for requests that were received via
3563 * IP multicast. RFC7252 8.1
3564 */
3565
3566 if (coap_is_mcast(&session->addr_info.local)) {
3567 if (request->type == COAP_MESSAGE_NON &&
3568 response->type == COAP_MESSAGE_RST)
3569 return RESPONSE_DROP;
3570
3571 if ((!resource || session->context->mcast_per_resource == 0) &&
3572 COAP_RESPONSE_CLASS(response->code) > 2)
3573 return RESPONSE_DROP;
3574 }
3575
3576 /* Default behavior applies when we are not dealing with a response
3577 * (class == 0) or the request did not contain a No-Response option.
3578 */
3579 return RESPONSE_DEFAULT;
3580}
3581
3582static coap_str_const_t coap_default_uri_wellknown = {
3584 (const uint8_t *)COAP_DEFAULT_URI_WELLKNOWN
3585};
3586
3587/* Initialized in coap_startup() */
3588static coap_resource_t resource_uri_wellknown;
3589
3590static void
3591handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu,
3592 coap_pdu_t *orig_pdu) {
3594 coap_pdu_t *response = NULL;
3595 coap_opt_filter_t opt_filter;
3596 coap_resource_t *resource = NULL;
3597 /* The respond field indicates whether a response must be treated
3598 * specially due to a No-Response option that declares disinterest
3599 * or interest in a specific response class. DEFAULT indicates that
3600 * No-Response has not been specified. */
3601 enum respond_t respond = RESPONSE_DEFAULT;
3602 coap_opt_iterator_t opt_iter;
3603 coap_opt_t *opt;
3604 int is_proxy_uri = 0;
3605 int is_proxy_scheme = 0;
3606 int skip_hop_limit_check = 0;
3607 int resp = 0;
3608 int send_early_empty_ack = 0;
3609 coap_string_t *query = NULL;
3610 coap_opt_t *observe = NULL;
3611 coap_string_t *uri_path = NULL;
3612 int observe_action = COAP_OBSERVE_CANCEL;
3613 coap_block_b_t block;
3614 int added_block = 0;
3615 coap_lg_srcv_t *free_lg_srcv = NULL;
3616#if COAP_Q_BLOCK_SUPPORT
3617 int lg_xmit_ctrl = 0;
3618#endif /* COAP_Q_BLOCK_SUPPORT */
3619#if COAP_ASYNC_SUPPORT
3620 coap_async_t *async;
3621#endif /* COAP_ASYNC_SUPPORT */
3622
3623 if (coap_is_mcast(&session->addr_info.local)) {
3624 if (COAP_PROTO_RELIABLE(session->proto) || pdu->type != COAP_MESSAGE_NON) {
3625 coap_log_info("Invalid multicast packet received RFC7252 8.1\n");
3626 return;
3627 }
3628 }
3629#if COAP_ASYNC_SUPPORT
3630 async = coap_find_async_lkd(session, pdu->actual_token);
3631 if (async) {
3632 coap_tick_t now;
3633
3634 coap_ticks(&now);
3635 if (async->delay == 0 || async->delay > now) {
3636 /* re-transmit missing ACK (only if CON) */
3637 coap_log_info("Retransmit async response\n");
3638 coap_send_ack_lkd(session, pdu);
3639 /* and do not pass on to the upper layers */
3640 return;
3641 }
3642 }
3643#endif /* COAP_ASYNC_SUPPORT */
3644
3645 coap_option_filter_clear(&opt_filter);
3646 if (!(context->unknown_resource && context->unknown_resource->is_reverse_proxy)) {
3647 opt = coap_check_option(pdu, COAP_OPTION_PROXY_SCHEME, &opt_iter);
3648 if (opt) {
3649 opt = coap_check_option(pdu, COAP_OPTION_URI_HOST, &opt_iter);
3650 if (!opt) {
3651 coap_log_debug("Proxy-Scheme requires Uri-Host\n");
3652 resp = 402;
3653 goto fail_response;
3654 }
3655 is_proxy_scheme = 1;
3656 }
3657
3658 opt = coap_check_option(pdu, COAP_OPTION_PROXY_URI, &opt_iter);
3659 if (opt)
3660 is_proxy_uri = 1;
3661 }
3662
3663 if (is_proxy_scheme || is_proxy_uri) {
3664 coap_uri_t uri;
3665
3666 if (!context->proxy_uri_resource) {
3667 /* Need to return a 5.05 RFC7252 Section 5.7.2 */
3668 coap_log_debug("Proxy-%s support not configured\n",
3669 is_proxy_scheme ? "Scheme" : "Uri");
3670 resp = 505;
3671 goto fail_response;
3672 }
3673 if (((size_t)pdu->code - 1 <
3674 (sizeof(resource->handler) / sizeof(resource->handler[0]))) &&
3675 !(context->proxy_uri_resource->handler[pdu->code - 1])) {
3676 /* Need to return a 5.05 RFC7252 Section 5.7.2 */
3677 coap_log_debug("Proxy-%s code %d.%02d handler not supported\n",
3678 is_proxy_scheme ? "Scheme" : "Uri",
3679 pdu->code/100, pdu->code%100);
3680 resp = 505;
3681 goto fail_response;
3682 }
3683
3684 /* Need to check if authority is the proxy endpoint RFC7252 Section 5.7.2 */
3685 if (is_proxy_uri) {
3687 coap_opt_length(opt), &uri) < 0) {
3688 /* Need to return a 5.05 RFC7252 Section 5.7.2 */
3689 coap_log_debug("Proxy-URI not decodable\n");
3690 resp = 505;
3691 goto fail_response;
3692 }
3693 } else {
3694 memset(&uri, 0, sizeof(uri));
3695 opt = coap_check_option(pdu, COAP_OPTION_URI_HOST, &opt_iter);
3696 if (opt) {
3697 uri.host.length = coap_opt_length(opt);
3698 uri.host.s = coap_opt_value(opt);
3699 } else
3700 uri.host.length = 0;
3701 }
3702
3703 resource = context->proxy_uri_resource;
3704 if (uri.host.length && resource->proxy_name_count &&
3705 resource->proxy_name_list) {
3706 size_t i;
3707
3708 if (resource->proxy_name_count == 1 &&
3709 resource->proxy_name_list[0]->length == 0) {
3710 /* If proxy_name_list[0] is zero length, then this is the endpoint */
3711 i = 0;
3712 } else {
3713 for (i = 0; i < resource->proxy_name_count; i++) {
3714 if (coap_string_equal(&uri.host, resource->proxy_name_list[i])) {
3715 break;
3716 }
3717 }
3718 }
3719 if (i != resource->proxy_name_count) {
3720 /* This server is hosting the proxy connection endpoint */
3721 if (pdu->crit_opt) {
3722 /* Cannot handle critical option */
3723 pdu->crit_opt = 0;
3724 resp = 402;
3725 resource = NULL;
3726 goto fail_response;
3727 }
3728 is_proxy_uri = 0;
3729 is_proxy_scheme = 0;
3730 skip_hop_limit_check = 1;
3731 }
3732 }
3733 resource = NULL;
3734 }
3735 assert(resource == NULL);
3736
3737 if (!skip_hop_limit_check) {
3738 opt = coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter);
3739 if (opt) {
3740 size_t hop_limit;
3741 uint8_t buf[4];
3742
3743 hop_limit =
3745 if (hop_limit == 1) {
3746 /* coap_send_internal() will fill in the IP address for us */
3747 resp = 508;
3748 goto fail_response;
3749 } else if (hop_limit < 1 || hop_limit > 255) {
3750 /* Need to return a 4.00 RFC8768 Section 3 */
3751 coap_log_info("Invalid Hop Limit\n");
3752 resp = 400;
3753 goto fail_response;
3754 }
3755 hop_limit--;
3757 coap_encode_var_safe8(buf, sizeof(buf), hop_limit),
3758 buf);
3759 }
3760 }
3761
3762 uri_path = coap_get_uri_path(pdu);
3763 if (!uri_path)
3764 return;
3765
3766 if (!is_proxy_uri && !is_proxy_scheme) {
3767 /* try to find the resource from the request URI */
3768 coap_str_const_t uri_path_c = { uri_path->length, uri_path->s };
3769 resource = coap_get_resource_from_uri_path_lkd(context, &uri_path_c);
3770 }
3771
3772 if ((resource == NULL) || (resource->is_unknown == 1) ||
3773 (resource->is_proxy_uri == 1)) {
3774 /* The resource was not found or there is an unexpected match against the
3775 * resource defined for handling unknown or proxy URIs.
3776 */
3777 if (resource != NULL)
3778 /* Close down unexpected match */
3779 resource = NULL;
3780 /*
3781 * Check if the request URI happens to be the well-known URI, or if the
3782 * unknown resource handler is defined, a PUT or optionally other methods,
3783 * if configured, for the unknown handler.
3784 *
3785 * if a PROXY URI/Scheme request and proxy URI handler defined, call the
3786 * proxy URI handler.
3787 *
3788 * else if unknown URI handler defined and COAP_RESOURCE_HANDLE_WELLKNOWN_CORE
3789 * set, call the unknown URI handler with any unknown URI (including
3790 * .well-known/core) if the appropriate method is defined.
3791 *
3792 * else if well-known URI generate a default response.
3793 *
3794 * else if unknown URI handler defined, call the unknown
3795 * URI handler (to allow for potential generation of resource
3796 * [RFC7272 5.8.3]) if the appropriate method is defined.
3797 *
3798 * else if DELETE return 2.02 (RFC7252: 5.8.4. DELETE).
3799 *
3800 * else return 4.04.
3801 */
3802
3803 if (is_proxy_uri || is_proxy_scheme) {
3804 resource = context->proxy_uri_resource;
3805 } else if (context->unknown_resource != NULL &&
3806 context->unknown_resource->flags & COAP_RESOURCE_HANDLE_WELLKNOWN_CORE &&
3807 ((size_t)pdu->code - 1 <
3808 (sizeof(resource->handler) / sizeof(coap_method_handler_t))) &&
3809 (context->unknown_resource->handler[pdu->code - 1])) {
3810 resource = context->unknown_resource;
3811 } else if (coap_string_equal(uri_path, &coap_default_uri_wellknown)) {
3812 /* request for .well-known/core */
3813 resource = &resource_uri_wellknown;
3814 } else if ((context->unknown_resource != NULL) &&
3815 ((size_t)pdu->code - 1 <
3816 (sizeof(resource->handler) / sizeof(coap_method_handler_t))) &&
3817 (context->unknown_resource->handler[pdu->code - 1])) {
3818 /*
3819 * The unknown_resource can be used to handle undefined resources
3820 * for a PUT request and can support any other registered handler
3821 * defined for it
3822 * Example set up code:-
3823 * r = coap_resource_unknown_init(hnd_put_unknown);
3824 * coap_register_request_handler(r, COAP_REQUEST_POST,
3825 * hnd_post_unknown);
3826 * coap_register_request_handler(r, COAP_REQUEST_GET,
3827 * hnd_get_unknown);
3828 * coap_register_request_handler(r, COAP_REQUEST_DELETE,
3829 * hnd_delete_unknown);
3830 * coap_add_resource(ctx, r);
3831 *
3832 * Note: It is not possible to observe the unknown_resource, a separate
3833 * resource must be created (by PUT or POST) which has a GET
3834 * handler to be observed
3835 */
3836 resource = context->unknown_resource;
3837 } else if (pdu->code == COAP_REQUEST_CODE_DELETE) {
3838 /*
3839 * Request for DELETE on non-existant resource (RFC7252: 5.8.4. DELETE)
3840 */
3841 coap_log_debug("request for unknown resource '%*.*s',"
3842 " return 2.02\n",
3843 (int)uri_path->length,
3844 (int)uri_path->length,
3845 uri_path->s);
3846 resp = 202;
3847 goto fail_response;
3848 } else if ((context->dyn_create_handler != NULL) &&
3850 /* Above test must be the same as in coap_op_dyn_resource_load_disk() */
3851 if (context->dynamic_cur < context->dynamic_max || context->dynamic_max == 0) {
3852#if COAP_WITH_OBSERVE_PERSIST
3853 /* If we are maintaining Observe persist */
3854 context->unknown_pdu = pdu;
3855 context->unknown_session = session;
3856#endif /* COAP_WITH_OBSERVE_PERSIST */
3857 coap_lock_callback_ret(resource, context->dyn_create_handler(session, pdu));
3858#if COAP_WITH_OBSERVE_PERSIST
3859 /* If we are maintaining Observe persist */
3860 context->unknown_pdu = NULL;
3861 context->unknown_session = NULL;
3862#endif /* COAP_WITH_OBSERVE_PERSIST */
3863 }
3864 if (!resource) {
3865 resp = 406;
3866 goto fail_response;
3867 }
3868 context->dynamic_cur++;
3869 resource->is_dynamic = 1;
3870 } else { /* request for any another resource, return 4.04 */
3871
3872 coap_log_debug("request for unknown resource '%*.*s', return 4.04\n",
3873 (int)uri_path->length, (int)uri_path->length, uri_path->s);
3874 resp = 404;
3875 goto fail_response;
3876 }
3877
3878 }
3879
3880 coap_resource_reference_lkd(resource);
3881
3882#if COAP_OSCORE_SUPPORT
3883 if ((resource->flags & COAP_RESOURCE_FLAGS_OSCORE_ONLY) && !session->oscore_encryption) {
3884 coap_log_debug("request for OSCORE only resource '%*.*s', return 4.04\n",
3885 (int)uri_path->length, (int)uri_path->length, uri_path->s);
3886 resp = 401;
3887 goto fail_response;
3888 }
3889#endif /* COAP_OSCORE_SUPPORT */
3890 if (resource->is_unknown == 0 && resource->is_proxy_uri == 0) {
3891 /* Check for existing resource and If-Non-Match */
3892 opt = coap_check_option(pdu, COAP_OPTION_IF_NONE_MATCH, &opt_iter);
3893 if (opt) {
3894 resp = 412;
3895 goto fail_response;
3896 }
3897 }
3898
3899 /* the resource was found, check if there is a registered handler */
3900 if ((size_t)pdu->code - 1 <
3901 sizeof(resource->handler) / sizeof(coap_method_handler_t))
3902 h = resource->handler[pdu->code - 1];
3903
3904 if (h == NULL) {
3905 resp = 405;
3906 goto fail_response;
3907 }
3908 if (pdu->code == COAP_REQUEST_CODE_FETCH) {
3909 if (coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter) == NULL) {
3910 opt = coap_check_option(pdu, COAP_OPTION_CONTENT_FORMAT, &opt_iter);
3911 if (opt == NULL) {
3912 /* RFC 8132 2.3.1 */
3913 resp = 415;
3914 goto fail_response;
3915 }
3916 }
3917 }
3918 if (context->mcast_per_resource &&
3919 (resource->flags & COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT) == 0 &&
3920 coap_is_mcast(&session->addr_info.local)) {
3921 resp = 405;
3922 goto fail_response;
3923 }
3924
3925 response = coap_pdu_init(pdu->type == COAP_MESSAGE_CON ?
3927 0, pdu->mid, coap_session_max_pdu_size_lkd(session));
3928 if (!response) {
3929 coap_log_err("could not create response PDU\n");
3930 resp = 500;
3931 goto fail_response;
3932 }
3933 response->session = session;
3934#if COAP_ASYNC_SUPPORT
3935 /* If handling a separate response, need CON, not ACK response */
3936 if (async && pdu->type == COAP_MESSAGE_CON)
3937 response->type = COAP_MESSAGE_CON;
3938#endif /* COAP_ASYNC_SUPPORT */
3939 /* A lot of the reliable code assumes type is CON */
3940 if (COAP_PROTO_RELIABLE(session->proto) && response->type != COAP_MESSAGE_CON)
3941 response->type = COAP_MESSAGE_CON;
3942
3943 if (!coap_add_token(response, pdu->actual_token.length,
3944 pdu->actual_token.s)) {
3945 resp = 500;
3946 goto fail_response;
3947 }
3948
3949 query = coap_get_query(pdu);
3950
3951 /* check for Observe option RFC7641 and RFC8132 */
3952 if (resource->observable &&
3953 (pdu->code == COAP_REQUEST_CODE_GET ||
3954 pdu->code == COAP_REQUEST_CODE_FETCH)) {
3955 observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
3956 }
3957
3958 /*
3959 * See if blocks need to be aggregated or next requests sent off
3960 * before invoking application request handler
3961 */
3962 if (session->block_mode & COAP_BLOCK_USE_LIBCOAP) {
3963 uint32_t block_mode = session->block_mode;
3964
3965 if (observe ||
3966 resource->flags & COAP_RESOURCE_FLAGS_FORCE_SINGLE_BODY)
3968 if (coap_handle_request_put_block(context, session, pdu, response,
3969 resource, uri_path, observe,
3970 &added_block, &free_lg_srcv)) {
3971 session->block_mode = block_mode;
3972 goto skip_handler;
3973 }
3974 session->block_mode = block_mode;
3975
3976 if (coap_handle_request_send_block(session, pdu, response, resource,
3977 query)) {
3978#if COAP_Q_BLOCK_SUPPORT
3979 lg_xmit_ctrl = 1;
3980#endif /* COAP_Q_BLOCK_SUPPORT */
3981 goto skip_handler;
3982 }
3983 }
3984
3985 if (observe) {
3986 observe_action =
3988 coap_opt_length(observe));
3989
3990 if (observe_action == COAP_OBSERVE_ESTABLISH) {
3991 coap_subscription_t *subscription;
3992
3993 if (coap_get_block_b(session, pdu, COAP_OPTION_BLOCK2, &block)) {
3994 if (block.num != 0) {
3995 response->code = COAP_RESPONSE_CODE(400);
3996 goto skip_handler;
3997 }
3998#if COAP_Q_BLOCK_SUPPORT
3999 } else if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK2,
4000 &block)) {
4001 if (block.num != 0) {
4002 response->code = COAP_RESPONSE_CODE(400);
4003 goto skip_handler;
4004 }
4005#endif /* COAP_Q_BLOCK_SUPPORT */
4006 }
4007 subscription = coap_add_observer(resource, session, &pdu->actual_token,
4008 pdu);
4009 if (subscription) {
4010 uint8_t buf[4];
4011
4012 coap_touch_observer(context, session, &pdu->actual_token);
4014 coap_encode_var_safe(buf, sizeof(buf),
4015 resource->observe),
4016 buf);
4017 }
4018 } else if (observe_action == COAP_OBSERVE_CANCEL) {
4019 coap_delete_observer_request(resource, session, &pdu->actual_token, pdu);
4020 } else {
4021 coap_log_info("observe: unexpected action %d\n", observe_action);
4022 }
4023 }
4024
4025 if ((resource == context->proxy_uri_resource ||
4026 (resource == context->unknown_resource &&
4027 context->unknown_resource->is_reverse_proxy)) &&
4028 COAP_PROTO_NOT_RELIABLE(session->proto) &&
4029 pdu->type == COAP_MESSAGE_CON &&
4030 !(session->block_mode & COAP_BLOCK_CACHE_RESPONSE)) {
4031 /* Make the proxy response separate and fix response later */
4032 send_early_empty_ack = 1;
4033 }
4034 if (send_early_empty_ack) {
4035 coap_send_ack_lkd(session, pdu);
4036 if (pdu->mid == session->last_con_mid) {
4037 /* request has already been processed - do not process it again */
4038 coap_log_debug("Duplicate request with mid=0x%04x - not processed\n",
4039 pdu->mid);
4040 goto drop_it_no_debug;
4041 }
4042 session->last_con_mid = pdu->mid;
4043 }
4044#if COAP_WITH_OBSERVE_PERSIST
4045 /* If we are maintaining Observe persist */
4046 if (resource == context->unknown_resource) {
4047 context->unknown_pdu = pdu;
4048 context->unknown_session = session;
4049 } else
4050 context->unknown_pdu = NULL;
4051#endif /* COAP_WITH_OBSERVE_PERSIST */
4052
4053 /*
4054 * Call the request handler with everything set up
4055 */
4056 if (resource == &resource_uri_wellknown) {
4057 /* Leave context locked */
4058 coap_log_debug("call handler for pseudo resource '%*.*s' (3)\n",
4059 (int)resource->uri_path->length, (int)resource->uri_path->length,
4060 resource->uri_path->s);
4061 h(resource, session, pdu, query, response);
4062 } else {
4063 coap_log_debug("call custom handler for resource '%*.*s' (3)\n",
4064 (int)resource->uri_path->length, (int)resource->uri_path->length,
4065 resource->uri_path->s);
4066 if (resource->flags & COAP_RESOURCE_SAFE_REQUEST_HANDLER) {
4067 coap_lock_callback_release(h(resource, session, pdu, query, response),
4068 /* context is being freed off */
4069 goto finish);
4070 } else {
4072 h(resource, session, pdu, query, response),
4073 /* context is being freed off */
4074 goto finish);
4075 }
4076 }
4077
4078 /* Check validity of response code */
4079 if (!coap_check_code_class(session, response)) {
4080 coap_log_warn("handle_request: Invalid PDU response code (%d.%02d)\n",
4081 COAP_RESPONSE_CLASS(response->code),
4082 response->code & 0x1f);
4083 goto drop_it_no_debug;
4084 }
4085
4086 /* Check if lg_xmit generated and update PDU code if so */
4087 coap_check_code_lg_xmit(session, pdu, response, resource, query);
4088
4089 if (free_lg_srcv) {
4090 /* Check to see if the server is doing a 4.01 + Echo response */
4091 if (response->code == COAP_RESPONSE_CODE(401) &&
4092 coap_check_option(response, COAP_OPTION_ECHO, &opt_iter)) {
4093 /* Need to keep lg_srcv around for client's response */
4094 } else {
4095 coap_lg_srcv_t *lg_srcv;
4096 /*
4097 * Need to check free_lg_srcv still exists in case of error or timing window
4098 */
4099 LL_FOREACH(session->lg_srcv, lg_srcv) {
4100 if (lg_srcv == free_lg_srcv) {
4101 LL_DELETE(session->lg_srcv, free_lg_srcv);
4102 coap_block_delete_lg_srcv(session, free_lg_srcv);
4103 break;
4104 }
4105 }
4106 }
4107 }
4108 if (added_block && COAP_RESPONSE_CLASS(response->code) == 2) {
4109 /* Just in case, as there are more to go */
4110 response->code = COAP_RESPONSE_CODE(231);
4111 }
4112
4113skip_handler:
4114 if (send_early_empty_ack &&
4115 response->type == COAP_MESSAGE_ACK) {
4116 /* Response is now separate - convert to CON as needed */
4117 response->type = COAP_MESSAGE_CON;
4118 /* Check for empty ACK - need to drop as already sent */
4119 if (response->code == 0) {
4120 goto drop_it_no_debug;
4121 }
4122 }
4123 respond = no_response(pdu, response, session, resource);
4124 if (respond != RESPONSE_DROP) {
4125#if (COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG)
4126 coap_mid_t mid = pdu->mid;
4127#endif
4128 if (COAP_RESPONSE_CLASS(response->code) != 2) {
4129 if (observe) {
4131 }
4132 }
4133 if (COAP_RESPONSE_CLASS(response->code) > 2) {
4134 if (observe)
4135 coap_delete_observer(resource, session, &pdu->actual_token);
4136 if (response->code != COAP_RESPONSE_CODE(413))
4138 }
4139
4140 /* If original request contained a token, and the registered
4141 * application handler made no changes to the response, then
4142 * this is an empty ACK with a token, which is a malformed
4143 * PDU */
4144 if ((response->type == COAP_MESSAGE_ACK)
4145 && (response->code == 0)) {
4146 /* Remove token from otherwise-empty acknowledgment PDU */
4147 response->actual_token.length = 0;
4148 response->e_token_length = 0;
4149 response->used_size = 0;
4150 response->data = NULL;
4151 }
4152
4153 if (!coap_is_mcast(&session->addr_info.local) ||
4154 (context->mcast_per_resource &&
4155 resource &&
4156 (resource->flags & COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYS))) {
4157 /* No delays to response */
4158#if COAP_Q_BLOCK_SUPPORT
4159 if (session->block_mode & COAP_BLOCK_USE_LIBCOAP &&
4160 !lg_xmit_ctrl && COAP_RESPONSE_CLASS(response->code) == 2 &&
4161 coap_get_block_b(session, response, COAP_OPTION_Q_BLOCK2, &block) &&
4162 block.m) {
4163 if (coap_send_q_block2(session, resource, query, pdu->code, block,
4164 response,
4165 COAP_SEND_INC_PDU) == COAP_INVALID_MID)
4166 coap_log_debug("cannot send response for mid=0x%x\n", mid);
4167 response = NULL;
4168 goto finish;
4169 }
4170#endif /* COAP_Q_BLOCK_SUPPORT */
4171 if (coap_send_internal(session, response, orig_pdu ? orig_pdu : pdu) == COAP_INVALID_MID) {
4172 coap_log_debug("cannot send response for mid=0x%04x\n", mid);
4173 goto finish;
4174 }
4175 } else {
4176 /* Need to delay mcast response */
4177 coap_queue_t *node = coap_new_node();
4178 uint8_t r;
4179 coap_tick_t delay;
4180
4181 if (!node) {
4182 coap_log_debug("mcast delay: insufficient memory\n");
4183 goto drop_it_no_debug;
4184 }
4185 if (!coap_pdu_encode_header(response, session->proto)) {
4187 goto drop_it_no_debug;
4188 }
4189
4190 node->id = response->mid;
4191 node->pdu = response;
4192 node->is_mcast = 1;
4193 coap_prng_lkd(&r, sizeof(r));
4194 delay = (COAP_DEFAULT_LEISURE_TICKS(session) * r) / 256;
4195 coap_log_debug(" %s: mid=0x%04x: mcast response delayed for %u.%03u secs\n",
4196 coap_session_str(session),
4197 response->mid,
4198 (unsigned int)(delay / COAP_TICKS_PER_SECOND),
4199 (unsigned int)((delay % COAP_TICKS_PER_SECOND) *
4200 1000 / COAP_TICKS_PER_SECOND));
4201 node->timeout = (unsigned int)delay;
4202 /* Use this to delay transmission */
4203 coap_wait_ack(session->context, session, node);
4204 }
4205 } else {
4206 coap_log_debug(" %s: mid=0x%04x: response dropped\n",
4207 coap_session_str(session),
4208 response->mid);
4209 coap_show_pdu(COAP_LOG_DEBUG, response);
4210drop_it_no_debug:
4211 coap_delete_pdu_lkd(response);
4212 }
4213#if COAP_Q_BLOCK_SUPPORT
4214 if (coap_get_block_b(session, pdu, COAP_OPTION_Q_BLOCK1, &block)) {
4215 if (COAP_PROTO_RELIABLE(session->proto)) {
4216 if (block.m) {
4217 /* All of the sequence not in yet */
4218 goto finish;
4219 }
4220 } else if (pdu->type == COAP_MESSAGE_NON) {
4221 /* More to go and not at a payload break */
4222 if (block.m && ((block.num + 1) % COAP_MAX_PAYLOADS(session))) {
4223 goto finish;
4224 }
4225 }
4226 }
4227#endif /* COAP_Q_BLOCK_SUPPORT */
4228
4229finish:
4230 if (query)
4231 coap_delete_string(query);
4232 if (resource)
4233 coap_resource_release_lkd(resource);
4234 coap_delete_string(uri_path);
4235 return;
4236
4237fail_response:
4238 coap_delete_pdu_lkd(response);
4239 response =
4241 &opt_filter);
4242 if (response)
4243 goto skip_handler;
4244 if (resource)
4245 coap_resource_release_lkd(resource);
4246 coap_delete_string(uri_path);
4247}
4248#endif /* COAP_SERVER_SUPPORT */
4249
4250#if COAP_CLIENT_SUPPORT
4251/* Call application-specific response handler when available. */
4252void
4254 coap_pdu_t *sent, coap_pdu_t *rcvd,
4255 void *body_data) {
4256 coap_context_t *context = session->context;
4257 coap_response_t ret;
4258
4259#if COAP_PROXY_SUPPORT
4260 if (context->proxy_response_cb) {
4261 coap_proxy_entry_t *proxy_entry;
4262 coap_proxy_req_t *proxy_req = coap_proxy_map_outgoing_request(session,
4263 rcvd,
4264 &proxy_entry);
4265
4266 if (proxy_req && proxy_req->incoming && !proxy_req->incoming->server_list) {
4267 coap_proxy_process_incoming(session, rcvd, body_data, proxy_req,
4268 proxy_entry);
4269 return;
4270 }
4271 }
4272#endif /* COAP_PROXY_SUPPORT */
4273 if (session->doing_send_recv && session->req_token &&
4274 coap_binary_equal(session->req_token, &rcvd->actual_token)) {
4275 /* processing coap_send_recv() call */
4276 session->resp_pdu = rcvd;
4278 /* Will get freed off when PDU is freed off */
4279 rcvd->data_free = body_data;
4280 coap_send_ack_lkd(session, rcvd);
4282 return;
4283 } else if (context->response_cb) {
4285 context->response_cb(session,
4286 sent,
4287 rcvd,
4288 rcvd->mid),
4289 /* context is being freed off */
4290 return);
4291 } else {
4292 ret = COAP_RESPONSE_OK;
4293 }
4294 if (ret == COAP_RESPONSE_FAIL && rcvd->type != COAP_MESSAGE_ACK) {
4295 coap_send_rst_lkd(session, rcvd);
4297 } else {
4298 coap_send_ack_lkd(session, rcvd);
4300 }
4301 coap_free_type(COAP_STRING, body_data);
4302}
4303
4304static void
4305handle_response(coap_context_t *context, coap_session_t *session,
4306 coap_pdu_t *sent, coap_pdu_t *rcvd) {
4307
4308 /* Set in case there is a later call to coap_update_token() */
4309 rcvd->session = session;
4310
4311 /* Check for message duplication */
4312 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
4313 if (rcvd->type == COAP_MESSAGE_CON) {
4314 if (rcvd->mid == session->last_con_mid) {
4315 /* Duplicate response: send ACK/RST, but don't process */
4316 if (session->last_con_handler_res == COAP_RESPONSE_OK)
4317 coap_send_ack_lkd(session, rcvd);
4318 else
4319 coap_send_rst_lkd(session, rcvd);
4320 return;
4321 }
4322 session->last_con_mid = rcvd->mid;
4323 } else if (rcvd->type == COAP_MESSAGE_ACK) {
4324 if (rcvd->mid == session->last_ack_mid) {
4325 /* Duplicate response */
4326 return;
4327 }
4328 session->last_ack_mid = rcvd->mid;
4329 }
4330 }
4331 /* Check to see if checking out extended token support */
4332 if (session->max_token_checked == COAP_EXT_T_CHECKING &&
4333 session->last_token) {
4334 coap_lg_crcv_t *lg_crcv;
4335
4336 if (!coap_binary_equal(session->last_token, &rcvd->actual_token) ||
4337 rcvd->actual_token.length != session->max_token_size ||
4338 rcvd->code == COAP_RESPONSE_CODE(400) ||
4339 rcvd->code == COAP_RESPONSE_CODE(503)) {
4340 coap_log_debug("Extended Token requested size support not available\n");
4342 } else {
4343 coap_log_debug("Extended Token support available\n");
4344 }
4346 /* Need to remove lg_crcv set up for this test */
4347 lg_crcv = coap_find_lg_crcv(session, rcvd);
4348 if (lg_crcv) {
4349 LL_DELETE(session->lg_crcv, lg_crcv);
4350 coap_block_delete_lg_crcv(session, lg_crcv);
4351 }
4352 coap_send_ack_lkd(session, rcvd);
4353 coap_reset_doing_first(session);
4354 return;
4355 }
4356#if COAP_Q_BLOCK_SUPPORT
4357 /* Check to see if checking out Q-Block support */
4358 if (session->block_mode & COAP_BLOCK_PROBE_Q_BLOCK) {
4359 if (rcvd->code == COAP_RESPONSE_CODE(402)) {
4360 coap_log_debug("Q-Block support not available\n");
4361 set_block_mode_drop_q(session->block_mode);
4362 } else {
4363 coap_block_b_t qblock;
4364
4365 if (coap_get_block_b(session, rcvd, COAP_OPTION_Q_BLOCK2, &qblock)) {
4366 coap_log_debug("Q-Block support available\n");
4367 set_block_mode_has_q(session->block_mode);
4368 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
4369 /* Flush out any entries on session->delayqueue */
4370 coap_session_connected(session);
4371 } else {
4372 coap_log_debug("Q-Block support not available\n");
4373 set_block_mode_drop_q(session->block_mode);
4374 }
4375 }
4376 coap_send_ack_lkd(session, rcvd);
4377 coap_reset_doing_first(session);
4378 return;
4379 }
4380#endif /* COAP_Q_BLOCK_SUPPORT */
4381
4382 if (session->block_mode & COAP_BLOCK_USE_LIBCOAP) {
4383 /* See if need to send next block to server */
4384 if (coap_handle_response_send_block(session, sent, rcvd)) {
4385 /* Next block transmitted, no need to inform app */
4386 coap_send_ack_lkd(session, rcvd);
4387 return;
4388 }
4389
4390 /* Need to see if needing to request next block */
4391 if (coap_handle_response_get_block(context, session, sent, rcvd,
4392 COAP_RECURSE_OK)) {
4393 /* Next block transmitted, ack sent no need to inform app */
4394 return;
4395 }
4396 }
4397 coap_reset_doing_first(session);
4398
4399 /* Call application-specific response handler when available. */
4400 coap_call_response_handler(session, sent, rcvd, NULL);
4401}
4402#endif /* COAP_CLIENT_SUPPORT */
4403
4404#if !COAP_DISABLE_TCP
4405static void
4407 coap_pdu_t *pdu) {
4408 coap_opt_iterator_t opt_iter;
4409 coap_opt_t *option;
4410 int set_mtu = 0;
4411
4412 coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
4413
4414 if (pdu->code == COAP_SIGNALING_CODE_CSM) {
4415 if (session->csm_not_seen) {
4416 coap_tick_t now;
4417
4418 coap_ticks(&now);
4419 /* CSM timeout before CSM seen */
4420 coap_log_warn("***%s: CSM received after CSM timeout\n",
4421 coap_session_str(session));
4422 coap_log_warn("***%s: Increase timeout in coap_context_set_csm_timeout_ms() to > %d\n",
4423 coap_session_str(session),
4424 (int)(((now - session->csm_tx) * 1000) / COAP_TICKS_PER_SECOND));
4425 }
4426 if (session->max_token_checked == COAP_EXT_T_NOT_CHECKED) {
4428 }
4429 while ((option = coap_option_next(&opt_iter))) {
4431 unsigned max_recv = coap_decode_var_bytes(coap_opt_value(option), coap_opt_length(option));
4432
4433 if (max_recv > COAP_DEFAULT_MAX_PDU_RX_SIZE) {
4435 coap_log_debug("* %s: Restricting CSM Max-Message-Size size to %u\n",
4436 coap_session_str(session), max_recv);
4437 }
4438 coap_session_set_mtu(session, max_recv);
4439 set_mtu = 1;
4440 } else if (opt_iter.number == COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER) {
4441 session->csm_block_supported = 1;
4442 } else if (opt_iter.number == COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH) {
4443 session->max_token_size =
4445 coap_opt_length(option));
4448 else if (session->max_token_size > COAP_TOKEN_EXT_MAX)
4451 }
4452 }
4453 if (set_mtu) {
4454 if (session->mtu > COAP_BERT_BASE && session->csm_block_supported)
4455 session->csm_bert_rem_support = 1;
4456 else
4457 session->csm_bert_rem_support = 0;
4458 }
4459 if (session->state == COAP_SESSION_STATE_CSM)
4460 coap_session_connected(session);
4461 } else if (pdu->code == COAP_SIGNALING_CODE_PING) {
4463 if (context->ping_cb) {
4464 coap_lock_callback(context->ping_cb(session, pdu, pdu->mid));
4465 }
4466 if (pong) {
4468 coap_send_internal(session, pong, NULL);
4469 }
4470 } else if (pdu->code == COAP_SIGNALING_CODE_PONG) {
4471 session->last_pong = session->last_rx_tx;
4472 if (context->pong_cb) {
4473 coap_lock_callback(context->pong_cb(session, pdu, pdu->mid));
4474 }
4475 } else if (pdu->code == COAP_SIGNALING_CODE_RELEASE
4476 || pdu->code == COAP_SIGNALING_CODE_ABORT) {
4478 }
4479}
4480#endif /* !COAP_DISABLE_TCP */
4481
4482static int
4484 if (COAP_PDU_IS_REQUEST(pdu) &&
4485 pdu->actual_token.length >
4486 (session->type == COAP_SESSION_TYPE_CLIENT ?
4487 session->max_token_size : session->context->max_token_size)) {
4488 /* https://rfc-editor.org/rfc/rfc8974#section-2.2.2 */
4489 if (session->max_token_size > COAP_TOKEN_DEFAULT_MAX) {
4490 coap_opt_filter_t opt_filter;
4491 coap_pdu_t *response;
4492
4493 memset(&opt_filter, 0, sizeof(coap_opt_filter_t));
4494 response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(400),
4495 &opt_filter);
4496 if (!response) {
4497 coap_log_warn("coap_dispatch: cannot create error response\n");
4498 } else {
4499 /*
4500 * Note - have to leave in oversize token as per
4501 * https://rfc-editor.org/rfc/rfc7252#section-5.3.1
4502 */
4503 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
4504 coap_log_warn("coap_dispatch: error sending response\n");
4505 }
4506 } else {
4507 /* Indicate no extended token support */
4508 coap_send_rst_lkd(session, pdu);
4509 }
4510 return 0;
4511 }
4512 return 1;
4513}
4514
4515void
4517 coap_pdu_t *pdu) {
4518 coap_queue_t *sent = NULL;
4519 coap_pdu_t *response;
4520 coap_pdu_t *orig_pdu = NULL;
4521 coap_opt_filter_t opt_filter;
4522 int is_ping_rst;
4523 int packet_is_bad = 0;
4524#if COAP_OSCORE_SUPPORT
4525 coap_opt_iterator_t opt_iter;
4526 coap_pdu_t *dec_pdu = NULL;
4527#endif /* COAP_OSCORE_SUPPORT */
4528 int is_ext_token_rst = 0;
4529 int oscore_invalid = 0;
4530
4531 pdu->session = session;
4533
4534 /* Check validity of received code */
4535 if (!coap_check_code_class(session, pdu)) {
4536 coap_log_info("coap_dispatch: Received invalid PDU code (%d.%02d)\n",
4538 pdu->code & 0x1f);
4539 packet_is_bad = 1;
4540 if (pdu->type == COAP_MESSAGE_CON) {
4542 }
4543 /* find message id in sendqueue to stop retransmission */
4544 coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent);
4545 goto cleanup;
4546 }
4547
4548 coap_option_filter_clear(&opt_filter);
4549
4550#if COAP_SERVER_SUPPORT
4551 /* See if this a repeat request */
4552 if (COAP_PDU_IS_REQUEST(pdu) && session->cached_pdu &&
4554 coap_digest_t digest;
4555
4556 coap_pdu_cksum(pdu, &digest);
4557 if (memcmp(&digest, &session->cached_pdu_cksum, sizeof(digest)) == 0) {
4558#if COAP_OSCORE_SUPPORT
4559 uint8_t oscore_encryption = session->oscore_encryption;
4560
4561 session->oscore_encryption = 0;
4562#endif /* COAP_OSCORE_SUPPORT */
4563 /* Account for coap_send_internal() doing a coap_delete_pdu() and
4564 cached_pdu must not be removed */
4565 coap_pdu_reference_lkd(session->cached_pdu);
4566 coap_log_debug("Retransmit response to duplicate request\n");
4567 if (coap_send_internal(session, session->cached_pdu, NULL) != COAP_INVALID_MID) {
4568#if COAP_OSCORE_SUPPORT
4569 session->oscore_encryption = oscore_encryption;
4570#endif /* COAP_OSCORE_SUPPORT */
4571 return;
4572 }
4573#if COAP_OSCORE_SUPPORT
4574 session->oscore_encryption = oscore_encryption;
4575#endif /* COAP_OSCORE_SUPPORT */
4576 }
4577 }
4578#endif /* COAP_SERVER_SUPPORT */
4579 if (pdu->type == COAP_MESSAGE_NON || pdu->type == COAP_MESSAGE_CON) {
4580 if (!check_token_size(session, pdu)) {
4581 goto cleanup;
4582 }
4583 }
4584#if COAP_OSCORE_SUPPORT
4585 if (!COAP_PDU_IS_SIGNALING(pdu) &&
4586 coap_option_check_critical(session, pdu, &opt_filter) == 0) {
4587 if (pdu->type == COAP_MESSAGE_CON || pdu->type == COAP_MESSAGE_NON) {
4588 if (COAP_PDU_IS_REQUEST(pdu)) {
4589 response =
4590 coap_new_error_response(pdu, COAP_RESPONSE_CODE(402), &opt_filter);
4591
4592 if (!response) {
4593 coap_log_warn("coap_dispatch: cannot create error response\n");
4594 } else {
4595 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
4596 coap_log_warn("coap_dispatch: error sending response\n");
4597 }
4598 } else {
4599 coap_send_rst_lkd(session, pdu);
4600 }
4601 }
4602 goto cleanup;
4603 }
4604
4605 if (coap_check_option(pdu, COAP_OPTION_OSCORE, &opt_iter) != NULL) {
4606 int decrypt = 1;
4607#if COAP_SERVER_SUPPORT
4608 coap_opt_t *opt;
4609 coap_resource_t *resource;
4610 coap_uri_t uri;
4611#endif /* COAP_SERVER_SUPPORT */
4612
4613 if (COAP_PDU_IS_RESPONSE(pdu) && !session->oscore_encryption)
4614 decrypt = 0;
4615
4616#if COAP_SERVER_SUPPORT
4617 if (decrypt && COAP_PDU_IS_REQUEST(pdu) &&
4618 coap_check_option(pdu, COAP_OPTION_PROXY_SCHEME, &opt_iter) != NULL &&
4619 (opt = coap_check_option(pdu, COAP_OPTION_URI_HOST, &opt_iter))
4620 != NULL) {
4621 /* Need to check whether this is a direct or proxy session */
4622 memset(&uri, 0, sizeof(uri));
4623 uri.host.length = coap_opt_length(opt);
4624 uri.host.s = coap_opt_value(opt);
4625 resource = context->proxy_uri_resource;
4626 if (uri.host.length && resource && resource->proxy_name_count &&
4627 resource->proxy_name_list) {
4628 size_t i;
4629 for (i = 0; i < resource->proxy_name_count; i++) {
4630 if (coap_string_equal(&uri.host, resource->proxy_name_list[i])) {
4631 break;
4632 }
4633 }
4634 if (i == resource->proxy_name_count) {
4635 /* This server is not hosting the proxy connection endpoint */
4636 decrypt = 0;
4637 }
4638 }
4639 }
4640#endif /* COAP_SERVER_SUPPORT */
4641 if (decrypt) {
4642 /* find message id in sendqueue to stop retransmission and get sent */
4643 coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent);
4644 /* Bump ref so pdu is not freed of, and keep a pointer to it */
4645 orig_pdu = pdu;
4646 coap_pdu_reference_lkd(orig_pdu);
4647 if ((dec_pdu = coap_oscore_decrypt_pdu(session, pdu)) == NULL) {
4648 if (session->recipient_ctx == NULL ||
4649 session->recipient_ctx->initial_state == 0) {
4650 coap_log_warn("OSCORE: PDU could not be decrypted\n");
4651 }
4653 coap_delete_pdu_lkd(orig_pdu);
4654 return;
4655 } else {
4656 session->oscore_encryption = 1;
4657 pdu = dec_pdu;
4658 }
4659 coap_log_debug("Decrypted PDU\n");
4661 }
4662 } else if (COAP_PDU_IS_RESPONSE(pdu) &&
4663 session->oscore_encryption &&
4664 pdu->type != COAP_MESSAGE_RST) {
4665 if (COAP_RESPONSE_CLASS(pdu->code) == 2) {
4666 /* Violates RFC 8613 2 */
4667 coap_log_err("received an invalid response to the OSCORE request\n");
4668 oscore_invalid = 1;
4669 }
4670 }
4671#endif /* COAP_OSCORE_SUPPORT */
4672
4673 switch (pdu->type) {
4674 case COAP_MESSAGE_ACK:
4675 if (NULL == sent) {
4676 /* find message id in sendqueue to stop retransmission */
4677 coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent);
4678 }
4679
4680 if (sent && session->con_active) {
4681 session->con_active--;
4682 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
4683 /* Flush out any entries on session->delayqueue */
4684 coap_session_connected(session);
4685 }
4686 if (oscore_invalid || coap_option_check_critical(session, pdu, &opt_filter) == 0) {
4687 packet_is_bad = 1;
4688 goto cleanup;
4689 }
4690
4691#if COAP_SERVER_SUPPORT
4692 /* if sent code was >= 64 the message might have been a
4693 * notification. Then, we must flag the observer to be alive
4694 * by setting obs->fail_cnt = 0. */
4695 if (sent && COAP_RESPONSE_CLASS(sent->pdu->code) == 2) {
4696 coap_touch_observer(context, sent->session, &sent->pdu->actual_token);
4697 }
4698#endif /* COAP_SERVER_SUPPORT */
4699
4700#if COAP_Q_BLOCK_SUPPORT
4701 if (session->lg_xmit && sent && sent->pdu && sent->pdu->type == COAP_MESSAGE_CON &&
4702 !(session->block_mode & COAP_BLOCK_PROBE_Q_BLOCK)) {
4703 int doing_q_block = 0;
4704 coap_lg_xmit_t *lg_xmit = NULL;
4705
4706 LL_FOREACH(session->lg_xmit, lg_xmit) {
4707 if ((lg_xmit->option == COAP_OPTION_Q_BLOCK1 || lg_xmit->option == COAP_OPTION_Q_BLOCK2) &&
4708 lg_xmit->last_all_sent == 0 && lg_xmit->sent_pdu->type != COAP_MESSAGE_NON) {
4709 doing_q_block = 1;
4710 break;
4711 }
4712 }
4713 if (doing_q_block && lg_xmit) {
4714 coap_block_b_t block;
4715
4716 memset(&block, 0, sizeof(block));
4717 if (lg_xmit->option == COAP_OPTION_Q_BLOCK1) {
4718 block.num = lg_xmit->last_block + lg_xmit->b.b1.count;
4719 } else {
4720 block.num = lg_xmit->last_block;
4721 }
4722 block.m = 1;
4723 block.szx = block.aszx = lg_xmit->blk_size;
4724 block.defined = 1;
4725 block.bert = 0;
4726 block.chunk_size = 1024;
4727
4728 coap_send_q_blocks(session, lg_xmit, block,
4729 lg_xmit->sent_pdu, COAP_SEND_SKIP_PDU);
4730 }
4731 }
4732#endif /* COAP_Q_BLOCK_SUPPORT */
4733 if (pdu->code == 0) {
4734#if COAP_CLIENT_SUPPORT
4735 /*
4736 * In coap_send(), lg_crcv was not set up if type is CON and protocol is not
4737 * reliable to save overhead as this can be set up on detection of a (Q)-Block2
4738 * response if the response was piggy-backed. Here, a separate response
4739 * detected and so the lg_crcv needs to be set up before the sent PDU
4740 * information is lost.
4741 *
4742 * lg_crcv was not set up if not a CoAP request.
4743 *
4744 * lg_crcv was always set up in coap_send() if Observe, Oscore and (Q)-Block1
4745 * options.
4746 */
4747 if (sent &&
4748 !coap_check_send_need_lg_crcv(session, sent->pdu) &&
4749 COAP_PDU_IS_REQUEST(sent->pdu)) {
4750 /*
4751 * lg_crcv was not set up in coap_send(). It could have been set up
4752 * the first separate response.
4753 * See if there already is a lg_crcv set up.
4754 */
4755 coap_lg_crcv_t *lg_crcv;
4756 uint64_t token_match =
4758 sent->pdu->actual_token.length));
4759
4760 LL_FOREACH(session->lg_crcv, lg_crcv) {
4761 if (token_match == STATE_TOKEN_BASE(lg_crcv->state_token) ||
4762 coap_binary_equal(&sent->pdu->actual_token, lg_crcv->app_token)) {
4763 break;
4764 }
4765 }
4766 if (!lg_crcv) {
4767 /*
4768 * Need to set up a lg_crcv as it was not set up in coap_send()
4769 * to save time, but server has not sent back a piggy-back response.
4770 */
4771 lg_crcv = coap_block_new_lg_crcv(session, sent->pdu, NULL);
4772 if (lg_crcv) {
4773 LL_PREPEND(session->lg_crcv, lg_crcv);
4774 }
4775 }
4776 }
4777#endif /* COAP_CLIENT_SUPPORT */
4778 /* an empty ACK needs no further handling */
4779 goto cleanup;
4780 } else if (COAP_PDU_IS_REQUEST(pdu)) {
4781 /* This is not legitimate - Request using ACK - ignore */
4782 coap_log_debug("dropped ACK with request code (%d.%02d)\n",
4784 pdu->code & 0x1f);
4785 packet_is_bad = 1;
4786 goto cleanup;
4787 }
4788
4789 break;
4790
4791 case COAP_MESSAGE_RST:
4792 /* We have sent something the receiver disliked, so we remove
4793 * not only the message id but also the subscriptions we might
4794 * have. */
4795 is_ping_rst = 0;
4796 if (pdu->mid == session->last_ping_mid &&
4797 session->last_ping > 0)
4798 is_ping_rst = 1;
4799
4800#if COAP_CLIENT_SUPPORT
4801#if COAP_Q_BLOCK_SUPPORT
4802 /* Check to see if checking out Q-Block support */
4803 if (session->block_mode & COAP_BLOCK_PROBE_Q_BLOCK &&
4804 session->remote_test_mid == pdu->mid) {
4805 coap_log_debug("Q-Block support not available\n");
4806 set_block_mode_drop_q(session->block_mode);
4807 coap_reset_doing_first(session);
4808 }
4809#endif /* COAP_Q_BLOCK_SUPPORT */
4810
4811 /* Check to see if checking out extended token support */
4812 if (session->max_token_checked == COAP_EXT_T_CHECKING &&
4813 session->remote_test_mid == pdu->mid) {
4814 coap_log_debug("Extended Token support not available\n");
4817 coap_reset_doing_first(session);
4818 is_ext_token_rst = 1;
4819 }
4820#endif /* COAP_CLIENT_SUPPORT */
4821
4822 if (!is_ping_rst && !is_ext_token_rst)
4823 coap_log_alert("got RST for mid=0x%04x\n", pdu->mid);
4824
4825 if (session->con_active) {
4826 session->con_active--;
4827 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
4828 /* Flush out any entries on session->delayqueue */
4829 coap_session_connected(session);
4830 }
4831
4832 /* find message id in sendqueue to stop retransmission */
4833 coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent);
4834
4835 if (sent) {
4836 if (!is_ping_rst)
4837 coap_cancel(context, sent);
4838
4839 if (!is_ping_rst && !is_ext_token_rst) {
4840 if (sent->pdu->type==COAP_MESSAGE_CON) {
4841 coap_handle_nack(sent->session, sent->pdu, COAP_NACK_RST, sent->id);
4842 }
4843 } else if (is_ping_rst) {
4844 if (context->pong_cb) {
4845 coap_lock_callback(context->pong_cb(session, pdu, pdu->mid));
4846 }
4847 session->last_pong = session->last_rx_tx;
4849 }
4850 } else {
4851#if COAP_SERVER_SUPPORT
4852 /* Need to check is there is a subscription active and delete it */
4853 RESOURCES_ITER(context->resources, r) {
4854 coap_subscription_t *obs, *tmp;
4855 LL_FOREACH_SAFE(r->subscribers, obs, tmp) {
4856 if (obs->pdu->mid == pdu->mid && obs->session == session) {
4857 /* Need to do this now as session may get de-referenced */
4859 coap_delete_observer(r, session, &obs->pdu->actual_token);
4860 coap_handle_nack(session, NULL, COAP_NACK_RST, pdu->mid);
4861 coap_session_release_lkd(session);
4862 goto cleanup;
4863 }
4864 }
4865 }
4866#endif /* COAP_SERVER_SUPPORT */
4867 coap_handle_nack(session, NULL, COAP_NACK_RST, pdu->mid);
4868 }
4869#if COAP_PROXY_SUPPORT
4870 if (!is_ping_rst) {
4871 /* Need to check is there is a proxy subscription active and delete it */
4872 coap_delete_proxy_subscriber(session, NULL, pdu->mid, COAP_PROXY_SUBS_MID);
4873 }
4874#endif /* COAP_PROXY_SUPPORT */
4875 goto cleanup;
4876
4877 case COAP_MESSAGE_NON:
4878 /* check for oscore issue or unknown critical options */
4879 if (oscore_invalid || coap_option_check_critical(session, pdu, &opt_filter) == 0) {
4880 packet_is_bad = 1;
4881 if (COAP_PDU_IS_REQUEST(pdu)) {
4882 response =
4883 coap_new_error_response(pdu, COAP_RESPONSE_CODE(402), &opt_filter);
4884
4885 if (!response) {
4886 coap_log_warn("coap_dispatch: cannot create error response\n");
4887 } else {
4888 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
4889 coap_log_warn("coap_dispatch: error sending response\n");
4890 }
4891 } else {
4892 coap_send_rst_lkd(session, pdu);
4893 }
4894 goto cleanup;
4895 }
4896 break;
4897
4898 case COAP_MESSAGE_CON:
4899 /* In a lossy context, the ACK of a separate response may have
4900 * been lost, so we need to stop retransmitting requests with the
4901 * same token. Matching on token potentially containing ext length bytes.
4902 */
4903 /* find message token in sendqueue to stop retransmission */
4904 coap_remove_from_queue_token(&context->sendqueue, session, &pdu->actual_token, &sent);
4905
4906 /* check for oscore issue or unknown critical options in non-signaling messages */
4907 if (oscore_invalid ||
4908 (!COAP_PDU_IS_SIGNALING(pdu) && coap_option_check_critical(session, pdu, &opt_filter) == 0)) {
4909 packet_is_bad = 1;
4910 if (COAP_PDU_IS_REQUEST(pdu)) {
4911 response =
4912 coap_new_error_response(pdu, COAP_RESPONSE_CODE(402), &opt_filter);
4913
4914 if (!response) {
4915 coap_log_warn("coap_dispatch: cannot create error response\n");
4916 } else {
4917 if (coap_send_internal(session, response, NULL) == COAP_INVALID_MID)
4918 coap_log_warn("coap_dispatch: error sending response\n");
4919 }
4920 } else {
4921 coap_send_rst_lkd(session, pdu);
4922 }
4923 goto cleanup;
4924 }
4925 break;
4926 default:
4927 break;
4928 }
4929
4930 /* Pass message to upper layer if a specific handler was
4931 * registered for a request that should be handled locally. */
4932#if !COAP_DISABLE_TCP
4933 if (COAP_PDU_IS_SIGNALING(pdu))
4934 handle_signaling(context, session, pdu);
4935 else
4936#endif /* !COAP_DISABLE_TCP */
4937#if COAP_SERVER_SUPPORT
4938 if (COAP_PDU_IS_REQUEST(pdu))
4939 handle_request(context, session, pdu, orig_pdu);
4940 else
4941#endif /* COAP_SERVER_SUPPORT */
4942#if COAP_CLIENT_SUPPORT
4943 if (COAP_PDU_IS_RESPONSE(pdu))
4944 handle_response(context, session, sent ? sent->pdu : NULL, pdu);
4945 else
4946#endif /* COAP_CLIENT_SUPPORT */
4947 {
4948 if (COAP_PDU_IS_EMPTY(pdu)) {
4949 if (context->ping_cb) {
4950 coap_lock_callback(context->ping_cb(session, pdu, pdu->mid));
4951 }
4952 } else {
4953 packet_is_bad = 1;
4954 }
4955 coap_log_debug("dropped message with invalid code (%d.%02d)\n",
4957 pdu->code & 0x1f);
4958
4959 if (!coap_is_mcast(&session->addr_info.local)) {
4960 if (COAP_PDU_IS_EMPTY(pdu)) {
4961 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
4962 coap_tick_t now;
4963 coap_ticks(&now);
4964 if (session->last_tx_rst + COAP_TICKS_PER_SECOND/4 < now) {
4966 session->last_tx_rst = now;
4967 }
4968 }
4969 } else {
4970 if (pdu->type == COAP_MESSAGE_CON)
4972 }
4973 }
4974 }
4975
4976cleanup:
4977 if (packet_is_bad) {
4978 if (sent) {
4979 coap_handle_nack(session, sent->pdu, COAP_NACK_BAD_RESPONSE, sent->id);
4980 } else {
4982 }
4983 }
4984 coap_delete_pdu_lkd(orig_pdu);
4986#if COAP_OSCORE_SUPPORT
4987 coap_delete_pdu_lkd(dec_pdu);
4988#endif /* COAP_OSCORE_SUPPORT */
4989}
4990
4991#if COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG
4992static const char *
4994 switch (event) {
4996 return "COAP_EVENT_DTLS_CLOSED";
4998 return "COAP_EVENT_DTLS_CONNECTED";
5000 return "COAP_EVENT_DTLS_RENEGOTIATE";
5002 return "COAP_EVENT_DTLS_ERROR";
5004 return "COAP_EVENT_TCP_CONNECTED";
5006 return "COAP_EVENT_TCP_CLOSED";
5008 return "COAP_EVENT_TCP_FAILED";
5010 return "COAP_EVENT_SESSION_CONNECTED";
5012 return "COAP_EVENT_SESSION_CLOSED";
5014 return "COAP_EVENT_SESSION_FAILED";
5016 return "COAP_EVENT_PARTIAL_BLOCK";
5018 return "COAP_EVENT_XMIT_BLOCK_FAIL";
5020 return "COAP_EVENT_BLOCK_ISSUE";
5022 return "COAP_EVENT_SERVER_SESSION_NEW";
5024 return "COAP_EVENT_SERVER_SESSION_DEL";
5026 return "COAP_EVENT_SERVER_SESSION_CONNECTED";
5028 return "COAP_EVENT_BAD_PACKET";
5030 return "COAP_EVENT_MSG_RETRANSMITTED";
5032 return "COAP_EVENT_FIRST_PDU_FAIL";
5034 return "COAP_EVENT_OSCORE_DECRYPTION_FAILURE";
5036 return "COAP_EVENT_OSCORE_NOT_ENABLED";
5038 return "COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD";
5040 return "COAP_EVENT_OSCORE_NO_SECURITY";
5042 return "COAP_EVENT_OSCORE_INTERNAL_ERROR";
5044 return "COAP_EVENT_OSCORE_DECODE_ERROR";
5046 return "COAP_EVENT_WS_PACKET_SIZE";
5048 return "COAP_EVENT_WS_CONNECTED";
5050 return "COAP_EVENT_WS_CLOSED";
5052 return "COAP_EVENT_KEEPALIVE_FAILURE";
5054 return "COAP_EVENT_RECONNECT_FAILED";
5056 return "COAP_EVENT_RECONNECT_SUCCESS";
5058 return "COAP_EVENT_RECONNECT_NO_MORE";
5060 return "COAP_EVENT_RECONNECT_STARTED";
5061 default:
5062 return "???";
5063 }
5064}
5065#endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG */
5066
5067COAP_API int
5069 coap_session_t *session) {
5070 int ret;
5071
5072 coap_lock_lock(return 0);
5073 ret = coap_handle_event_lkd(context, event, session);
5075 return ret;
5076}
5077
5078int
5080 coap_session_t *session) {
5081 int ret = 0;
5082
5083 coap_log_debug("***EVENT: %s\n", coap_event_name(event));
5084
5085 if (context->event_cb) {
5086 coap_lock_callback_ret(ret, context->event_cb(session, event));
5087#if COAP_PROXY_SUPPORT
5088 if (event == COAP_EVENT_SERVER_SESSION_DEL)
5089 coap_proxy_remove_association(session, 0);
5090#endif /* COAP_PROXY_SUPPORT */
5091#if COAP_CLIENT_SUPPORT
5092 switch (event) {
5107 /* Those that are deemed fatal to end sending a request */
5108 session->doing_send_recv = 0;
5109 break;
5111 /* Session will now be available as well - for call-home */
5112 if (session->type == COAP_SESSION_TYPE_SERVER && session->proto == COAP_PROTO_DTLS) {
5114 session);
5115 }
5116 break;
5122 break;
5124 /* Session will now be available as well - for call-home if not (D)TLS */
5125 if (session->type == COAP_SESSION_TYPE_SERVER &&
5126 (session->proto == COAP_PROTO_TCP || session->proto == COAP_PROTO_TLS)) {
5128 session);
5129 }
5130 break;
5135 break;
5137 /* Session will now be available as well - for call-home if not (D)TLS */
5138 if (session->proto == COAP_PROTO_UDP) {
5140 session);
5141 }
5142 break;
5150 default:
5151 break;
5152 }
5153#endif /* COAP_CLIENT_SUPPORT */
5154 }
5155 return ret;
5156}
5157
5158COAP_API int
5160 int ret;
5161
5162 coap_lock_lock(return 0);
5163 ret = coap_can_exit_lkd(context);
5165 return ret;
5166}
5167
5168int
5170 coap_session_t *s, *rtmp;
5171 if (!context)
5172 return 1;
5174 if (context->sendqueue)
5175 return 0;
5176#if COAP_SERVER_SUPPORT
5177 coap_endpoint_t *ep;
5178
5179 LL_FOREACH(context->endpoint, ep) {
5180 SESSIONS_ITER(ep->sessions, s, rtmp) {
5181 if (s->delayqueue)
5182 return 0;
5183 if (s->lg_xmit)
5184 return 0;
5185 }
5186 }
5187#endif /* COAP_SERVER_SUPPORT */
5188#if COAP_CLIENT_SUPPORT
5189 SESSIONS_ITER(context->sessions, s, rtmp) {
5190 if (s->delayqueue)
5191 return 0;
5192 if (s->lg_xmit)
5193 return 0;
5194 }
5195#endif /* COAP_CLIENT_SUPPORT */
5196 return 1;
5197}
5198#if COAP_SERVER_SUPPORT
5199#if COAP_ASYNC_SUPPORT
5200/*
5201 * Return 1 if there is a future expire time, else 0.
5202 * Update tim_rem with remaining value if return is 1.
5203 */
5204int
5205coap_check_async(coap_context_t *context, coap_tick_t now, coap_tick_t *tim_rem) {
5207 coap_async_t *async, *tmp;
5208 int ret = 0;
5209
5210 if (context->async_state_traversing)
5211 return 0;
5212 context->async_state_traversing = 1;
5213 LL_FOREACH_SAFE(context->async_state, async, tmp) {
5214 if (async->delay != 0 && !async->session->is_rate_limiting) {
5215 if (async->delay <= now) {
5216 /* Send off the request to the application */
5217 coap_log_debug("Async PDU presented to app.\n");
5218 coap_show_pdu(COAP_LOG_DEBUG, async->pdu);
5219 handle_request(context, async->session, async->pdu, NULL);
5220
5221 /* Remove this async entry as it has now fired */
5222 coap_free_async_lkd(async->session, async);
5223 } else {
5224 next_due = async->delay - now;
5225 ret = 1;
5226 }
5227 }
5228 }
5229 if (tim_rem)
5230 *tim_rem = next_due;
5231 context->async_state_traversing = 0;
5232 return ret;
5233}
5234#endif /* COAP_ASYNC_SUPPORT */
5235#endif /* COAP_SERVER_SUPPORT */
5236
5238uint8_t coap_unique_id[8] = { 0 };
5239
5240#if COAP_THREAD_SAFE
5241/*
5242 * Global lock for multi-thread support
5243 */
5244coap_lock_t global_lock;
5245/*
5246 * low level protection mutex
5247 */
5248coap_mutex_t m_show_pdu;
5249coap_mutex_t m_log_impl;
5250coap_mutex_t m_io_threads;
5251#endif /* COAP_THREAD_SAFE */
5252
5253void
5255 coap_tick_t now;
5256#ifndef WITH_CONTIKI
5257 uint64_t us;
5258#endif /* !WITH_CONTIKI */
5259
5260 if (coap_started)
5261 return;
5262 coap_started = 1;
5263
5264#if COAP_THREAD_SAFE
5265 coap_lock_init(&global_lock);
5266 coap_mutex_init(&m_show_pdu);
5267 coap_mutex_init(&m_log_impl);
5268 coap_mutex_init(&m_io_threads);
5269#endif /* COAP_THREAD_SAFE */
5270
5271#if defined(HAVE_WINSOCK2_H)
5272 WORD wVersionRequested = MAKEWORD(2, 2);
5273 WSADATA wsaData;
5274 WSAStartup(wVersionRequested, &wsaData);
5275#endif
5277 coap_ticks(&now);
5278#ifndef WITH_CONTIKI
5279 us = coap_ticks_to_rt_us(now);
5280 /* Be accurate to the nearest (approx) us */
5281 coap_prng_init_lkd((unsigned int)us);
5282#else /* WITH_CONTIKI */
5283 coap_start_io_process();
5284#endif /* WITH_CONTIKI */
5287#ifdef WITH_LWIP
5288 coap_io_lwip_init();
5289#endif /* WITH_LWIP */
5290#if COAP_SERVER_SUPPORT
5291 static coap_str_const_t well_known = { sizeof(".well-known/core")-1,
5292 (const uint8_t *)".well-known/core"
5293 };
5294 memset(&resource_uri_wellknown, 0, sizeof(resource_uri_wellknown));
5295 resource_uri_wellknown.ref = 1;
5296 resource_uri_wellknown.handler[COAP_REQUEST_GET-1] = hnd_get_wellknown_lkd;
5297 resource_uri_wellknown.flags = COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT;
5298 resource_uri_wellknown.uri_path = &well_known;
5299#endif /* COAP_SERVER_SUPPORT */
5302}
5303
5304void
5306 if (!coap_started)
5307 return;
5308 coap_started = 0;
5309#if defined(HAVE_WINSOCK2_H)
5310 WSACleanup();
5311#elif defined(WITH_CONTIKI)
5312 coap_stop_io_process();
5313#endif
5314#ifdef WITH_LWIP
5315 coap_io_lwip_cleanup();
5316#endif /* WITH_LWIP */
5318
5319#if COAP_THREAD_SAFE
5320 coap_mutex_destroy(&m_show_pdu);
5321 coap_mutex_destroy(&m_log_impl);
5322 coap_mutex_destroy(&m_io_threads);
5323#endif /* COAP_THREAD_SAFE */
5324
5326}
5327
5328void
5330 coap_response_handler_t handler) {
5331#if COAP_CLIENT_SUPPORT
5332 context->response_cb = handler;
5333#else /* ! COAP_CLIENT_SUPPORT */
5334 (void)context;
5335 (void)handler;
5336#endif /* ! COAP_CLIENT_SUPPORT */
5337}
5338
5339void
5342#if COAP_PROXY_SUPPORT
5343 context->proxy_response_cb = handler;
5344#else /* ! COAP_PROXY_SUPPORT */
5345 (void)context;
5346 (void)handler;
5347#endif /* ! COAP_PROXY_SUPPORT */
5348}
5349
5350void
5352 coap_nack_handler_t handler) {
5353 context->nack_cb = handler;
5354}
5355
5356void
5358 coap_ping_handler_t handler) {
5359 context->ping_cb = handler;
5360}
5361
5362void
5364 coap_pong_handler_t handler) {
5365 context->pong_cb = handler;
5366}
5367
5368void
5370 coap_resource_dynamic_create_t dyn_create_handler,
5371 uint32_t dynamic_max) {
5372 context->dyn_create_handler = dyn_create_handler;
5373 context->dynamic_max = dynamic_max;
5374 return;
5375}
5376
5377COAP_API void
5379 coap_lock_lock(return);
5380 coap_register_option_lkd(ctx, type);
5382}
5383
5384void
5387}
5388
5389#if ! defined WITH_CONTIKI && ! defined WITH_LWIP && ! defined RIOT_VERSION && !defined(__ZEPHYR__)
5390#if COAP_SERVER_SUPPORT
5391COAP_API int
5392coap_join_mcast_group_intf(coap_context_t *ctx, const char *group_name,
5393 const char *ifname) {
5394 int ret;
5395
5396 coap_lock_lock(return -1);
5397 ret = coap_join_mcast_group_intf_lkd(ctx, group_name, ifname);
5399 return ret;
5400}
5401
5402int
5403coap_join_mcast_group_intf_lkd(coap_context_t *ctx, const char *group_name,
5404 const char *ifname) {
5405#if COAP_IPV4_SUPPORT
5406 struct ip_mreq mreq4;
5407#endif /* COAP_IPV4_SUPPORT */
5408#if COAP_IPV6_SUPPORT
5409 struct ipv6_mreq mreq6;
5410#endif /* COAP_IPV6_SUPPORT */
5411 struct addrinfo *resmulti = NULL, hints, *ainfo;
5412 int result = -1;
5413 coap_endpoint_t *endpoint;
5414 int mgroup_setup = 0;
5415
5416 /* Need to have at least one endpoint! */
5417 assert(ctx->endpoint);
5418 if (!ctx->endpoint)
5419 return -1;
5420
5421 /* Default is let the kernel choose */
5422#if COAP_IPV6_SUPPORT
5423 mreq6.ipv6mr_interface = 0;
5424#endif /* COAP_IPV6_SUPPORT */
5425#if COAP_IPV4_SUPPORT
5426 mreq4.imr_interface.s_addr = INADDR_ANY;
5427#endif /* COAP_IPV4_SUPPORT */
5428
5429 memset(&hints, 0, sizeof(hints));
5430 hints.ai_socktype = SOCK_DGRAM;
5431
5432 /* resolve the multicast group address */
5433 result = getaddrinfo(group_name, NULL, &hints, &resmulti);
5434
5435 if (result != 0) {
5436 coap_log_err("coap_join_mcast_group_intf: %s: "
5437 "Cannot resolve multicast address: %s\n",
5438 group_name, gai_strerror(result));
5439 goto finish;
5440 }
5441
5442 /* Need to do a windows equivalent at some point */
5443#ifndef _WIN32
5444 if (ifname) {
5445 /* interface specified - check if we have correct IPv4/IPv6 information */
5446 int done_ip4 = 0;
5447 int done_ip6 = 0;
5448#if defined(ESPIDF_VERSION)
5449 struct netif *netif;
5450#else /* !ESPIDF_VERSION */
5451#if COAP_IPV4_SUPPORT
5452 int ip4fd;
5453#endif /* COAP_IPV4_SUPPORT */
5454 struct ifreq ifr;
5455#endif /* !ESPIDF_VERSION */
5456
5457 /* See which mcast address family types are being asked for */
5458 for (ainfo = resmulti; ainfo != NULL && !(done_ip4 == 1 && done_ip6 == 1);
5459 ainfo = ainfo->ai_next) {
5460 switch (ainfo->ai_family) {
5461#if COAP_IPV6_SUPPORT
5462 case AF_INET6:
5463 if (done_ip6)
5464 break;
5465 done_ip6 = 1;
5466#if defined(ESPIDF_VERSION)
5467 netif = netif_find(ifname);
5468 if (netif)
5469 mreq6.ipv6mr_interface = netif_get_index(netif);
5470 else
5471 coap_log_err("coap_join_mcast_group_intf: %s: "
5472 "Cannot get IPv4 address: %s\n",
5473 ifname, coap_socket_strerror());
5474#else /* !ESPIDF_VERSION */
5475 memset(&ifr, 0, sizeof(ifr));
5476 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
5477 ifr.ifr_name[IFNAMSIZ - 1] = '\000';
5478
5479#ifdef HAVE_IF_NAMETOINDEX
5480 mreq6.ipv6mr_interface = if_nametoindex(ifr.ifr_name);
5481 if (mreq6.ipv6mr_interface == 0) {
5482 coap_log_warn("coap_join_mcast_group_intf: "
5483 "cannot get interface index for '%s'\n",
5484 ifname);
5485 }
5486#elif defined(__QNXNTO__)
5487#else /* !HAVE_IF_NAMETOINDEX */
5488 result = ioctl(ctx->endpoint->sock.fd, SIOCGIFINDEX, &ifr);
5489 if (result != 0) {
5490 coap_log_warn("coap_join_mcast_group_intf: "
5491 "cannot get interface index for '%s': %s\n",
5492 ifname, coap_socket_strerror());
5493 } else {
5494 /* Capture the IPv6 if_index for later */
5495 mreq6.ipv6mr_interface = ifr.ifr_ifindex;
5496 }
5497#endif /* !HAVE_IF_NAMETOINDEX */
5498#endif /* !ESPIDF_VERSION */
5499#endif /* COAP_IPV6_SUPPORT */
5500 break;
5501#if COAP_IPV4_SUPPORT
5502 case AF_INET:
5503 if (done_ip4)
5504 break;
5505 done_ip4 = 1;
5506#if defined(ESPIDF_VERSION)
5507 netif = netif_find(ifname);
5508 if (netif)
5509 mreq4.imr_interface.s_addr = netif_ip4_addr(netif)->addr;
5510 else
5511 coap_log_err("coap_join_mcast_group_intf: %s: "
5512 "Cannot get IPv4 address: %s\n",
5513 ifname, coap_socket_strerror());
5514#else /* !ESPIDF_VERSION */
5515 /*
5516 * Need an AF_INET socket to do this unfortunately to stop
5517 * "Invalid argument" error if AF_INET6 socket is used for SIOCGIFADDR
5518 */
5519 ip4fd = socket(AF_INET, SOCK_DGRAM, 0);
5520 if (ip4fd == -1) {
5521 coap_log_err("coap_join_mcast_group_intf: %s: socket: %s\n",
5522 ifname, coap_socket_strerror());
5523 continue;
5524 }
5525 memset(&ifr, 0, sizeof(ifr));
5526 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
5527 ifr.ifr_name[IFNAMSIZ - 1] = '\000';
5528 result = ioctl(ip4fd, SIOCGIFADDR, &ifr);
5529 if (result != 0) {
5530 coap_log_err("coap_join_mcast_group_intf: %s: "
5531 "Cannot get IPv4 address: %s\n",
5532 ifname, coap_socket_strerror());
5533 } else {
5534 /* Capture the IPv4 address for later */
5535 mreq4.imr_interface = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
5536 }
5537 close(ip4fd);
5538#endif /* !ESPIDF_VERSION */
5539 break;
5540#endif /* COAP_IPV4_SUPPORT */
5541 default:
5542 break;
5543 }
5544 }
5545 }
5546#else /* _WIN32 */
5547 /*
5548 * On Windows this function ignores the ifname variable so we unset this
5549 * variable on this platform in any case in order to enable the interface
5550 * selection from the bind address below.
5551 */
5552 ifname = 0;
5553#endif /* _WIN32 */
5554
5555 /* Add in mcast address(es) to appropriate interface */
5556 for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
5557 LL_FOREACH(ctx->endpoint, endpoint) {
5558 /* Only UDP currently supported */
5559 if (endpoint->proto == COAP_PROTO_UDP) {
5560 coap_address_t gaddr;
5561
5562 coap_address_init(&gaddr);
5563#if COAP_IPV6_SUPPORT
5564 if (ainfo->ai_family == AF_INET6) {
5565 if (!ifname) {
5566 if (endpoint->bind_addr.addr.sa.sa_family == AF_INET6) {
5567 /*
5568 * Do it on the ifindex that the server is listening on
5569 * (sin6_scope_id could still be 0)
5570 */
5571 mreq6.ipv6mr_interface =
5572 endpoint->bind_addr.addr.sin6.sin6_scope_id;
5573 } else {
5574 mreq6.ipv6mr_interface = 0;
5575 }
5576 }
5577 gaddr.addr.sin6.sin6_family = AF_INET6;
5578 gaddr.addr.sin6.sin6_port = endpoint->bind_addr.addr.sin6.sin6_port;
5579 gaddr.addr.sin6.sin6_addr = mreq6.ipv6mr_multiaddr =
5580 ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
5581 result = setsockopt(endpoint->sock.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
5582 (char *)&mreq6, sizeof(mreq6));
5583 }
5584#endif /* COAP_IPV6_SUPPORT */
5585#if COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT
5586 else
5587#endif /* COAP_IPV4_SUPPORT && COAP_IPV6_SUPPORT */
5588#if COAP_IPV4_SUPPORT
5589 if (ainfo->ai_family == AF_INET) {
5590 if (!ifname) {
5591 if (endpoint->bind_addr.addr.sa.sa_family == AF_INET) {
5592 /*
5593 * Do it on the interface that the server is listening on
5594 * (sin_addr could still be INADDR_ANY)
5595 */
5596 mreq4.imr_interface = endpoint->bind_addr.addr.sin.sin_addr;
5597 } else {
5598 mreq4.imr_interface.s_addr = INADDR_ANY;
5599 }
5600 }
5601 gaddr.addr.sin.sin_family = AF_INET;
5602 gaddr.addr.sin.sin_port = endpoint->bind_addr.addr.sin.sin_port;
5603 gaddr.addr.sin.sin_addr.s_addr = mreq4.imr_multiaddr.s_addr =
5604 ((struct sockaddr_in *)ainfo->ai_addr)->sin_addr.s_addr;
5605 result = setsockopt(endpoint->sock.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
5606 (char *)&mreq4, sizeof(mreq4));
5607 }
5608#endif /* COAP_IPV4_SUPPORT */
5609 else {
5610 continue;
5611 }
5612
5613 if (result == COAP_SOCKET_ERROR) {
5614 coap_log_err("coap_join_mcast_group_intf: %s: setsockopt: %s\n",
5615 group_name, coap_socket_strerror());
5616 } else {
5617 char addr_str[INET6_ADDRSTRLEN + 8 + 1];
5618
5619 addr_str[sizeof(addr_str)-1] = '\000';
5620 if (coap_print_addr(&gaddr, (uint8_t *)addr_str,
5621 sizeof(addr_str) - 1)) {
5622 if (ifname)
5623 coap_log_debug("added mcast group %s i/f %s\n", addr_str,
5624 ifname);
5625 else
5626 coap_log_debug("added mcast group %s\n", addr_str);
5627 }
5628 mgroup_setup = 1;
5629 }
5630 }
5631 }
5632 }
5633 if (!mgroup_setup) {
5634 result = -1;
5635 }
5636
5637finish:
5638 freeaddrinfo(resmulti);
5639
5640 return result;
5641}
5642
5643void
5645 context->mcast_per_resource = 1;
5646}
5647
5648#endif /* ! COAP_SERVER_SUPPORT */
5649
5650#if COAP_CLIENT_SUPPORT
5651int
5652coap_mcast_set_hops(coap_session_t *session, size_t hops) {
5653 if (session && coap_is_mcast(&session->addr_info.remote)) {
5654 switch (session->addr_info.remote.addr.sa.sa_family) {
5655#if COAP_IPV4_SUPPORT
5656 case AF_INET:
5657 if (setsockopt(session->sock.fd, IPPROTO_IP, IP_MULTICAST_TTL,
5658 (const char *)&hops, sizeof(hops)) < 0) {
5659 coap_log_info("coap_mcast_set_hops: %" PRIuS ": setsockopt: %s\n",
5660 hops, coap_socket_strerror());
5661 return 0;
5662 }
5663 return 1;
5664#endif /* COAP_IPV4_SUPPORT */
5665#if COAP_IPV6_SUPPORT
5666 case AF_INET6:
5667 if (setsockopt(session->sock.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
5668 (const char *)&hops, sizeof(hops)) < 0) {
5669 coap_log_info("coap_mcast_set_hops: %" PRIuS ": setsockopt: %s\n",
5670 hops, coap_socket_strerror());
5671 return 0;
5672 }
5673 return 1;
5674#endif /* COAP_IPV6_SUPPORT */
5675 default:
5676 break;
5677 }
5678 }
5679 return 0;
5680}
5681#endif /* COAP_CLIENT_SUPPORT */
5682
5683#else /* defined WITH_CONTIKI || defined WITH_LWIP || defined RIOT_VERSION || defined(__ZEPHYR__) */
5684COAP_API int
5686 const char *group_name COAP_UNUSED,
5687 const char *ifname COAP_UNUSED) {
5688 return -1;
5689}
5690
5691int
5693 size_t hops COAP_UNUSED) {
5694 return 0;
5695}
5696
5697void
5699}
5700#endif /* defined WITH_CONTIKI || defined WITH_LWIP || defined RIOT_VERSION || defined(__ZEPHYR__) */
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
void coap_debug_reset(void)
Reset all the defined logging parameters.
struct coap_lg_crcv_t coap_lg_crcv_t
struct coap_endpoint_t coap_endpoint_t
struct coap_async_t coap_async_t
Async Entry information.
struct coap_cache_entry_t coap_cache_entry_t
struct coap_proxy_entry_t coap_proxy_entry_t
Proxy information.
struct coap_subscription_t coap_subscription_t
struct coap_resource_t coap_resource_t
struct coap_lg_srcv_t coap_lg_srcv_t
#define PRIuS
#define PRIdS
#define PRIu32
const char * coap_socket_strerror(void)
Definition coap_io.c:940
void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
Given a packet, set msg and msg_len to an address and length of the packet's data in memory.
Definition coap_io.c:203
void coap_update_io_timer(coap_context_t *context, coap_tick_t delay)
Update when to continue with I/O processing, unless packets come in in the meantime.
Definition coap_io.c:70
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:31
#define COAP_SOCKET_ERROR
Definition coap_io.h:51
coap_nack_reason_t
Definition coap_io.h:64
@ COAP_NACK_NOT_DELIVERABLE
Definition coap_io.h:66
@ COAP_NACK_TOO_MANY_RETRIES
Definition coap_io.h:65
@ COAP_NACK_ICMP_ISSUE
Definition coap_io.h:69
@ COAP_NACK_RST
Definition coap_io.h:67
@ COAP_NACK_BAD_RESPONSE
Definition coap_io.h:70
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
#define COAP_SOCKET_NOT_EMPTY
the socket is not empty
#define COAP_SOCKET_CAN_WRITE
non blocking socket can now write without blocking
#define COAP_SOCKET_BOUND
the socket is bound
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
#define COAP_SOCKET_CAN_ACCEPT
non blocking server socket can now accept without blocking
#define COAP_SOCKET_WANT_WRITE
non blocking socket is waiting for writing
#define COAP_SOCKET_CAN_CONNECT
non blocking client socket can now connect without blocking
void coap_epoll_ctl_mod(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to modify the state of events that epoll is tracking on the appropriate file ...
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
#define COAP_SOCKET_CONNECTED
the socket is connected
@ COAP_LAYER_SESSION
Library specific build wrapper for coap_internal.h.
#define COAP_API
void coap_dump_memory_type_counts(coap_log_t level)
Dumps the current usage of malloc'd memory types.
Definition coap_mem.c:748
void coap_memory_init(void)
Initializes libcoap's memory management.
@ COAP_NODE
Definition coap_mem.h:37
@ COAP_CONTEXT
Definition coap_mem.h:38
@ COAP_STRING
Definition coap_mem.h:33
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.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
CoAP mutex mechanism wrapper.
#define coap_mutex_init(a)
int coap_mutex_t
#define coap_mutex_destroy(a)
#define FRAC_BITS
The number of bits for the fractional part of ACK_TIMEOUT and ACK_RANDOM_FACTOR.
Definition coap_net.c:83
static ssize_t coap_send_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node)
Definition coap_net.c:1147
static int send_recv_terminate
Definition coap_net.c:2195
static int coap_remove_from_queue_token(coap_queue_t **queue, coap_session_t *session, coap_bin_const_t *token, coap_queue_t **node)
Definition coap_net.c:3103
#define MAX_BITS
The maximum number of bits for fixed point integers that are used for retransmission time calculation...
Definition coap_net.c:89
void coap_cleanup(void)
Definition coap_net.c:5305
#define ACK_TIMEOUT
creates a Qx.FRAC_BITS from session's 'ack_timeout'
Definition coap_net.c:104
static const char * coap_event_name(coap_event_t event)
Definition coap_net.c:4993
static int coap_cancel(coap_context_t *context, const coap_queue_t *sent)
This function cancels outstanding messages for the session and token specified in sent.
Definition coap_net.c:3419
int coap_started
Definition coap_net.c:5237
static int coap_handle_dgram_for_proto(coap_context_t *ctx, coap_session_t *session, coap_packet_t *packet)
Definition coap_net.c:2480
static void coap_write_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now)
Definition coap_net.c:2521
COAP_STATIC_INLINE void coap_free_node(coap_queue_t *node)
Definition coap_net.c:112
#define SHR_FP(val, frac)
static void handle_signaling(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu)
Definition coap_net.c:4406
#define min(a, b)
Definition coap_net.c:76
static int prepend_508_ip(coap_session_t *session, coap_pdu_t *pdu)
Definition coap_net.c:1897
void coap_startup(void)
Definition coap_net.c:5254
static int check_token_size(coap_session_t *session, const coap_pdu_t *pdu)
Definition coap_net.c:4483
static unsigned int s_csm_timeout
Definition coap_net.c:531
COAP_STATIC_INLINE coap_queue_t * coap_malloc_node(void)
Definition coap_net.c:107
uint8_t coap_unique_id[8]
Definition coap_net.c:5238
#define FP1
#define ACK_RANDOM_FACTOR
creates a Qx.FRAC_BITS from session's 'ack_random_factor'
Definition coap_net.c:100
#define INET6_ADDRSTRLEN
Definition coap_net.c:72
int coap_dtls_context_set_pki(coap_context_t *ctx COAP_UNUSED, const coap_dtls_pki_t *setup_data COAP_UNUSED, const coap_dtls_role_t role COAP_UNUSED)
Definition coap_notls.c:108
int coap_dtls_receive(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
Definition coap_notls.c:247
int coap_dtls_context_load_pki_trust_store(coap_context_t *ctx COAP_UNUSED)
Definition coap_notls.c:124
int coap_dtls_context_set_pki_root_cas(coap_context_t *ctx COAP_UNUSED, const char *ca_file COAP_UNUSED, const char *ca_path COAP_UNUSED)
Definition coap_notls.c:116
void coap_dtls_free_context(void *handle COAP_UNUSED)
Definition coap_notls.c:190
void * coap_dtls_new_context(coap_context_t *coap_context COAP_UNUSED)
Definition coap_notls.c:185
#define NULL
Definition coap_option.h:30
uint16_t coap_option_num_t
Definition coap_option.h:37
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:43
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
void coap_io_do_epoll_lkd(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition coap_net.c:2889
void coap_reset_doing_first(coap_session_t *session)
Reset doing the first packet state when testing for optional functionality.
coap_mid_t coap_send_rst_lkd(coap_session_t *session, const coap_pdu_t *request)
Sends an RST message with code 0 for the specified request to dst.
Definition coap_net.c:1104
coap_mid_t coap_send_message_type_lkd(coap_session_t *session, const coap_pdu_t *request, coap_pdu_type_t type)
Helper function to create and send a message with type (usually ACK or RST).
Definition coap_net.c:1228
coap_mid_t coap_send_error_lkd(coap_session_t *session, const coap_pdu_t *request, coap_pdu_code_t code, coap_opt_filter_t *opts)
Sends an error response with code code for request request to dst.
Definition coap_net.c:1199
void coap_io_do_io_lkd(coap_context_t *ctx, coap_tick_t now)
Processes any outstanding read, write, accept or connect I/O as indicated in the coap_socket_t struct...
Definition coap_net.c:2819
int coap_send_recv_lkd(coap_session_t *session, coap_pdu_t *request_pdu, coap_pdu_t **response_pdu, uint32_t timeout_ms)
Definition coap_net.c:2224
void coap_io_process_remove_threads_lkd(coap_context_t *context)
Release the coap_io_process() worker threads.
int coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
void coap_call_response_handler(coap_session_t *session, coap_pdu_t *sent, coap_pdu_t *rcvd, void *body_free)
unsigned int coap_io_prepare_epoll_lkd(coap_context_t *ctx, coap_tick_t now)
Any now timed out delayed packet is transmitted, along with any packets associated with requested obs...
Definition coap_io.c:219
coap_mid_t coap_send_lkd(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:1508
coap_mid_t coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request)
Sends an ACK message with code 0 for the specified request to dst.
Definition coap_net.c:1119
#define COAP_IO_NO_WAIT
Definition coap_net.h:841
#define COAP_IO_WAIT
Definition coap_net.h:840
COAP_API void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition coap_net.c:2878
COAP_API void coap_io_do_io(coap_context_t *ctx, coap_tick_t now)
Processes any outstanding read, write, accept or connect I/O as indicated in the coap_socket_t struct...
Definition coap_net.c:2812
void coap_check_code_lg_xmit(const coap_session_t *session, const coap_pdu_t *request, coap_pdu_t *response, const coap_resource_t *resource, const coap_string_t *query)
The function checks that the code in a newly formed lg_xmit created by coap_add_data_large_response_l...
#define STATE_TOKEN_BASE(t)
@ COAP_RECURSE_OK
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
Definition coap_block.h:95
#define COAP_BLOCK_TRY_Q_BLOCK
Definition coap_block.h:67
#define COAP_BLOCK_SINGLE_BODY
Definition coap_block.h:66
int coap_get_block_b(const coap_session_t *session, const coap_pdu_t *pdu, coap_option_num_t number, coap_block_b_t *block)
Initializes block from pdu.
Definition coap_block.c:64
#define COAP_BLOCK_NO_PREEMPTIVE_RTAG
Definition coap_block.h:69
#define COAP_BLOCK_CACHE_RESPONSE
Definition coap_block.h:73
#define COAP_BLOCK_USE_LIBCOAP
Definition coap_block.h:65
void coap_delete_cache_entry(coap_context_t *context, coap_cache_entry_t *cache_entry)
Remove a cache-entry from the hash list and free off all the appropriate contents apart from app_data...
int64_t coap_tick_diff_t
This data type is used to represent the difference between two clock_tick_t values.
Definition coap_time.h:161
void coap_clock_init(void)
Initializes the internal clock.
Definition coap_time.c:68
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:149
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition coap_time.h:164
#define COAP_MAX_DELAY_TICKS
Definition coap_time.h:231
uint64_t coap_ticks_to_rt_us(coap_tick_t t)
Helper function that converts coap ticks to POSIX wallclock time in us.
Definition coap_time.c:128
void coap_prng_init_lkd(unsigned int seed)
Seeds the default random number generation function with the given seed.
Definition coap_prng.c:178
int coap_prng_lkd(void *buf, size_t len)
Fills buf with len random bytes using the default pseudo random number generator.
Definition coap_prng.c:190
#define COAP_RESOURCE_HANDLE_WELLKNOWN_CORE
Define this when invoking coap_resource_unknown_init2() if .well-known/core is to be passed to the un...
#define COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT
This resource has support for multicast requests.
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_4_XX
Disable libcoap library suppressing 4.xx multicast responses (overridden by RFC7969 No-Response optio...
#define COAP_RESOURCE_SAFE_REQUEST_HANDLER
Don't lock this resource when calling app call-back handler for requests as handler will not be manip...
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYS
Disable libcoap library from adding in delays to multicast requests before releasing the response bac...
void(* coap_method_handler_t)(coap_resource_t *resource, coap_session_t *session, const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response)
Definition of message handler function.
#define COAP_RESOURCE_FLAGS_OSCORE_ONLY
Define this resource as an OSCORE enabled access only.
#define COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_5_XX
Disable libcoap library suppressing 5.xx multicast responses (overridden by RFC7969 No-Response optio...
uint32_t coap_print_status_t
Status word to encode the result of conditional print or copy operations such as coap_print_link().
#define COAP_PRINT_STATUS_ERROR
#define COAP_RESOURCE_FLAGS_FORCE_SINGLE_BODY
Force all large traffic to this resource to be presented as a single body to the request handler.
#define COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_05
Enable libcoap library suppression of 205 multicast responses that are empty (overridden by RFC7969 N...
#define COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_XX
Enable libcoap library suppressing 2.xx multicast responses (overridden by RFC7969 No-Response option...
int coap_handle_event_lkd(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:5079
uint16_t coap_new_message_id_lkd(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now)
Set sendqueue_basetime in the given context object ctx to now.
Definition coap_net.c:117
int coap_delete_node_lkd(coap_queue_t *node)
Destroys specified node.
Definition coap_net.c:214
void coap_delete_all(coap_queue_t *queue)
Removes all items from given queue and frees the allocated storage.
Definition coap_net.c:234
int coap_context_set_psk2_lkd(coap_context_t *context, coap_dtls_spsk_t *setup_data)
Set the context's default PSK hint and/or key for a server.
void coap_register_option_lkd(coap_context_t *ctx, uint16_t type)
Registers the option number number with the given context object context.
Definition coap_net.c:5385
int coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_mid_t id, coap_queue_t **node)
This function removes the element with given id from the list given list.
Definition coap_net.c:3055
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition coap_net.c:257
COAP_API int coap_delete_node(coap_queue_t *node)
Destroys specified node.
Definition coap_net.c:191
int coap_client_delay_first(coap_session_t *session)
Delay the sending of the first client request until some other negotiation has completed.
Definition coap_net.c:1376
int coap_context_set_psk_lkd(coap_context_t *context, const char *hint, const uint8_t *key, size_t key_len)
Set the context's default PSK hint and/or key for a server.
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition coap_net.c:265
void coap_dispatch(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu)
Dispatches the PDUs from the receive queue in given context.
Definition coap_net.c:4516
int coap_insert_node(coap_queue_t **queue, coap_queue_t *node)
Adds node to given queue, ordered by variable t in node.
Definition coap_net.c:154
unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r)
Calculates the initial timeout based on the session CoAP transmission parameters 'ack_timeout',...
Definition coap_net.c:1256
int coap_join_mcast_group_intf_lkd(coap_context_t *ctx, const char *groupname, const char *ifname)
Function interface for joining a multicast group for listening for the currently defined endpoints th...
void coap_free_context_lkd(coap_context_t *context)
CoAP stack context must be released with coap_free_context_lkd().
Definition coap_net.c:841
int coap_context_load_pki_trust_store_lkd(coap_context_t *ctx)
Load the context's default trusted CAs for a client or server.
Definition coap_net.c:455
coap_mid_t coap_send_internal(coap_session_t *session, coap_pdu_t *pdu, coap_pdu_t *request_pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:2007
void * coap_context_set_app_data2_lkd(coap_context_t *context, void *app_data, coap_app_data_free_callback_t callback)
Stores data with the given context, returning the previously stored value or NULL.
Definition coap_net.c:718
int coap_can_exit_lkd(coap_context_t *context)
Returns 1 if there are no messages to send or to dispatch in the context's queues.
Definition coap_net.c:5169
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition coap_net.c:2342
int coap_check_code_class(coap_session_t *session, coap_pdu_t *pdu)
Check whether the pdu contains a valid code class.
Definition coap_net.c:1443
int coap_context_set_pki_root_cas_lkd(coap_context_t *ctx, const char *ca_file, const char *ca_dir)
Set the context's default Root CA information for a client or server.
Definition coap_net.c:435
int coap_option_check_critical(coap_session_t *session, coap_pdu_t *pdu, coap_opt_filter_t *unknown)
Verifies that pdu contains no unknown critical options, duplicate options or the options defined as R...
Definition coap_net.c:944
coap_mid_t coap_wait_ack(coap_context_t *context, coap_session_t *session, coap_queue_t *node)
Definition coap_net.c:1282
coap_queue_t * coap_new_node(void)
Creates a new node suitable for adding to the CoAP sendqueue.
Definition coap_net.c:243
void coap_cancel_session_messages(coap_context_t *context, coap_session_t *session, coap_nack_reason_t reason)
Cancels all outstanding messages for session session.
Definition coap_net.c:3162
int coap_context_set_pki_lkd(coap_context_t *context, const coap_dtls_pki_t *setup_data)
Set the context's default PKI information for a server.
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *msg, size_t msg_len)
Parses and interprets a CoAP datagram with context ctx.
Definition coap_net.c:2994
void coap_cancel_all_messages(coap_context_t *context, coap_session_t *session, coap_bin_const_t *token)
Cancels all outstanding messages for session session that have the specified token.
Definition coap_net.c:3201
void coap_context_set_session_timeout(coap_context_t *context, unsigned int session_timeout)
Set the session timeout value.
Definition coap_net.c:580
unsigned int coap_context_get_max_handshake_sessions(const coap_context_t *context)
Get the session timeout value.
Definition coap_net.c:527
COAP_API int coap_join_mcast_group_intf(coap_context_t *ctx, const char *groupname, const char *ifname)
Function interface for joining a multicast group for listening for the currently defined endpoints th...
void(* coap_pong_handler_t)(coap_session_t *session, const coap_pdu_t *received, const coap_mid_t mid)
Received Pong handler that is used as callback in coap_context_t.
Definition coap_net.h:103
unsigned int coap_context_get_max_idle_sessions(const coap_context_t *context)
Get the maximum idle sessions count.
Definition coap_net.c:516
COAP_API int coap_send_recv(coap_session_t *session, coap_pdu_t *request_pdu, coap_pdu_t **response_pdu, uint32_t timeout_ms)
Definition coap_net.c:2203
coap_context_t * coap_new_context(const coap_address_t *listen_addr)
Creates a new coap_context_t object that will hold the CoAP stack status.
Definition coap_net.c:728
COAP_API coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:1498
COAP_API int coap_context_set_pki(coap_context_t *context, const coap_dtls_pki_t *setup_data)
Set the context's default PKI information for a server.
void coap_mcast_per_resource(coap_context_t *context)
Function interface to enable processing mcast requests on a per resource basis.
coap_response_t(* coap_response_handler_t)(coap_session_t *session, const coap_pdu_t *sent, const coap_pdu_t *received, const coap_mid_t mid)
Response handler that is used as callback in coap_context_t.
Definition coap_net.h:67
void coap_context_set_max_body_size(coap_context_t *context, uint32_t max_body_size)
Set the maximum supported body size.
Definition coap_net.c:490
COAP_API coap_mid_t coap_send_error(coap_session_t *session, const coap_pdu_t *request, coap_pdu_code_t code, coap_opt_filter_t *opts)
Sends an error response with code code for request request to dst.
Definition coap_net.c:1186
void coap_context_rate_limit_ppm(coap_context_t *context, uint64_t rate_limit_ppm)
Set the ratelimit for packets per minute.
Definition coap_net.c:480
void coap_context_set_csm_max_message_size(coap_context_t *context, uint32_t csm_max_message_size)
Set the CSM max session size value.
Definition coap_net.c:562
void coap_context_set_csm_timeout(coap_context_t *context, unsigned int csm_timeout)
Set the CSM timeout value.
Definition coap_net.c:534
void coap_send_recv_terminate(void)
Terminate any active coap_send_recv() sessions.
Definition coap_net.c:2198
coap_resource_t *(* coap_resource_dynamic_create_t)(coap_session_t *session, const coap_pdu_t *request)
Definition of resource dynamic creation handler function.
Definition coap_net.h:115
void coap_register_response_handler(coap_context_t *context, coap_response_handler_t handler)
Registers a new message handler that is called whenever a response is received.
Definition coap_net.c:5329
COAP_API void * coap_context_set_app_data2(coap_context_t *context, void *app_data, coap_app_data_free_callback_t callback)
Stores data with the given context, returning the previously stored value or NULL.
Definition coap_net.c:707
coap_pdu_t * coap_new_error_response(const coap_pdu_t *request, coap_pdu_code_t code, coap_opt_filter_t *opts)
Creates a new ACK PDU with specified error code.
Definition coap_net.c:3234
void coap_context_set_max_handshake_sessions(coap_context_t *context, unsigned int max_handshake_sessions)
Set the maximum number of sessions in (D)TLS handshake value.
Definition coap_net.c:521
int coap_context_get_coap_fd(const coap_context_t *context)
Get the libcoap internal file descriptor for using in an application's select() or returned as an eve...
Definition coap_net.c:620
void coap_register_dynamic_resource_handler(coap_context_t *context, coap_resource_dynamic_create_t dyn_create_handler, uint32_t dynamic_max)
Sets up a handler for calling when an unknown resource is requested.
Definition coap_net.c:5369
COAP_API void coap_set_app_data(coap_context_t *context, void *app_data)
Definition coap_net.c:818
int coap_mcast_set_hops(coap_session_t *session, size_t hops)
Function interface for defining the hop count (ttl) for sending multicast traffic.
coap_response_t
Definition coap_net.h:51
void(* coap_ping_handler_t)(coap_session_t *session, const coap_pdu_t *received, const coap_mid_t mid)
Received Ping handler that is used as callback in coap_context_t.
Definition coap_net.h:92
void coap_ticks(coap_tick_t *t)
Returns the current value of an internal tick counter.
Definition coap_time.c:90
COAP_API void coap_free_context(coap_context_t *context)
CoAP stack context must be released with coap_free_context().
Definition coap_net.c:832
void(* coap_nack_handler_t)(coap_session_t *session, const coap_pdu_t *sent, const coap_nack_reason_t reason, const coap_mid_t mid)
Negative Acknowedge handler that is used as callback in coap_context_t.
Definition coap_net.h:80
void coap_context_set_shutdown_no_observe(coap_context_t *context)
Definition coap_net.c:611
void * coap_context_get_app_data(const coap_context_t *context)
Returns any application-specific data that has been stored with context using the function coap_conte...
Definition coap_net.c:701
COAP_API int coap_context_set_pki_root_cas(coap_context_t *ctx, const char *ca_file, const char *ca_dir)
Set the context's default Root CA information for a client or server.
Definition coap_net.c:423
COAP_API void coap_context_set_app_data(coap_context_t *context, void *app_data)
Stores data with the given context.
Definition coap_net.c:693
uint32_t coap_context_get_csm_max_message_size(const coap_context_t *context)
Get the CSM max session size value.
Definition coap_net.c:575
unsigned int coap_context_get_session_timeout(const coap_context_t *context)
Get the session timeout value.
Definition coap_net.c:606
COAP_API int coap_context_set_psk(coap_context_t *context, const char *hint, const uint8_t *key, size_t key_len)
Set the context's default PSK hint and/or key for a server.
COAP_API coap_mid_t coap_send_ack(coap_session_t *session, const coap_pdu_t *request)
Sends an ACK message with code 0 for the specified request to dst.
Definition coap_net.c:1109
unsigned int coap_context_get_csm_timeout_ms(const coap_context_t *context)
Get the CSM timeout value.
Definition coap_net.c:557
void coap_register_ping_handler(coap_context_t *context, coap_ping_handler_t handler)
Registers a new message handler that is called whenever a CoAP Ping message is received.
Definition coap_net.c:5357
COAP_API int coap_context_set_psk2(coap_context_t *context, coap_dtls_spsk_t *setup_data)
Set the context's default PSK hint and/or key for a server.
void * coap_get_app_data(const coap_context_t *ctx)
Definition coap_net.c:826
int coap_context_set_cid_tuple_change(coap_context_t *context, uint8_t every)
Set the Connection ID client tuple frequency change for testing CIDs.
Definition coap_net.c:469
void coap_context_set_max_idle_sessions(coap_context_t *context, unsigned int max_idle_sessions)
Set the maximum idle sessions count.
Definition coap_net.c:510
COAP_API coap_mid_t coap_send_message_type(coap_session_t *session, const coap_pdu_t *request, coap_pdu_type_t type)
Helper function to create and send a message with type (usually ACK or RST).
Definition coap_net.c:1217
COAP_API coap_mid_t coap_send_rst(coap_session_t *session, const coap_pdu_t *request)
Sends an RST message with code 0 for the specified request to dst.
Definition coap_net.c:1094
void coap_context_set_session_reconnect_time2(coap_context_t *context, unsigned int reconnect_time, uint8_t retry_count)
Set the session reconnect delay time after a working client session has failed.
Definition coap_net.c:592
void coap_context_set_keepalive(coap_context_t *context, unsigned int seconds)
Set the context keepalive timer for sessions.
Definition coap_net.c:464
COAP_API int coap_can_exit(coap_context_t *context)
Returns 1 if there are no messages to send or to dispatch in the context's queues.
Definition coap_net.c:5159
COAP_API void coap_register_option(coap_context_t *ctx, uint16_t type)
Registers the option number number with the given context object context.
Definition coap_net.c:5378
unsigned int coap_context_get_csm_timeout(const coap_context_t *context)
Get the CSM timeout value.
Definition coap_net.c:541
COAP_API int coap_context_load_pki_trust_store(coap_context_t *ctx)
Load the hosts's default trusted CAs for a client or server.
Definition coap_net.c:445
void coap_context_set_session_reconnect_time(coap_context_t *context, unsigned int reconnect_time)
Set the session reconnect delay time after a working client session has failed.
Definition coap_net.c:586
void coap_register_pong_handler(coap_context_t *context, coap_pong_handler_t handler)
Registers a new message handler that is called whenever a CoAP Pong message is received.
Definition coap_net.c:5363
void coap_context_set_max_token_size(coap_context_t *context, size_t max_token_size)
Set the maximum token size (RFC8974).
Definition coap_net.c:499
COAP_API int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:5068
void coap_register_nack_handler(coap_context_t *context, coap_nack_handler_t handler)
Registers a new message handler that is called whenever a confirmable message (request or response) i...
Definition coap_net.c:5351
void coap_context_set_csm_timeout_ms(coap_context_t *context, unsigned int csm_timeout_ms)
Set the CSM timeout value.
Definition coap_net.c:547
@ COAP_RESPONSE_FAIL
Response not liked - send CoAP RST packet.
Definition coap_net.h:52
@ COAP_RESPONSE_OK
Response is fine.
Definition coap_net.h:53
const coap_bin_const_t * coap_get_session_client_psk_identity(const coap_session_t *coap_session)
Get the current client's PSK identity.
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
Definition coap_notls.c:154
coap_session_t * coap_session_new_dtls_session(coap_session_t *session, coap_tick_t now)
Create a new DTLS session for the session.
int coap_dtls_set_cid_tuple_change(coap_context_t *context, uint8_t every)
Set the Connection ID client tuple frequency change for testing CIDs.
void coap_dtls_shutdown(void)
Close down the underlying (D)TLS Library layer.
Definition coap_notls.c:166
const coap_bin_const_t * coap_get_session_client_psk_key(const coap_session_t *coap_session)
Get the current client's PSK key.
const coap_bin_const_t * coap_get_session_server_psk_key(const coap_session_t *coap_session)
Get the current server's PSK key.
const coap_bin_const_t * coap_get_session_server_psk_hint(const coap_session_t *coap_session)
Get the current server's PSK identity hint.
#define COAP_DTLS_PKI_SETUP_VERSION
Latest PKI setup version.
Definition coap_dtls.h:311
@ COAP_DTLS_ROLE_SERVER
Internal function invoked for server.
Definition coap_dtls.h:50
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:47
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
uint64_t coap_decode_var_bytes8(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:71
unsigned int coap_encode_var_safe8(uint8_t *buf, size_t length, uint64_t val)
Encodes multiple-length byte sequences.
Definition coap_encode.c:81
coap_event_t
Scalar type to represent different events, e.g.
Definition coap_event.h:36
@ COAP_EVENT_OSCORE_DECODE_ERROR
Triggered when there is an OSCORE decode of OSCORE option failure.
Definition coap_event.h:130
@ COAP_EVENT_SESSION_CONNECTED
Triggered when TCP layer completes exchange of CSM information.
Definition coap_event.h:63
@ COAP_EVENT_RECONNECT_FAILED
Triggered when a session failed, and a reconnect is going to be attempted.
Definition coap_event.h:149
@ COAP_EVENT_OSCORE_INTERNAL_ERROR
Triggered when there is an OSCORE internal error i.e malloc failed.
Definition coap_event.h:128
@ COAP_EVENT_DTLS_CLOSED
Triggerred when (D)TLS session closed.
Definition coap_event.h:41
@ COAP_EVENT_TCP_FAILED
Triggered when TCP layer fails for some reason.
Definition coap_event.h:57
@ COAP_EVENT_WS_CONNECTED
Triggered when the WebSockets layer is up.
Definition coap_event.h:137
@ COAP_EVENT_DTLS_CONNECTED
Triggered when (D)TLS session connected.
Definition coap_event.h:43
@ COAP_EVENT_BLOCK_ISSUE
Triggered when a block transfer could not be handled.
Definition coap_event.h:77
@ COAP_EVENT_SESSION_FAILED
Triggered when TCP layer fails following exchange of CSM information.
Definition coap_event.h:67
@ COAP_EVENT_PARTIAL_BLOCK
Triggered when not all of a large body has been received.
Definition coap_event.h:73
@ COAP_EVENT_XMIT_BLOCK_FAIL
Triggered when not all of a large body has been transmitted.
Definition coap_event.h:75
@ COAP_EVENT_SERVER_SESSION_NEW
Called in the CoAP IO loop if a new server-side session is created due to an incoming connection.
Definition coap_event.h:89
@ COAP_EVENT_OSCORE_NOT_ENABLED
Triggered when trying to use OSCORE to decrypt, but it is not enabled.
Definition coap_event.h:122
@ COAP_EVENT_RECONNECT_STARTED
Triggered when a session starts to reconnect.
Definition coap_event.h:155
@ COAP_EVENT_WS_CLOSED
Triggered when the WebSockets layer is closed.
Definition coap_event.h:139
@ COAP_EVENT_RECONNECT_NO_MORE
Triggered when a session failed, and retry reconnect attempts failed.
Definition coap_event.h:153
@ COAP_EVENT_SESSION_CLOSED
Triggered when TCP layer closes following exchange of CSM information.
Definition coap_event.h:65
@ COAP_EVENT_FIRST_PDU_FAIL
Triggered when the initial app PDU cannot be transmitted.
Definition coap_event.h:114
@ COAP_EVENT_SERVER_SESSION_DEL
Called in the CoAP IO loop if a server session is deleted (e.g., due to inactivity or because the max...
Definition coap_event.h:98
@ COAP_EVENT_OSCORE_NO_SECURITY
Triggered when there is no OSCORE security definition found.
Definition coap_event.h:126
@ COAP_EVENT_DTLS_RENEGOTIATE
Triggered when (D)TLS session renegotiated.
Definition coap_event.h:45
@ COAP_EVENT_BAD_PACKET
Triggered when badly formatted packet received.
Definition coap_event.h:110
@ COAP_EVENT_SERVER_SESSION_CONNECTED
Called in the CoAP IO loop once a server session is active and (D)TLS (if any) is established.
Definition coap_event.h:104
@ COAP_EVENT_MSG_RETRANSMITTED
Triggered when a message is retransmitted.
Definition coap_event.h:112
@ COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD
Triggered when there is no OSCORE encrypted payload provided.
Definition coap_event.h:124
@ COAP_EVENT_RECONNECT_SUCCESS
Triggered when a session failed, and a reconnect is successful.
Definition coap_event.h:151
@ COAP_EVENT_TCP_CLOSED
Triggered when TCP layer is closed.
Definition coap_event.h:55
@ COAP_EVENT_WS_PACKET_SIZE
Triggered when there is an oversize WebSockets packet.
Definition coap_event.h:135
@ COAP_EVENT_TCP_CONNECTED
Triggered when TCP layer connects.
Definition coap_event.h:53
@ COAP_EVENT_OSCORE_DECRYPTION_FAILURE
Triggered when there is an OSCORE decryption failure.
Definition coap_event.h:120
@ COAP_EVENT_KEEPALIVE_FAILURE
Triggered when no response to a keep alive (ping) packet.
Definition coap_event.h:144
@ COAP_EVENT_DTLS_ERROR
Triggered when (D)TLS error occurs.
Definition coap_event.h:47
#define coap_lock_specific_callback_release(lock, func, failed)
Dummy for no thread-safe code.
coap_mutex_t coap_lock_t
#define coap_lock_callback(func)
Dummy for no thread-safe code.
#define coap_lock_init(lock)
Dummy for no thread-safe code.
#define coap_lock_callback_ret(r, func)
Dummy for no thread-safe code.
#define coap_lock_callback_ret_release(r, func, failed)
Dummy for no thread-safe code.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_callback_release(func, failed)
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition coap_debug.c:103
#define coap_log_alert(...)
Definition coap_debug.h:90
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition coap_debug.c:793
#define coap_log_emerg(...)
Definition coap_debug.h:87
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition coap_debug.c:241
const char * coap_endpoint_str(const coap_endpoint_t *endpoint)
Get endpoint description.
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_info(...)
Definition coap_debug.h:114
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_err(...)
Definition coap_debug.h:102
@ COAP_LOG_DEBUG
Definition coap_debug.h:64
@ COAP_LOG_WARN
Definition coap_debug.h:61
int coap_netif_strm_connect2(coap_session_t *session)
Layer function interface for Netif stream connect (tcp).
ssize_t coap_netif_dgrm_read(coap_session_t *session, coap_packet_t *packet)
Function interface for layer data datagram receiving for sessions.
Definition coap_netif.c:72
ssize_t coap_netif_dgrm_read_ep(coap_endpoint_t *endpoint, coap_packet_t *packet)
Function interface for layer data datagram receiving for endpoints.
int coap_netif_available(coap_session_t *session)
Function interface to check whether netif for session is still available.
Definition coap_netif.c:25
#define COAP_OBSERVE_CANCEL
The value COAP_OBSERVE_CANCEL in a GET/FETCH request option COAP_OPTION_OBSERVE indicates that the ob...
#define COAP_OBSERVE_ESTABLISH
The value COAP_OBSERVE_ESTABLISH in a GET/FETCH request option COAP_OPTION_OBSERVE indicates a new ob...
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
coap_opt_iterator_t * coap_option_iterator_init(const coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t *filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list.
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
void coap_option_filter_clear(coap_opt_filter_t *filter)
Clears filter filter.
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.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
int coap_option_filter_get(coap_opt_filter_t *filter, coap_option_num_t option)
Checks if number is contained in filter.
int coap_option_filter_set(coap_opt_filter_t *filter, coap_option_num_t option)
Sets the corresponding entry for number in filter.
coap_pdu_t * coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, coap_pdu_t *pdu, coap_bin_const_t *kid_context, oscore_partial_iv_t send_partial_iv)
Encrypts the specified pdu when OSCORE encryption is required on session.
struct coap_pdu_t * coap_oscore_decrypt_pdu(coap_session_t *session, coap_pdu_t *pdu)
Decrypts the OSCORE-encrypted parts of pdu when OSCORE is used.
int coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu)
Convert PDU to use Proxy-Scheme option if Proxy-Uri option is present.
void coap_delete_all_oscore(coap_context_t *context)
Cleanup all allocated OSCORE information.
#define COAP_PDU_IS_RESPONSE(pdu)
coap_pdu_t * coap_pdu_reference_lkd(coap_pdu_t *pdu)
Increment reference counter on a pdu to stop it prematurely getting freed off when coap_delete_pdu() ...
Definition coap_pdu.c:1680
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:194
#define COAP_TOKEN_EXT_2B_TKL
size_t coap_insert_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Inserts option of given number in the pdu with the appropriate data.
Definition coap_pdu.c:652
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition coap_pdu.c:512
int coap_pdu_parse_opt(coap_pdu_t *pdu, coap_opt_filter_t *error_opts)
Verify consistency in the given CoAP PDU structure and locate the data.
Definition coap_pdu.c:1376
#define COAP_DROPPED_RESPONSE
Indicates that a response is suppressed.
int coap_pdu_parse_header(coap_pdu_t *pdu, coap_proto_t proto)
Decode the protocol specific header for the specified PDU.
Definition coap_pdu.c:1102
size_t coap_pdu_parse_header_size(coap_proto_t proto, const uint8_t *data)
Interprets data to determine the number of bytes in the header.
Definition coap_pdu.c:1018
#define COAP_PDU_DELAYED
#define COAP_PDU_IS_EMPTY(pdu)
#define COAP_DEFAULT_MAX_PDU_RX_SIZE
#define COAP_PDU_IS_SIGNALING(pdu)
int coap_option_check_repeatable(coap_option_num_t number)
Check whether the option is allowed to be repeated or not.
Definition coap_pdu.c:606
size_t coap_update_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Updates existing first option of given number in the pdu with the new data.
Definition coap_pdu.c:751
#define COAP_TOKEN_EXT_1B_TKL
size_t coap_pdu_encode_header(coap_pdu_t *pdu, coap_proto_t proto)
Compose the protocol specific header for the specified PDU.
Definition coap_pdu.c:1542
#define COAP_DEFAULT_VERSION
int coap_pdu_parse2(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu, coap_opt_filter_t *error_opts)
Parses data into the CoAP PDU structure given in result.
Definition coap_pdu.c:1518
size_t coap_pdu_parse_size(coap_proto_t proto, const uint8_t *data, size_t length)
Parses data to extract the message size.
Definition coap_pdu.c:1049
int coap_pdu_resize(coap_pdu_t *pdu, size_t new_size)
Dynamically grows the size of pdu to new_size.
Definition coap_pdu.c:307
#define COAP_PDU_IS_REQUEST(pdu)
size_t coap_add_option_internal(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition coap_pdu.c:807
#define COAP_OPTION_HOP_LIMIT
Definition coap_pdu.h:135
#define COAP_OPTION_NORESPONSE
Definition coap_pdu.h:148
#define COAP_OPTION_URI_HOST
Definition coap_pdu.h:122
#define COAP_OPTION_IF_MATCH
Definition coap_pdu.h:121
#define COAP_OPTION_BLOCK2
Definition coap_pdu.h:140
const char * coap_response_phrase(unsigned char code)
Returns a human-readable response phrase for the specified CoAP response code.
Definition coap_pdu.c:978
#define COAP_OPTION_CONTENT_FORMAT
Definition coap_pdu.h:130
#define COAP_OPTION_BLOCK1
Definition coap_pdu.h:141
#define COAP_OPTION_Q_BLOCK1
Definition coap_pdu.h:137
#define COAP_OPTION_PROXY_SCHEME
Definition coap_pdu.h:145
#define COAP_OPTION_URI_QUERY
Definition coap_pdu.h:134
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:266
#define COAP_TOKEN_DEFAULT_MAX
Definition coap_pdu.h:58
#define COAP_OPTION_IF_NONE_MATCH
Definition coap_pdu.h:124
#define COAP_TOKEN_EXT_MAX
Definition coap_pdu.h:62
#define COAP_OPTION_URI_PATH
Definition coap_pdu.h:129
#define COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH
Definition coap_pdu.h:202
#define COAP_RESPONSE_CODE(N)
Definition coap_pdu.h:163
#define COAP_RESPONSE_CLASS(C)
Definition coap_pdu.h:166
coap_pdu_code_t
Set of codes available for a PDU.
Definition coap_pdu.h:330
#define COAP_OPTION_OSCORE
Definition coap_pdu.h:128
coap_pdu_type_t
CoAP PDU message type definitions.
Definition coap_pdu.h:70
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition coap_pdu.h:201
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition coap_pdu.c:379
#define COAP_OPTION_Q_BLOCK2
Definition coap_pdu.h:143
#define COAP_SIGNALING_OPTION_CUSTODY
Definition coap_pdu.h:205
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:1508
#define COAP_OPTION_RTAG
Definition coap_pdu.h:149
#define COAP_OPTION_URI_PORT
Definition coap_pdu.h:126
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:102
#define COAP_OPTION_ACCEPT
Definition coap_pdu.h:136
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:269
#define COAP_OPTION_PROXY_URI
Definition coap_pdu.h:144
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:125
#define COAP_DEFAULT_URI_WELLKNOWN
well-known resources URI
Definition coap_pdu.h:55
#define COAP_BERT_BASE
Definition coap_pdu.h:46
#define COAP_OPTION_ECHO
Definition coap_pdu.h:147
#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT
Definition coap_pdu.h:217
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition coap_pdu.h:200
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition coap_pdu.c:872
@ COAP_REQUEST_GET
Definition coap_pdu.h:81
@ COAP_PROTO_WS
Definition coap_pdu.h:322
@ COAP_PROTO_DTLS
Definition coap_pdu.h:319
@ COAP_PROTO_UDP
Definition coap_pdu.h:318
@ COAP_PROTO_TLS
Definition coap_pdu.h:321
@ COAP_PROTO_WSS
Definition coap_pdu.h:323
@ COAP_PROTO_TCP
Definition coap_pdu.h:320
@ COAP_SIGNALING_CODE_ABORT
Definition coap_pdu.h:373
@ COAP_REQUEST_CODE_PUT
Definition coap_pdu.h:335
@ COAP_REQUEST_CODE_POST
Definition coap_pdu.h:334
@ COAP_SIGNALING_CODE_CSM
Definition coap_pdu.h:369
@ COAP_SIGNALING_CODE_PING
Definition coap_pdu.h:370
@ COAP_REQUEST_CODE_DELETE
Definition coap_pdu.h:336
@ COAP_SIGNALING_CODE_PONG
Definition coap_pdu.h:371
@ COAP_EMPTY_CODE
Definition coap_pdu.h:331
@ COAP_REQUEST_CODE_GET
Definition coap_pdu.h:333
@ COAP_SIGNALING_CODE_RELEASE
Definition coap_pdu.h:372
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:337
@ COAP_MESSAGE_NON
Definition coap_pdu.h:72
@ COAP_MESSAGE_ACK
Definition coap_pdu.h:73
@ COAP_MESSAGE_CON
Definition coap_pdu.h:71
@ COAP_MESSAGE_RST
Definition coap_pdu.h:74
void coap_register_proxy_response_handler(coap_context_t *context, coap_proxy_response_handler_t handler)
Registers a new message handler that is called whenever a response is received by the proxy logic.
Definition coap_net.c:5340
coap_pdu_t *(* coap_proxy_response_handler_t)(coap_session_t *session, const coap_pdu_t *sent, coap_pdu_t *received, coap_cache_key_t *cache_key)
Proxy response handler that is used as callback held in coap_context_t.
Definition coap_proxy.h:133
void coap_connect_session(coap_session_t *session, coap_tick_t now)
ssize_t coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node)
#define COAP_DEFAULT_LEISURE_TICKS(s)
The DEFAULT_LEISURE definition for the session (s).
void coap_handle_nack(coap_session_t *session, coap_pdu_t *sent, const coap_nack_reason_t reason, const coap_mid_t mid)
size_t coap_session_max_pdu_rcv_size(const coap_session_t *session)
Get maximum acceptable receive PDU size.
void coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now)
Definition coap_net.c:2551
int coap_session_reconnect(coap_session_t *session)
Close the current session (if not already closed) and reconnect to server (client session only).
void coap_session_server_keepalive_failed(coap_session_t *session)
Clear down a session following a keepalive failure.
#define COAP_NSTART(s)
#define COAP_MAX_PAYLOADS(s)
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
ssize_t coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu)
Send a pdu according to the session's protocol.
Definition coap_net.c:1134
size_t coap_session_max_pdu_size_lkd(const coap_session_t *session)
Get maximum acceptable PDU size.
void coap_session_release_lkd(coap_session_t *session)
Decrement reference counter on a session.
coap_session_t * coap_session_reference_lkd(coap_session_t *session)
Increment reference counter on a session.
void coap_session_disconnected_lkd(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
@ COAP_EXT_T_NOT_CHECKED
Not checked.
@ COAP_EXT_T_CHECKING
Token size check request sent.
@ COAP_EXT_T_CHECKED
Token size valid.
void coap_session_set_mtu(coap_session_t *session, unsigned mtu)
Set the session MTU.
coap_session_state_t
coap_session_state_t values
#define COAP_PROTO_NOT_RELIABLE(p)
#define COAP_PROTO_RELIABLE(p)
void(* coap_app_data_free_callback_t)(void *data)
Callback to free off the app data when the entry is being deleted / freed off.
@ COAP_SESSION_TYPE_HELLO
server-side ephemeral session for responding to a client hello
@ COAP_SESSION_TYPE_SERVER
server-side
@ COAP_SESSION_TYPE_CLIENT
client-side
@ COAP_SESSION_STATE_CSM
@ COAP_SESSION_STATE_ESTABLISHED
@ COAP_SESSION_STATE_NONE
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:130
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:81
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:119
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:114
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition coap_str.h:222
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition coap_str.h:208
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
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition coap_str.c:50
int coap_epoll_is_supported(void)
Determine whether epoll is supported or not.
Definition coap_net.c:630
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition coap_notls.c:41
int coap_af_unix_is_supported(void)
Check whether socket type AF_UNIX is available.
Definition coap_net.c:684
int coap_ipv6_is_supported(void)
Check whether IPv6 is available.
Definition coap_net.c:657
int coap_threadsafe_is_supported(void)
Determine whether libcoap is threadsafe or not.
Definition coap_net.c:639
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition coap_notls.c:36
int coap_server_is_supported(void)
Check whether Server code is available.
Definition coap_net.c:675
int coap_client_is_supported(void)
Check whether Client code is available.
Definition coap_net.c:666
int coap_ipv4_is_supported(void)
Check whether IPv4 is available.
Definition coap_net.c:648
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition coap_uri.c:1023
int coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri)
Parses a given string into URI components.
Definition coap_uri.c:299
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:972
#define COAP_UNUSED
Definition libcoap.h:74
#define COAP_STATIC_INLINE
Definition libcoap.h:57
coap_address_t remote
remote address and port
Definition coap_io.h:58
coap_address_t local
local address and port
Definition coap_io.h:59
Multi-purpose address abstraction.
struct sockaddr_in sin
struct sockaddr_in6 sin6
struct sockaddr sa
union coap_address_t::@0 addr
CoAP binary data definition with const data.
Definition coap_str.h:65
size_t length
length of binary data
Definition coap_str.h:66
const uint8_t * s
read-only binary data
Definition coap_str.h:67
CoAP binary data definition.
Definition coap_str.h:57
size_t length
length of binary data
Definition coap_str.h:58
uint8_t * s
binary data
Definition coap_str.h:59
Structure of Block options with BERT support.
Definition coap_block.h:55
unsigned int num
block number
Definition coap_block.h:56
uint32_t chunk_size
‍1024 if BERT
Definition coap_block.h:62
unsigned int bert
Operating as BERT.
Definition coap_block.h:61
unsigned int aszx
block size (0-7 including BERT
Definition coap_block.h:59
unsigned int defined
Set if block found.
Definition coap_block.h:60
unsigned int m
1 if more blocks follow, 0 otherwise
Definition coap_block.h:57
unsigned int szx
block size (0-6)
Definition coap_block.h:58
The CoAP stack's global state is stored in a coap_context_t object.
coap_tick_t sendqueue_basetime
The time stamp in the first element of the sendqeue is relative to sendqueue_basetime.
uint64_t rl_ticks_per_packet
If not 0, rate limit NON to ticks per packet.
uint32_t dynamic_cur
Current number of dynamic resources.
coap_app_data_free_callback_t app_cb
call-back to release app_data
coap_pong_handler_t pong_cb
Called when a ping response is received.
coap_nack_handler_t nack_cb
Called when a response issue has occurred.
coap_resource_dynamic_create_t dyn_create_handler
Dynamc resource create handler.
uint32_t max_body_size
Max supported body size or 0 is unlimited.
void * app_data
application-specific data
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
uint32_t dynamic_max
Max number of dynamic resources or 0 is unlimited.
coap_event_handler_t event_cb
Callback function that is used to signal events to the application.
coap_opt_filter_t known_options
uint32_t csm_max_message_size
Value for CSM Max-Message-Size.
unsigned int max_handshake_sessions
Maximum number of simultaneous negotating sessions per endpoint.
coap_ping_handler_t ping_cb
Called when a CoAP ping is received.
coap_queue_t * sendqueue
uint32_t max_token_size
Largest token size supported RFC8974.
uint32_t csm_timeout_ms
Timeout for waiting for a CSM from the remote side.
unsigned int session_timeout
Number of seconds of inactivity after which an unused session will be closed.
uint32_t block_mode
Zero or more COAP_BLOCK_ or'd options.
unsigned int max_idle_sessions
Maximum number of simultaneous unused sessions per endpoint.
coap_bin_const_t key
Definition coap_dtls.h:385
coap_bin_const_t identity
Definition coap_dtls.h:384
coap_dtls_cpsk_info_t psk_info
Client PSK definition.
Definition coap_dtls.h:447
The structure used for defining the PKI setup data to be used.
Definition coap_dtls.h:316
uint8_t version
Definition coap_dtls.h:317
coap_bin_const_t hint
Definition coap_dtls.h:455
coap_bin_const_t key
Definition coap_dtls.h:456
The structure used for defining the Server PSK setup data to be used.
Definition coap_dtls.h:505
coap_dtls_spsk_info_t psk_info
Server PSK definition.
Definition coap_dtls.h:537
uint64_t state_token
state token
uint32_t count
the number of packets sent for payload
coap_binary_t * app_token
original PDU token
coap_layer_read_t l_read
coap_layer_write_t l_write
coap_layer_establish_t l_establish
Structure to hold large body (many blocks) transmission information.
coap_tick_t last_all_sent
Last time all data sent or 0.
uint8_t blk_size
large block transmission size
union coap_lg_xmit_t::@1 b
int last_block
last acknowledged block number Block1 last transmitted Q-Block2
coap_pdu_t * sent_pdu
The sent pdu with all the data.
coap_l_block1_t b1
uint16_t option
large block transmisson CoAP option
Iterator to run through PDU options.
coap_option_num_t number
decoded option number
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
structure for CoAP PDUs
uint8_t * token
first byte of token (or extended length bytes prefix), if any, or options
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
uint8_t hdr_size
actual size used for protocol-specific header (0 until header is encoded)
coap_bin_const_t actual_token
Actual token in pdu.
uint8_t * data
first byte of payload, if any
coap_mid_t mid
message id, if any, in regular host byte order
uint32_t e_token_length
length of Token space (includes leading extended bytes
size_t used_size
used bytes of storage for token, options and payload
uint8_t crit_opt
Set if unknown critical option for proxy.
coap_binary_t * data_free
Data to be freed off by coap_delete_pdu()
size_t alloc_size
allocated storage for token, options and payload
coap_session_t * session
Session responsible for PDU or NULL.
coap_pdu_type_t type
message type
Queue entry.
coap_address_t remote
For re-transmission - where the node is going.
coap_session_t * session
the CoAP session
coap_pdu_t * pdu
the CoAP PDU to send
unsigned int timeout
the randomized timeout value
uint8_t is_mcast
Set if this is a queued mcast response.
struct coap_queue_t * next
coap_mid_t id
CoAP message id.
coap_tick_t t
when to send PDU for the next time
unsigned char retransmit_cnt
retransmission counter, will be removed when zero
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_lg_xmit_t * lg_xmit
list of large transmissions
volatile uint8_t max_token_checked
Check for max token size coap_ext_token_check_t.
uint8_t csm_not_seen
Set if timeout waiting for CSM.
coap_bin_const_t * psk_key
If client, this field contains the current pre-shared key for server; When this field is NULL,...
uint32_t block_mode
Zero or more COAP_BLOCK_ or'd options.
uint8_t delay_recursive
Set if in coap_client_delay_first()
coap_socket_t sock
socket object for the session, if any
coap_pdu_t * partial_pdu
incomplete incoming pdu
uint32_t max_token_size
Largest token size supported RFC8974.
coap_bin_const_t * psk_identity
If client, this field contains the current identity for server; When this field is NULL,...
coap_session_state_t state
current state of relationship with peer
uint8_t csm_bert_rem_support
CSM TCP BERT blocks supported (remote)
uint8_t is_rate_limiting
Currently NON rate limiting.
coap_mid_t remote_test_mid
mid used for checking remote support
uint8_t read_header[8]
storage space for header of incoming message header
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
coap_response_t last_con_handler_res
The result of calling the response handler of the last CON.
coap_tick_t last_tx
Last time a ratelimited packet is sent.
coap_bin_const_t * psk_hint
If client, this field contains the server provided identity hint.
coap_bin_const_t * last_token
coap_dtls_cpsk_t cpsk_setup_data
client provided PSK initial setup data
size_t mtu
path or CSM mtu (xmt)
size_t partial_read
if > 0 indicates number of bytes already read for an incoming message
void * tls
security parameters
uint16_t max_retransmit
maximum re-transmit count (default 4)
uint8_t csm_block_supported
CSM TCP blocks supported.
uint8_t proxy_session
Set if this is an ongoing proxy session.
uint8_t con_active
Active CON request sent.
coap_queue_t * delayqueue
list of delayed messages waiting to be sent
uint32_t tx_rtag
Next Request-Tag number to use.
coap_mid_t last_ping_mid
the last keepalive message id that was used in this session
uint64_t rl_ticks_per_packet
If not 0, rate limit NON to ticks per packet.
coap_mid_t last_con_mid
The last CON mid that has been been processed.
coap_session_type_t type
client or server side socket
coap_mid_t last_ack_mid
The last ACK mid that has been been processed.
coap_context_t * context
session's context
size_t partial_write
if > 0 indicates number of bytes already written from the pdu at the head of sendqueue
coap_bin_const_t * echo
last token used to make a request
coap_layer_func_t lfunc[COAP_LAYER_LAST]
Layer functions to use.
coap_session_t * session
Used to determine session owner.
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values
CoAP string data definition with const data.
Definition coap_str.h:47
const uint8_t * s
read-only string data
Definition coap_str.h:49
size_t length
length of string
Definition coap_str.h:48
CoAP string data definition.
Definition coap_str.h:39
uint8_t * s
string data
Definition coap_str.h:41
size_t length
length of string
Definition coap_str.h:40
Representation of parsed URI.
Definition coap_uri.h:70
coap_str_const_t host
The host part of the URI.
Definition coap_uri.h:71