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