1 /* net.c -- CoAP network interface
2 *
3 * Copyright (C) 2010--2019 Olaf Bergmann <bergmann@tzi.org>
4 * Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved.
5 *
6 * This file is part of the CoAP library libcoap. Please see
7 * README for terms of use.
8 */
9
10 #include "coap_internal.h"
11
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #ifdef HAVE_LIMITS_H
16 #include <limits.h>
17 #endif
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #elif HAVE_SYS_UNISTD_H
21 #include <sys/unistd.h>
22 #endif
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 #ifdef HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
28 #endif
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #ifdef HAVE_ARPA_INET_H
33 #include <arpa/inet.h>
34 #endif
35 #ifdef COAP_EPOLL_SUPPORT
36 #include <sys/epoll.h>
37 #include <sys/timerfd.h>
38 #endif /* COAP_EPOLL_SUPPORT */
39 #ifdef HAVE_WS2TCPIP_H
40 #include <ws2tcpip.h>
41 #endif
42
43 #ifdef HAVE_NETDB_H
44 #include <netdb.h>
45 #endif
46
47 #ifdef WITH_LWIP
48 #include <lwip/pbuf.h>
49 #include <lwip/udp.h>
50 #include <lwip/timeouts.h>
51 #endif
52
53 #ifndef min
54 #define min(a,b) ((a) < (b) ? (a) : (b))
55 #endif
56
57 /**
58 * The number of bits for the fractional part of ACK_TIMEOUT and
59 * ACK_RANDOM_FACTOR. Must be less or equal 8.
60 */
61 #define FRAC_BITS 6
62
63 /**
64 * The maximum number of bits for fixed point integers that are used
65 * for retransmission time calculation. Currently this must be @c 8.
66 */
67 #define MAX_BITS 8
68
69 #if FRAC_BITS > 8
70 #error FRAC_BITS must be less or equal 8
71 #endif
72
73 /** creates a Qx.frac from fval in coap_fixed_point_t */
74 #define Q(frac,fval) ((uint16_t)(((1 << (frac)) * fval.integer_part) + \
75 ((1 << (frac)) * fval.fractional_part + 500)/1000))
76
77 /** creates a Qx.FRAC_BITS from session's 'ack_random_factor' */
78 #define ACK_RANDOM_FACTOR \
79 Q(FRAC_BITS, session->ack_random_factor)
80
81 /** creates a Qx.FRAC_BITS from session's 'ack_timeout' */
82 #define ACK_TIMEOUT Q(FRAC_BITS, session->ack_timeout)
83
84 #if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
85
86 COAP_STATIC_INLINE coap_queue_t *
coap_malloc_node(void)87 coap_malloc_node(void) {
88 return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t));
89 }
90
91 COAP_STATIC_INLINE void
coap_free_node(coap_queue_t * node)92 coap_free_node(coap_queue_t *node) {
93 coap_free_type(COAP_NODE, node);
94 }
95 #endif /* !defined(WITH_LWIP) && !defined(WITH_CONTIKI) */
96
97 void coap_free_endpoint(coap_endpoint_t *ep);
98
99 #ifdef WITH_LWIP
100
101 #include <lwip/memp.h>
102
103 static void coap_retransmittimer_execute(void *arg);
104 static void coap_retransmittimer_restart(coap_context_t *ctx);
105
106 COAP_STATIC_INLINE coap_queue_t *
coap_malloc_node()107 coap_malloc_node() {
108 return (coap_queue_t *)memp_malloc(MEMP_COAP_NODE);
109 }
110
111 COAP_STATIC_INLINE void
coap_free_node(coap_queue_t * node)112 coap_free_node(coap_queue_t *node) {
113 memp_free(MEMP_COAP_NODE, node);
114 }
115
116 #endif /* WITH_LWIP */
117 #ifdef WITH_CONTIKI
118 # ifndef DEBUG
119 # define DEBUG DEBUG_PRINT
120 # endif /* DEBUG */
121
122 #include "net/ip/uip-debug.h"
123
124 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
125 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
126
127 void coap_resources_init();
128
129 unsigned char initialized = 0;
130 coap_context_t the_coap_context;
131
132 PROCESS(coap_retransmit_process, "message retransmit process");
133
134 COAP_STATIC_INLINE coap_queue_t *
coap_malloc_node()135 coap_malloc_node() {
136 return (coap_queue_t *)coap_malloc_type(COAP_NODE, 0);
137 }
138
139 COAP_STATIC_INLINE void
coap_free_node(coap_queue_t * node)140 coap_free_node(coap_queue_t *node) {
141 coap_free_type(COAP_NODE, node);
142 }
143 #endif /* WITH_CONTIKI */
144
145 unsigned int
coap_adjust_basetime(coap_context_t * ctx,coap_tick_t now)146 coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) {
147 unsigned int result = 0;
148 coap_tick_diff_t delta = now - ctx->sendqueue_basetime;
149
150 if (ctx->sendqueue) {
151 /* delta < 0 means that the new time stamp is before the old. */
152 if (delta <= 0) {
153 ctx->sendqueue->t -= delta;
154 } else {
155 /* This case is more complex: The time must be advanced forward,
156 * thus possibly leading to timed out elements at the queue's
157 * start. For every element that has timed out, its relative
158 * time is set to zero and the result counter is increased. */
159
160 coap_queue_t *q = ctx->sendqueue;
161 coap_tick_t t = 0;
162 while (q && (t + q->t < (coap_tick_t)delta)) {
163 t += q->t;
164 q->t = 0;
165 result++;
166 q = q->next;
167 }
168
169 /* finally adjust the first element that has not expired */
170 if (q) {
171 q->t = (coap_tick_t)delta - t;
172 }
173 }
174 }
175
176 /* adjust basetime */
177 ctx->sendqueue_basetime += delta;
178
179 return result;
180 }
181
182 int
coap_insert_node(coap_queue_t ** queue,coap_queue_t * node)183 coap_insert_node(coap_queue_t **queue, coap_queue_t *node) {
184 coap_queue_t *p, *q;
185 if (!queue || !node)
186 return 0;
187
188 /* set queue head if empty */
189 if (!*queue) {
190 *queue = node;
191 return 1;
192 }
193
194 /* replace queue head if PDU's time is less than head's time */
195 q = *queue;
196 if (node->t < q->t) {
197 node->next = q;
198 *queue = node;
199 q->t -= node->t; /* make q->t relative to node->t */
200 return 1;
201 }
202
203 /* search for right place to insert */
204 do {
205 node->t -= q->t; /* make node-> relative to q->t */
206 p = q;
207 q = q->next;
208 } while (q && q->t <= node->t);
209
210 /* insert new item */
211 if (q) {
212 q->t -= node->t; /* make q->t relative to node->t */
213 }
214 node->next = q;
215 p->next = node;
216 return 1;
217 }
218
219 int
coap_delete_node(coap_queue_t * node)220 coap_delete_node(coap_queue_t *node) {
221 if (!node)
222 return 0;
223
224 coap_delete_pdu(node->pdu);
225 if ( node->session ) {
226 /*
227 * Need to remove out of context->sendqueue as added in by coap_wait_ack()
228 */
229 if (node->session->context->sendqueue) {
230 LL_DELETE(node->session->context->sendqueue, node);
231 }
232 coap_session_release(node->session);
233 }
234 coap_free_node(node);
235
236 return 1;
237 }
238
239 void
coap_delete_all(coap_queue_t * queue)240 coap_delete_all(coap_queue_t *queue) {
241 if (!queue)
242 return;
243
244 coap_delete_all(queue->next);
245 coap_delete_node(queue);
246 }
247
248 coap_queue_t *
coap_new_node(void)249 coap_new_node(void) {
250 coap_queue_t *node;
251 node = coap_malloc_node();
252
253 if (!node) {
254 coap_log(LOG_WARNING, "coap_new_node: malloc failed\n");
255 return NULL;
256 }
257
258 memset(node, 0, sizeof(*node));
259 return node;
260 }
261
262 coap_queue_t *
coap_peek_next(coap_context_t * context)263 coap_peek_next(coap_context_t *context) {
264 if (!context || !context->sendqueue)
265 return NULL;
266
267 return context->sendqueue;
268 }
269
270 coap_queue_t *
coap_pop_next(coap_context_t * context)271 coap_pop_next(coap_context_t *context) {
272 coap_queue_t *next;
273
274 if (!context || !context->sendqueue)
275 return NULL;
276
277 next = context->sendqueue;
278 context->sendqueue = context->sendqueue->next;
279 if (context->sendqueue) {
280 context->sendqueue->t += next->t;
281 }
282 next->next = NULL;
283 return next;
284 }
285
286 static size_t
coap_get_session_client_psk(const coap_session_t * session,const uint8_t * hint,size_t hint_len,uint8_t * identity,size_t * identity_len,size_t max_identity_len,uint8_t * psk,size_t max_psk_len)287 coap_get_session_client_psk(
288 const coap_session_t *session,
289 const uint8_t *hint, size_t hint_len,
290 uint8_t *identity, size_t *identity_len, size_t max_identity_len,
291 uint8_t *psk, size_t max_psk_len
292 ) {
293 (void)hint;
294 (void)hint_len;
295 if (session->psk_identity && session->psk_identity_len > 0 && session->psk_key && session->psk_key_len > 0) {
296 if (session->psk_identity_len <= max_identity_len && session->psk_key_len <= max_psk_len) {
297 memcpy(identity, session->psk_identity, session->psk_identity_len);
298 memcpy(psk, session->psk_key, session->psk_key_len);
299 *identity_len = session->psk_identity_len;
300 return session->psk_key_len;
301 }
302 } else if (session->context && session->context->psk_key && session->context->psk_key_len > 0) {
303 if (session->context->psk_key_len <= max_psk_len) {
304 *identity_len = 0;
305 memcpy(psk, session->context->psk_key, session->context->psk_key_len);
306 return session->context->psk_key_len;
307 }
308 }
309 *identity_len = 0;
310 return 0;
311 }
312
313 static size_t
coap_get_context_server_psk(const coap_session_t * session,const uint8_t * identity,size_t identity_len,uint8_t * psk,size_t max_psk_len)314 coap_get_context_server_psk(
315 const coap_session_t *session,
316 const uint8_t *identity, size_t identity_len,
317 uint8_t *psk, size_t max_psk_len
318 ) {
319 (void)identity;
320 (void)identity_len;
321 const coap_context_t *ctx = session->context;
322 if (ctx && ctx->psk_key && ctx->psk_key_len > 0 && ctx->psk_key_len <= max_psk_len) {
323 memcpy(psk, ctx->psk_key, ctx->psk_key_len);
324 return ctx->psk_key_len;
325 }
326 return 0;
327 }
328
329 static size_t
coap_get_context_server_hint(const coap_session_t * session,uint8_t * hint,size_t max_hint_len)330 coap_get_context_server_hint(
331 const coap_session_t *session,
332 uint8_t *hint, size_t max_hint_len
333 ) {
334 const coap_context_t *ctx = session->context;
335 if (ctx && ctx->psk_hint && ctx->psk_hint_len > 0 && ctx->psk_hint_len <= max_hint_len) {
336 memcpy(hint, ctx->psk_hint, ctx->psk_hint_len);
337 return ctx->psk_hint_len;
338 }
339 return 0;
340 }
341
coap_context_set_psk(coap_context_t * ctx,const char * hint,const uint8_t * key,size_t key_len)342 int coap_context_set_psk(coap_context_t *ctx,
343 const char *hint,
344 const uint8_t *key, size_t key_len
345 ) {
346
347 if (ctx->psk_hint)
348 coap_free(ctx->psk_hint);
349 ctx->psk_hint = NULL;
350 ctx->psk_hint_len = 0;
351
352 if (hint) {
353 size_t hint_len = strlen(hint);
354 ctx->psk_hint = (uint8_t*)coap_malloc(hint_len);
355 if (ctx->psk_hint) {
356 memcpy(ctx->psk_hint, hint, hint_len);
357 ctx->psk_hint_len = hint_len;
358 } else {
359 coap_log(LOG_ERR, "No memory to store PSK hint\n");
360 return 0;
361 }
362 }
363
364 if (ctx->psk_key)
365 coap_free(ctx->psk_key);
366 ctx->psk_key = NULL;
367 ctx->psk_key_len = 0;
368
369 if (key && key_len > 0) {
370 ctx->psk_key = (uint8_t *)coap_malloc(key_len);
371 if (ctx->psk_key) {
372 memcpy(ctx->psk_key, key, key_len);
373 ctx->psk_key_len = key_len;
374 } else {
375 coap_log(LOG_ERR, "No memory to store PSK key\n");
376 return 0;
377 }
378 }
379 if (coap_dtls_is_supported()) {
380 return coap_dtls_context_set_psk(ctx, hint, COAP_DTLS_ROLE_SERVER);
381 }
382 return 0;
383 }
384
coap_context_set_pki(coap_context_t * ctx,coap_dtls_pki_t * setup_data)385 int coap_context_set_pki(coap_context_t *ctx,
386 coap_dtls_pki_t* setup_data
387 ) {
388 if (!setup_data)
389 return 0;
390 if (setup_data->version != COAP_DTLS_PKI_SETUP_VERSION) {
391 coap_log(LOG_ERR, "coap_context_set_pki: Wrong version of setup_data\n");
392 return 0;
393 }
394 if (coap_dtls_is_supported()) {
395 return coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_SERVER);
396 }
397 return 0;
398 }
399
coap_context_set_pki_root_cas(coap_context_t * ctx,const char * ca_file,const char * ca_dir)400 int coap_context_set_pki_root_cas(coap_context_t *ctx,
401 const char *ca_file,
402 const char *ca_dir
403 ) {
404 if (coap_dtls_is_supported()) {
405 return coap_dtls_context_set_pki_root_cas(ctx, ca_file, ca_dir);
406 }
407 return 0;
408 }
409
coap_context_set_keepalive(coap_context_t * context,unsigned int seconds)410 void coap_context_set_keepalive(coap_context_t *context, unsigned int seconds) {
411 context->ping_timeout = seconds;
412 }
413
coap_context_get_coap_fd(coap_context_t * context)414 int coap_context_get_coap_fd(coap_context_t *context) {
415 #ifdef COAP_EPOLL_SUPPORT
416 return context->epfd;
417 #else /* ! COAP_EPOLL_SUPPORT */
418 (void)context;
419 return -1;
420 #endif /* ! COAP_EPOLL_SUPPORT */
421 }
422
423 coap_context_t *
coap_new_context(const coap_address_t * listen_addr)424 coap_new_context(
425 const coap_address_t *listen_addr) {
426 coap_context_t *c;
427
428 #ifdef WITH_CONTIKI
429 if (initialized)
430 return NULL;
431 #endif /* WITH_CONTIKI */
432
433 coap_startup();
434
435 #ifndef WITH_CONTIKI
436 c = coap_malloc_type(COAP_CONTEXT, sizeof(coap_context_t));
437 #endif /* not WITH_CONTIKI */
438
439 #ifndef WITH_CONTIKI
440 if (!c) {
441 coap_log(LOG_EMERG, "coap_init: malloc: failed\n");
442 return NULL;
443 }
444 #endif /* not WITH_CONTIKI */
445 #ifdef WITH_CONTIKI
446 coap_resources_init();
447 coap_memory_init();
448
449 c = &the_coap_context;
450 initialized = 1;
451 #endif /* WITH_CONTIKI */
452
453 memset(c, 0, sizeof(coap_context_t));
454
455 #ifdef COAP_EPOLL_SUPPORT
456 c->epfd = epoll_create1(0);
457 if (c->epfd == -1) {
458 coap_log(LOG_ERR, "coap_new_context: Unable to epoll_create: %s (%d)\n",
459 coap_socket_strerror(),
460 errno);
461 goto onerror;
462 }
463 if (c->epfd != -1) {
464 c->eptimerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);
465 if (c->eptimerfd == -1) {
466 coap_log(LOG_ERR, "coap_new_context: Unable to timerfd_create: %s (%d)\n",
467 coap_socket_strerror(),
468 errno);
469 goto onerror;
470 }
471 else {
472 int ret;
473 struct epoll_event event;
474
475 /* Needed if running 32bit as ptr is only 32bit */
476 memset(&event, 0, sizeof(event));
477 event.events = EPOLLIN;
478 /* We special case this event by setting to NULL */
479 event.data.ptr = NULL;
480
481 ret = epoll_ctl(c->epfd, EPOLL_CTL_ADD, c->eptimerfd, &event);
482 if (ret == -1) {
483 coap_log(LOG_ERR,
484 "%s: epoll_ctl ADD failed: %s (%d)\n",
485 "coap_new_context",
486 coap_socket_strerror(), errno);
487 goto onerror;
488 }
489 }
490 }
491 #endif /* COAP_EPOLL_SUPPORT */
492
493 if (coap_dtls_is_supported()) {
494 c->dtls_context = coap_dtls_new_context(c);
495 if (!c->dtls_context) {
496 coap_log(LOG_EMERG, "coap_init: no DTLS context available\n");
497 coap_free_context(c);
498 return NULL;
499 }
500 }
501
502 /* set default CSM timeout */
503 c->csm_timeout = 30;
504
505 if (listen_addr) {
506 coap_endpoint_t *endpoint = coap_new_endpoint(c, listen_addr, COAP_PROTO_UDP);
507 if (endpoint == NULL) {
508 goto onerror;
509 }
510 }
511
512 #if !defined(WITH_LWIP)
513 c->network_send = coap_network_send;
514 c->network_read = coap_network_read;
515 #endif
516
517 c->get_client_psk = coap_get_session_client_psk;
518 c->get_server_psk = coap_get_context_server_psk;
519 c->get_server_hint = coap_get_context_server_hint;
520
521 #ifdef WITH_CONTIKI
522 process_start(&coap_retransmit_process, (char *)c);
523
524 PROCESS_CONTEXT_BEGIN(&coap_retransmit_process);
525 #ifndef WITHOUT_OBSERVE
526 etimer_set(&c->notify_timer, COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND);
527 #endif /* WITHOUT_OBSERVE */
528 /* the retransmit timer must be initialized to some large value */
529 etimer_set(&the_coap_context.retransmit_timer, 0xFFFF);
530 PROCESS_CONTEXT_END(&coap_retransmit_process);
531 #endif /* WITH_CONTIKI */
532
533 return c;
534
535 onerror:
536 coap_free_type(COAP_CONTEXT, c);
537 return NULL;
538 }
539
540 void
coap_set_app_data(coap_context_t * ctx,void * app_data)541 coap_set_app_data(coap_context_t *ctx, void *app_data) {
542 assert(ctx);
543 ctx->app = app_data;
544 }
545
546 void *
coap_get_app_data(const coap_context_t * ctx)547 coap_get_app_data(const coap_context_t *ctx) {
548 assert(ctx);
549 return ctx->app;
550 }
551
552 void
coap_free_context(coap_context_t * context)553 coap_free_context(coap_context_t *context) {
554 coap_endpoint_t *ep, *tmp;
555 coap_session_t *sp, *rtmp;
556
557 if (!context)
558 return;
559
560 coap_delete_all(context->sendqueue);
561
562 #ifdef WITH_LWIP
563 context->sendqueue = NULL;
564 coap_retransmittimer_restart(context);
565 #endif
566
567 coap_delete_all_resources(context);
568
569 LL_FOREACH_SAFE(context->endpoint, ep, tmp) {
570 coap_free_endpoint(ep);
571 }
572
573 SESSIONS_ITER_SAFE(context->sessions, sp, rtmp) {
574 coap_session_release(sp);
575 }
576
577 if (context->dtls_context)
578 coap_dtls_free_context(context->dtls_context);
579
580 if (context->psk_hint)
581 coap_free(context->psk_hint);
582
583 if (context->psk_key)
584 coap_free(context->psk_key);
585
586 #ifdef COAP_EPOLL_SUPPORT
587 if (context->eptimerfd != -1) {
588 int ret;
589 struct epoll_event event;
590
591 /* Kernels prior to 2.6.9 expect non NULL event parameter */
592 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, context->eptimerfd, &event);
593 if (ret == -1) {
594 coap_log(LOG_ERR,
595 "%s: epoll_ctl DEL failed: %s (%d)\n",
596 "coap_free_context",
597 coap_socket_strerror(), errno);
598 }
599 close(context->eptimerfd);
600 context->eptimerfd = -1;
601 }
602 if (context->epfd != -1) {
603 close(context->epfd);
604 context->epfd = -1;
605 }
606 #endif /* COAP_EPOLL_SUPPORT */
607
608 #ifndef WITH_CONTIKI
609 coap_free_type(COAP_CONTEXT, context);
610 #endif/* not WITH_CONTIKI */
611 #ifdef WITH_CONTIKI
612 memset(&the_coap_context, 0, sizeof(coap_context_t));
613 initialized = 0;
614 #endif /* WITH_CONTIKI */
615 }
616
617 int
coap_option_check_critical(coap_context_t * ctx,coap_pdu_t * pdu,coap_opt_filter_t unknown)618 coap_option_check_critical(coap_context_t *ctx,
619 coap_pdu_t *pdu,
620 coap_opt_filter_t unknown) {
621
622 coap_opt_iterator_t opt_iter;
623 int ok = 1;
624
625 coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
626
627 while (coap_option_next(&opt_iter)) {
628
629 /* The following condition makes use of the fact that
630 * coap_option_getb() returns -1 if type exceeds the bit-vector
631 * filter. As the vector is supposed to be large enough to hold
632 * the largest known option, we know that everything beyond is
633 * bad.
634 */
635 if (opt_iter.type & 0x01) {
636 /* first check the built-in critical options */
637 switch (opt_iter.type) {
638 case COAP_OPTION_IF_MATCH:
639 case COAP_OPTION_URI_HOST:
640 case COAP_OPTION_IF_NONE_MATCH:
641 case COAP_OPTION_URI_PORT:
642 case COAP_OPTION_URI_PATH:
643 case COAP_OPTION_URI_QUERY:
644 case COAP_OPTION_ACCEPT:
645 case COAP_OPTION_PROXY_URI:
646 case COAP_OPTION_PROXY_SCHEME:
647 case COAP_OPTION_BLOCK2:
648 case COAP_OPTION_BLOCK1:
649 break;
650 default:
651 if (coap_option_filter_get(ctx->known_options, opt_iter.type) <= 0) {
652 coap_log(LOG_DEBUG, "unknown critical option %d\n", opt_iter.type);
653 ok = 0;
654
655 /* When opt_iter.type is beyond our known option range,
656 * coap_option_filter_set() will return -1 and we are safe to leave
657 * this loop. */
658 if (coap_option_filter_set(unknown, opt_iter.type) == -1) {
659 break;
660 }
661 }
662 }
663 }
664 }
665
666 return ok;
667 }
668
669 coap_tid_t
coap_send_ack(coap_session_t * session,coap_pdu_t * request)670 coap_send_ack(coap_session_t *session, coap_pdu_t *request) {
671 coap_pdu_t *response;
672 coap_tid_t result = COAP_INVALID_TID;
673
674 if (request && request->type == COAP_MESSAGE_CON &&
675 COAP_PROTO_NOT_RELIABLE(session->proto)) {
676 response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->tid, 0);
677 if (response)
678 result = coap_send(session, response);
679 }
680 return result;
681 }
682
683 ssize_t
coap_session_send_pdu(coap_session_t * session,coap_pdu_t * pdu)684 coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu) {
685 ssize_t bytes_written = -1;
686 assert(pdu->hdr_size > 0);
687 switch(session->proto) {
688 case COAP_PROTO_UDP:
689 bytes_written = coap_session_send(session, pdu->token - pdu->hdr_size,
690 pdu->used_size + pdu->hdr_size);
691 break;
692 case COAP_PROTO_DTLS:
693 bytes_written = coap_dtls_send(session, pdu->token - pdu->hdr_size,
694 pdu->used_size + pdu->hdr_size);
695 break;
696 case COAP_PROTO_TCP:
697 bytes_written = coap_session_write(session, pdu->token - pdu->hdr_size,
698 pdu->used_size + pdu->hdr_size);
699 break;
700 case COAP_PROTO_TLS:
701 bytes_written = coap_tls_write(session, pdu->token - pdu->hdr_size,
702 pdu->used_size + pdu->hdr_size);
703 break;
704 default:
705 break;
706 }
707 coap_show_pdu(LOG_DEBUG, pdu);
708 return bytes_written;
709 }
710
711 static ssize_t
coap_send_pdu(coap_session_t * session,coap_pdu_t * pdu,coap_queue_t * node)712 coap_send_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node) {
713 ssize_t bytes_written;
714
715 #ifdef WITH_LWIP
716
717 coap_socket_t *sock = &session->sock;
718 if (sock->flags == COAP_SOCKET_EMPTY) {
719 if (session->endpoint == NULL) {
720 return COAP_INVALID_TID;
721 }
722 sock = &session->endpoint->sock;
723 }
724 if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto))
725 session->con_active++;
726
727 bytes_written = coap_socket_send_pdu(sock, session, pdu);
728 if (LOG_DEBUG <= coap_get_log_level()) {
729 coap_show_pdu(LOG_DEBUG, pdu);
730 }
731 coap_ticks(&session->last_rx_tx);
732
733 #else
734
735 /* Do not send error responses for requests that were received via
736 * IP multicast.
737 * FIXME: If No-Response option indicates interest, these responses
738 * must not be dropped. */
739 if (coap_is_mcast(&session->addr_info.local) &&
740 COAP_RESPONSE_CLASS(pdu->code) > 2) {
741 return COAP_DROPPED_RESPONSE;
742 }
743
744 if (session->state == COAP_SESSION_STATE_NONE) {
745 if (session->proto == COAP_PROTO_DTLS && !session->tls) {
746 session->tls = coap_dtls_new_client_session(session);
747 if (session->tls) {
748 session->state = COAP_SESSION_STATE_HANDSHAKE;
749 return coap_session_delay_pdu(session, pdu, node);
750 }
751 coap_handle_event(session->context, COAP_EVENT_DTLS_ERROR, session);
752 return -1;
753 } else if(COAP_PROTO_RELIABLE(session->proto)) {
754 if (!coap_socket_connect_tcp1(
755 &session->sock, &session->local_if, &session->addr_info.remote,
756 session->proto == COAP_PROTO_TLS ? COAPS_DEFAULT_PORT : COAP_DEFAULT_PORT,
757 &session->addr_info.local, &session->addr_info.remote
758 )) {
759 coap_handle_event(session->context, COAP_EVENT_TCP_FAILED, session);
760 return -1;
761 }
762 session->last_ping = 0;
763 session->last_pong = 0;
764 session->csm_tx = 0;
765 coap_ticks( &session->last_rx_tx );
766 if ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) != 0) {
767 session->state = COAP_SESSION_STATE_CONNECTING;
768 return coap_session_delay_pdu(session, pdu, node);
769 }
770 coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
771 if (session->proto == COAP_PROTO_TLS) {
772 int connected = 0;
773 session->state = COAP_SESSION_STATE_HANDSHAKE;
774 session->tls = coap_tls_new_client_session(session, &connected);
775 if (session->tls) {
776 if (connected) {
777 coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session);
778 coap_session_send_csm(session);
779 }
780 return coap_session_delay_pdu(session, pdu, node);
781 }
782 coap_handle_event(session->context, COAP_EVENT_DTLS_ERROR, session);
783 coap_session_disconnected(session, COAP_NACK_TLS_FAILED);
784 return -1;
785 } else {
786 coap_session_send_csm(session);
787 }
788 } else {
789 return -1;
790 }
791 }
792
793 if (pdu->type == COAP_MESSAGE_CON &&
794 (session->sock.flags & COAP_SOCKET_NOT_EMPTY) &&
795 (session->sock.flags & COAP_SOCKET_MULTICAST)) {
796 /* Violates RFC72522 8.1 */
797 coap_log(LOG_ERR, "Multicast requests cannot be Confirmable (RFC7252 8.1)\n");
798 return -1;
799 }
800
801 if (session->state != COAP_SESSION_STATE_ESTABLISHED ||
802 (pdu->type == COAP_MESSAGE_CON && session->con_active >= COAP_DEFAULT_NSTART)) {
803 return coap_session_delay_pdu(session, pdu, node);
804 }
805
806 if ((session->sock.flags & COAP_SOCKET_NOT_EMPTY) &&
807 (session->sock.flags & COAP_SOCKET_WANT_WRITE))
808 return coap_session_delay_pdu(session, pdu, node);
809
810 if (pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(session->proto))
811 session->con_active++;
812
813 bytes_written = coap_session_send_pdu(session, pdu);
814
815 #endif /* WITH_LWIP */
816
817 return bytes_written;
818 }
819
820 coap_tid_t
coap_send_error(coap_session_t * session,coap_pdu_t * request,unsigned char code,coap_opt_filter_t opts)821 coap_send_error(coap_session_t *session,
822 coap_pdu_t *request,
823 unsigned char code,
824 coap_opt_filter_t opts) {
825 coap_pdu_t *response;
826 coap_tid_t result = COAP_INVALID_TID;
827
828 assert(request);
829 assert(session);
830
831 response = coap_new_error_response(request, code, opts);
832 if (response)
833 result = coap_send(session, response);
834
835 return result;
836 }
837
838 coap_tid_t
coap_send_message_type(coap_session_t * session,coap_pdu_t * request,unsigned char type)839 coap_send_message_type(coap_session_t *session, coap_pdu_t *request, unsigned char type) {
840 coap_pdu_t *response;
841 coap_tid_t result = COAP_INVALID_TID;
842
843 if (request) {
844 response = coap_pdu_init(type, 0, request->tid, 0);
845 if (response)
846 result = coap_send(session, response);
847 }
848 return result;
849 }
850
851 /**
852 * Calculates the initial timeout based on the session CoAP transmission
853 * parameters 'ack_timeout', 'ack_random_factor', and COAP_TICKS_PER_SECOND.
854 * The calculation requires 'ack_timeout' and 'ack_random_factor' to be in
855 * Qx.FRAC_BITS fixed point notation, whereas the passed parameter @p r
856 * is interpreted as the fractional part of a Q0.MAX_BITS random value.
857 *
858 * @param session session timeout is associated with
859 * @param r random value as fractional part of a Q0.MAX_BITS fixed point
860 * value
861 * @return COAP_TICKS_PER_SECOND * 'ack_timeout' *
862 * (1 + ('ack_random_factor' - 1) * r)
863 */
864 unsigned int
coap_calc_timeout(coap_session_t * session,unsigned char r)865 coap_calc_timeout(coap_session_t *session, unsigned char r) {
866 unsigned int result;
867
868 /* The integer 1.0 as a Qx.FRAC_BITS */
869 #define FP1 Q(FRAC_BITS, ((coap_fixed_point_t){1,0}))
870
871 /* rounds val up and right shifts by frac positions */
872 #define SHR_FP(val,frac) (((val) + (1 << ((frac) - 1))) >> (frac))
873
874 /* Inner term: multiply ACK_RANDOM_FACTOR by Q0.MAX_BITS[r] and
875 * make the result a rounded Qx.FRAC_BITS */
876 result = SHR_FP((ACK_RANDOM_FACTOR - FP1) * r, MAX_BITS);
877
878 /* Add 1 to the inner term and multiply with ACK_TIMEOUT, then
879 * make the result a rounded Qx.FRAC_BITS */
880 result = SHR_FP(((result + FP1) * ACK_TIMEOUT), FRAC_BITS);
881
882 /* Multiply with COAP_TICKS_PER_SECOND to yield system ticks
883 * (yields a Qx.FRAC_BITS) and shift to get an integer */
884 return SHR_FP((COAP_TICKS_PER_SECOND * result), FRAC_BITS);
885
886 #undef FP1
887 #undef SHR_FP
888 }
889
890 coap_tid_t
coap_wait_ack(coap_context_t * context,coap_session_t * session,coap_queue_t * node)891 coap_wait_ack(coap_context_t *context, coap_session_t *session,
892 coap_queue_t *node) {
893 coap_tick_t now;
894
895 node->session = coap_session_reference(session);
896
897 /* Set timer for pdu retransmission. If this is the first element in
898 * the retransmission queue, the base time is set to the current
899 * time and the retransmission time is node->timeout. If there is
900 * already an entry in the sendqueue, we must check if this node is
901 * to be retransmitted earlier. Therefore, node->timeout is first
902 * normalized to the base time and then inserted into the queue with
903 * an adjusted relative time.
904 */
905 coap_ticks(&now);
906 if (context->sendqueue == NULL) {
907 node->t = node->timeout << node->retransmit_cnt;
908 context->sendqueue_basetime = now;
909 } else {
910 /* make node->t relative to context->sendqueue_basetime */
911 node->t = (now - context->sendqueue_basetime) +
912 (node->timeout << node->retransmit_cnt);
913 }
914
915 coap_insert_node(&context->sendqueue, node);
916
917 #ifdef WITH_LWIP
918 if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
919 coap_retransmittimer_restart(context);
920 #endif
921
922 #ifdef WITH_CONTIKI
923 { /* (re-)initialize retransmission timer */
924 coap_queue_t *nextpdu;
925
926 nextpdu = coap_peek_next(context);
927 assert(nextpdu); /* we have just inserted a node */
928
929 /* must set timer within the context of the retransmit process */
930 PROCESS_CONTEXT_BEGIN(&coap_retransmit_process);
931 etimer_set(&context->retransmit_timer, nextpdu->t);
932 PROCESS_CONTEXT_END(&coap_retransmit_process);
933 }
934 #endif /* WITH_CONTIKI */
935
936 coap_log(LOG_DEBUG, "** %s: tid=%d: added to retransmit queue (%ums)\n",
937 coap_session_str(node->session), node->id,
938 (unsigned)(node->t * 1000 / COAP_TICKS_PER_SECOND));
939
940 #ifdef COAP_EPOLL_SUPPORT
941 if (context->eptimerfd != -1) {
942 coap_ticks(&now);
943 if (context->next_timeout == 0 ||
944 context->next_timeout > now + (node->t * 1000 / COAP_TICKS_PER_SECOND)) {
945 struct itimerspec new_value;
946 int ret;
947
948 context->next_timeout = now + (node->t * 1000 / COAP_TICKS_PER_SECOND);
949 memset(&new_value, 0, sizeof(new_value));
950 coap_tick_t rem_timeout = (node->t * 1000 / COAP_TICKS_PER_SECOND);
951 /* Need to trigger an event on context->epfd in the future */
952 new_value.it_value.tv_sec = rem_timeout / 1000;
953 new_value.it_value.tv_nsec = (rem_timeout % 1000) * 1000000;
954 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
955 if (ret == -1) {
956 coap_log(LOG_ERR,
957 "%s: timerfd_settime failed: %s (%d)\n",
958 "coap_wait_ack",
959 coap_socket_strerror(), errno);
960 }
961 }
962 }
963 #endif /* COAP_EPOLL_SUPPORT */
964
965 return node->id;
966 }
967
968 coap_tid_t
coap_send(coap_session_t * session,coap_pdu_t * pdu)969 coap_send(coap_session_t *session, coap_pdu_t *pdu) {
970 uint8_t r;
971 ssize_t bytes_written;
972
973 if (!coap_pdu_encode_header(pdu, session->proto)) {
974 goto error;
975 }
976
977 bytes_written = coap_send_pdu( session, pdu, NULL );
978
979 if (bytes_written == COAP_PDU_DELAYED) {
980 /* do not free pdu as it is stored with session for later use */
981 return pdu->tid;
982 }
983
984 if (bytes_written < 0) {
985 coap_delete_pdu(pdu);
986 return (coap_tid_t)bytes_written;
987 }
988
989 if (COAP_PROTO_RELIABLE(session->proto) &&
990 (size_t)bytes_written < pdu->used_size + pdu->hdr_size) {
991 if (coap_session_delay_pdu(session, pdu, NULL) == COAP_PDU_DELAYED) {
992 session->partial_write = (size_t)bytes_written;
993 /* do not free pdu as it is stored with session for later use */
994 return pdu->tid;
995 } else {
996 goto error;
997 }
998 }
999
1000 if (pdu->type != COAP_MESSAGE_CON || COAP_PROTO_RELIABLE(session->proto)) {
1001 coap_tid_t id = pdu->tid;
1002 coap_delete_pdu(pdu);
1003 return id;
1004 }
1005
1006 coap_queue_t *node = coap_new_node();
1007 if (!node) {
1008 coap_log(LOG_DEBUG, "coap_wait_ack: insufficient memory\n");
1009 goto error;
1010 }
1011
1012 node->id = pdu->tid;
1013 node->pdu = pdu;
1014 prng(&r, sizeof(r));
1015 /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
1016 node->timeout = coap_calc_timeout(session, r);
1017 return coap_wait_ack(session->context, session, node);
1018 error:
1019 coap_delete_pdu(pdu);
1020 return COAP_INVALID_TID;
1021 }
1022
1023 coap_tid_t
coap_retransmit(coap_context_t * context,coap_queue_t * node)1024 coap_retransmit(coap_context_t *context, coap_queue_t *node) {
1025 if (!context || !node)
1026 return COAP_INVALID_TID;
1027
1028 /* re-initialize timeout when maximum number of retransmissions are not reached yet */
1029 if (node->retransmit_cnt < node->session->max_retransmit) {
1030 ssize_t bytes_written;
1031 coap_tick_t now;
1032
1033 node->retransmit_cnt++;
1034 coap_ticks(&now);
1035 if (context->sendqueue == NULL) {
1036 node->t = node->timeout << node->retransmit_cnt;
1037 context->sendqueue_basetime = now;
1038 } else {
1039 /* make node->t relative to context->sendqueue_basetime */
1040 node->t = (now - context->sendqueue_basetime) + (node->timeout << node->retransmit_cnt);
1041 }
1042 coap_insert_node(&context->sendqueue, node);
1043 #ifdef WITH_LWIP
1044 if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
1045 coap_retransmittimer_restart(context);
1046 #endif
1047
1048 coap_log(LOG_DEBUG, "** %s: tid=%d: retransmission #%d\n",
1049 coap_session_str(node->session), node->id, node->retransmit_cnt);
1050
1051 if (node->session->con_active)
1052 node->session->con_active--;
1053 bytes_written = coap_send_pdu(node->session, node->pdu, node);
1054
1055 if (bytes_written == COAP_PDU_DELAYED) {
1056 /* PDU was not retransmitted immediately because a new handshake is
1057 in progress. node was moved to the send queue of the session. */
1058 return node->id;
1059 }
1060
1061 if (bytes_written < 0)
1062 return (int)bytes_written;
1063
1064 return node->id;
1065 }
1066
1067 /* no more retransmissions, remove node from system */
1068
1069 #ifndef WITH_CONTIKI
1070 coap_log(LOG_DEBUG, "** %s: tid=%d: give up after %d attempts\n",
1071 coap_session_str(node->session), node->id, node->retransmit_cnt);
1072 #endif
1073
1074 #ifndef WITHOUT_OBSERVE
1075 /* Check if subscriptions exist that should be canceled after
1076 COAP_MAX_NOTIFY_FAILURES */
1077 if (node->pdu->code >= 64) {
1078 coap_binary_t token = { 0, NULL };
1079
1080 token.length = node->pdu->token_length;
1081 token.s = node->pdu->token;
1082
1083 coap_handle_failed_notify(context, node->session, &token);
1084 }
1085 #endif /* WITHOUT_OBSERVE */
1086 if (node->session->con_active) {
1087 node->session->con_active--;
1088 if (node->session->state == COAP_SESSION_STATE_ESTABLISHED) {
1089 /*
1090 * As there may be another CON in a different queue entry on the same
1091 * session that needs to be immediately released,
1092 * coap_session_connected() is called.
1093 * However, there is the possibility coap_wait_ack() may be called for
1094 * this node (queue) and re-added to context->sendqueue.
1095 * coap_delete_node(node) called shortly will handle this and remove it.
1096 */
1097 coap_session_connected(node->session);
1098 }
1099 }
1100
1101 /* And finally delete the node */
1102 if (node->pdu->type == COAP_MESSAGE_CON && context->nack_handler)
1103 context->nack_handler(context, node->session, node->pdu, COAP_NACK_TOO_MANY_RETRIES, node->id);
1104 coap_delete_node(node);
1105 return COAP_INVALID_TID;
1106 }
1107
1108 #ifdef WITH_LWIP
1109 /* WITH_LWIP, this is handled by coap_recv in a different way */
1110 void
coap_read(coap_context_t * ctx,coap_tick_t now)1111 coap_read(coap_context_t *ctx, coap_tick_t now) {
1112 return;
1113 }
1114 #else /* WITH_LWIP */
1115
1116 static int
coap_handle_dgram_for_proto(coap_context_t * ctx,coap_session_t * session,coap_packet_t * packet)1117 coap_handle_dgram_for_proto(coap_context_t *ctx, coap_session_t *session, coap_packet_t *packet) {
1118 uint8_t *data;
1119 size_t data_len;
1120 int result = -1;
1121
1122 coap_packet_get_memmapped(packet, &data, &data_len);
1123
1124 if (session->proto == COAP_PROTO_DTLS) {
1125 if (session->type == COAP_SESSION_TYPE_HELLO)
1126 result = coap_dtls_hello(session, data, data_len);
1127 else if (session->tls)
1128 result = coap_dtls_receive(session, data, data_len);
1129 } else if (session->proto == COAP_PROTO_UDP) {
1130 result = coap_handle_dgram(ctx, session, data, data_len);
1131 }
1132 return result;
1133 }
1134
1135 static void
coap_connect_session(coap_context_t * ctx,coap_session_t * session,coap_tick_t now)1136 coap_connect_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) {
1137 (void)ctx;
1138 if (coap_socket_connect_tcp2(&session->sock, &session->addr_info.local,
1139 &session->addr_info.remote)) {
1140 session->last_rx_tx = now;
1141 coap_handle_event(session->context, COAP_EVENT_TCP_CONNECTED, session);
1142 if (session->proto == COAP_PROTO_TCP) {
1143 coap_session_send_csm(session);
1144 } else if (session->proto == COAP_PROTO_TLS) {
1145 int connected = 0;
1146 session->state = COAP_SESSION_STATE_HANDSHAKE;
1147 session->tls = coap_tls_new_client_session(session, &connected);
1148 if (session->tls) {
1149 if (connected) {
1150 coap_handle_event(session->context, COAP_EVENT_DTLS_CONNECTED, session);
1151 coap_session_send_csm(session);
1152 }
1153 } else {
1154 coap_handle_event(session->context, COAP_EVENT_DTLS_ERROR, session);
1155 coap_session_disconnected(session, COAP_NACK_TLS_FAILED);
1156 }
1157 }
1158 } else {
1159 coap_handle_event(session->context, COAP_EVENT_TCP_FAILED, session);
1160 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
1161 }
1162 }
1163
1164 static void
coap_write_session(coap_context_t * ctx,coap_session_t * session,coap_tick_t now)1165 coap_write_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) {
1166 (void)ctx;
1167 assert(session->sock.flags & COAP_SOCKET_CONNECTED);
1168
1169 while (session->delayqueue) {
1170 ssize_t bytes_written;
1171 coap_queue_t *q = session->delayqueue;
1172 coap_log(LOG_DEBUG, "** %s: tid=%d: transmitted after delay\n",
1173 coap_session_str(session), (int)q->pdu->tid);
1174 assert(session->partial_write < q->pdu->used_size + q->pdu->hdr_size);
1175 switch (session->proto) {
1176 case COAP_PROTO_TCP:
1177 bytes_written = coap_session_write(
1178 session,
1179 q->pdu->token - q->pdu->hdr_size - session->partial_write,
1180 q->pdu->used_size + q->pdu->hdr_size - session->partial_write
1181 );
1182 break;
1183 case COAP_PROTO_TLS:
1184 bytes_written = coap_tls_write(
1185 session,
1186 q->pdu->token - q->pdu->hdr_size - session->partial_write,
1187 q->pdu->used_size + q->pdu->hdr_size - session->partial_write
1188 );
1189 break;
1190 default:
1191 bytes_written = -1;
1192 break;
1193 }
1194 if (bytes_written > 0)
1195 session->last_rx_tx = now;
1196 if (bytes_written <= 0 || (size_t)bytes_written < q->pdu->used_size + q->pdu->hdr_size - session->partial_write) {
1197 if (bytes_written > 0)
1198 session->partial_write += (size_t)bytes_written;
1199 break;
1200 }
1201 session->delayqueue = q->next;
1202 session->partial_write = 0;
1203 coap_delete_node(q);
1204 }
1205 }
1206
1207 static void
coap_read_session(coap_context_t * ctx,coap_session_t * session,coap_tick_t now)1208 coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) {
1209 #if COAP_CONSTRAINED_STACK
1210 static coap_mutex_t s_static_mutex = COAP_MUTEX_INITIALIZER;
1211 static coap_packet_t s_packet;
1212 #else /* ! COAP_CONSTRAINED_STACK */
1213 coap_packet_t s_packet;
1214 #endif /* ! COAP_CONSTRAINED_STACK */
1215 coap_packet_t *packet = &s_packet;
1216
1217 #if COAP_CONSTRAINED_STACK
1218 coap_mutex_lock(&s_static_mutex);
1219 #endif /* COAP_CONSTRAINED_STACK */
1220 #ifdef COAP_SUPPORT_SOCKET_BROADCAST
1221 assert(session->sock.flags & (COAP_SOCKET_CONNECTED | COAP_SOCKET_MULTICAST | COAP_SOCKET_BROADCAST));
1222 #else
1223 assert(session->sock.flags & (COAP_SOCKET_CONNECTED | COAP_SOCKET_MULTICAST));
1224 #endif
1225
1226 if (COAP_PROTO_NOT_RELIABLE(session->proto)) {
1227 ssize_t bytes_read;
1228 memcpy(&packet->addr_info, &session->addr_info, sizeof(packet->addr_info));
1229 bytes_read = ctx->network_read(&session->sock, packet);
1230
1231 if (bytes_read < 0) {
1232 if (bytes_read == -2)
1233 /* Reset the session back to startup defaults */
1234 coap_session_disconnected(session, COAP_NACK_ICMP_ISSUE);
1235 else
1236 coap_log(LOG_WARNING, "* %s: read error\n",
1237 coap_session_str(session));
1238 } else if (bytes_read > 0) {
1239 session->last_rx_tx = now;
1240 memcpy(&session->addr_info, &packet->addr_info,
1241 sizeof(session->addr_info));
1242 coap_log(LOG_DEBUG, "* %s: received %zd bytes\n",
1243 coap_session_str(session), bytes_read);
1244 coap_handle_dgram_for_proto(ctx, session, packet);
1245 }
1246 } else {
1247 ssize_t bytes_read = 0;
1248 const uint8_t *p;
1249 int retry;
1250 /* adjust for LWIP */
1251 uint8_t *buf = packet->payload;
1252 size_t buf_len = sizeof(packet->payload);
1253
1254 do {
1255 if (session->proto == COAP_PROTO_TCP)
1256 bytes_read = coap_socket_read(&session->sock, buf, buf_len);
1257 else if (session->proto == COAP_PROTO_TLS)
1258 bytes_read = coap_tls_read(session, buf, buf_len);
1259 if (bytes_read > 0) {
1260 coap_log(LOG_DEBUG, "* %s: received %zd bytes\n",
1261 coap_session_str(session), bytes_read);
1262 session->last_rx_tx = now;
1263 }
1264 p = buf;
1265 retry = bytes_read == (ssize_t)buf_len;
1266 while (bytes_read > 0) {
1267 if (session->partial_pdu) {
1268 size_t len = session->partial_pdu->used_size
1269 + session->partial_pdu->hdr_size
1270 - session->partial_read;
1271 size_t n = min(len, (size_t)bytes_read);
1272 memcpy(session->partial_pdu->token - session->partial_pdu->hdr_size
1273 + session->partial_read, p, n);
1274 p += n;
1275 bytes_read -= n;
1276 if (n == len) {
1277 if (coap_pdu_parse_header(session->partial_pdu, session->proto)
1278 && coap_pdu_parse_opt(session->partial_pdu)) {
1279 coap_dispatch(ctx, session, session->partial_pdu);
1280 }
1281 coap_delete_pdu(session->partial_pdu);
1282 session->partial_pdu = NULL;
1283 session->partial_read = 0;
1284 } else {
1285 session->partial_read += n;
1286 }
1287 } else if (session->partial_read > 0) {
1288 size_t hdr_size = coap_pdu_parse_header_size(session->proto,
1289 session->read_header);
1290 size_t len = hdr_size - session->partial_read;
1291 size_t n = min(len, (size_t)bytes_read);
1292 memcpy(session->read_header + session->partial_read, p, n);
1293 p += n;
1294 bytes_read -= n;
1295 if (n == len) {
1296 size_t size = coap_pdu_parse_size(session->proto, session->read_header,
1297 hdr_size);
1298 session->partial_pdu = coap_pdu_init(0, 0, 0, size);
1299 if (session->partial_pdu == NULL) {
1300 bytes_read = -1;
1301 break;
1302 }
1303 if (session->partial_pdu->alloc_size < size && !coap_pdu_resize(session->partial_pdu, size)) {
1304 bytes_read = -1;
1305 break;
1306 }
1307 session->partial_pdu->hdr_size = (uint8_t)hdr_size;
1308 session->partial_pdu->used_size = size;
1309 memcpy(session->partial_pdu->token - hdr_size, session->read_header, hdr_size);
1310 session->partial_read = hdr_size;
1311 if (size == 0) {
1312 if (coap_pdu_parse_header(session->partial_pdu, session->proto)) {
1313 coap_dispatch(ctx, session, session->partial_pdu);
1314 }
1315 coap_delete_pdu(session->partial_pdu);
1316 session->partial_pdu = NULL;
1317 session->partial_read = 0;
1318 }
1319 } else {
1320 session->partial_read += bytes_read;
1321 }
1322 } else {
1323 session->read_header[0] = *p++;
1324 bytes_read -= 1;
1325 if (!coap_pdu_parse_header_size(session->proto,
1326 session->read_header)) {
1327 bytes_read = -1;
1328 break;
1329 }
1330 session->partial_read = 1;
1331 }
1332 }
1333 } while (bytes_read == 0 && retry);
1334 if (bytes_read < 0)
1335 coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE);
1336 }
1337 #if COAP_CONSTRAINED_STACK
1338 coap_mutex_unlock(&s_static_mutex);
1339 #endif /* COAP_CONSTRAINED_STACK */
1340 }
1341
1342 static int
coap_read_endpoint(coap_context_t * ctx,coap_endpoint_t * endpoint,coap_tick_t now)1343 coap_read_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, coap_tick_t now) {
1344 ssize_t bytes_read = -1;
1345 int result = -1; /* the value to be returned */
1346 #if COAP_CONSTRAINED_STACK
1347 static coap_mutex_t e_static_mutex = COAP_MUTEX_INITIALIZER;
1348 static coap_packet_t e_packet;
1349 #else /* ! COAP_CONSTRAINED_STACK */
1350 coap_packet_t e_packet;
1351 #endif /* ! COAP_CONSTRAINED_STACK */
1352 coap_packet_t *packet = &e_packet;
1353
1354 assert(COAP_PROTO_NOT_RELIABLE(endpoint->proto));
1355 assert(endpoint->sock.flags & COAP_SOCKET_BOUND);
1356
1357 #if COAP_CONSTRAINED_STACK
1358 coap_mutex_lock(&e_static_mutex);
1359 #endif /* COAP_CONSTRAINED_STACK */
1360
1361 /* Need to do this as there may be holes in addr_info */
1362 memset(&packet->addr_info, 0, sizeof(packet->addr_info));
1363 coap_address_init(&packet->addr_info.remote);
1364 coap_address_copy(&packet->addr_info.local, &endpoint->bind_addr);
1365 bytes_read = ctx->network_read(&endpoint->sock, packet);
1366
1367 if (bytes_read < 0) {
1368 coap_log(LOG_WARNING, "* %s: read failed\n", coap_endpoint_str(endpoint));
1369 } else if (bytes_read > 0) {
1370 coap_session_t *session = coap_endpoint_get_session(endpoint, packet, now);
1371 if (session) {
1372 coap_log(LOG_DEBUG, "* %s: received %zd bytes\n",
1373 coap_session_str(session), bytes_read);
1374 result = coap_handle_dgram_for_proto(ctx, session, packet);
1375 if (endpoint->proto == COAP_PROTO_DTLS && session->type == COAP_SESSION_TYPE_HELLO && result == 1)
1376 coap_session_new_dtls_session(session, now);
1377 }
1378 }
1379 #if COAP_CONSTRAINED_STACK
1380 coap_mutex_unlock(&e_static_mutex);
1381 #endif /* COAP_CONSTRAINED_STACK */
1382 return result;
1383 }
1384
1385 static int
coap_write_endpoint(coap_context_t * ctx,coap_endpoint_t * endpoint,coap_tick_t now)1386 coap_write_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, coap_tick_t now) {
1387 (void)ctx;
1388 (void)endpoint;
1389 (void)now;
1390 return 0;
1391 }
1392
1393 static int
coap_accept_endpoint(coap_context_t * ctx,coap_endpoint_t * endpoint,coap_tick_t now)1394 coap_accept_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint,
1395 coap_tick_t now) {
1396 coap_session_t *session = coap_new_server_session(ctx, endpoint);
1397 if (session)
1398 session->last_rx_tx = now;
1399 return session != NULL;
1400 }
1401
1402 void
coap_read(coap_context_t * ctx,coap_tick_t now)1403 coap_read(coap_context_t *ctx, coap_tick_t now) {
1404 #ifdef COAP_EPOLL_SUPPORT
1405 (void)ctx;
1406 (void)now;
1407 coap_log(LOG_EMERG,
1408 "coap_read() requires libcoap not compiled for using epoll\n");
1409 #else /* ! COAP_EPOLL_SUPPORT */
1410 coap_endpoint_t *ep, *tmp;
1411 coap_session_t *s, *rtmp;
1412 int session_may_freed;
1413 coap_session_type_t session_type;
1414 LL_FOREACH_SAFE(ctx->endpoint, ep, tmp) {
1415 if ((ep->sock.flags & COAP_SOCKET_CAN_READ) != 0)
1416 coap_read_endpoint(ctx, ep, now);
1417 if ((ep->sock.flags & COAP_SOCKET_CAN_WRITE) != 0)
1418 coap_write_endpoint(ctx, ep, now);
1419 if ((ep->sock.flags & COAP_SOCKET_CAN_ACCEPT) != 0)
1420 coap_accept_endpoint(ctx, ep, now);
1421 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1422 session_may_freed = 0;
1423 session_type = s->type;
1424 if ((s->sock.flags & COAP_SOCKET_CAN_READ) != 0) {
1425 /* Make sure the session object is not deleted in one of the callbacks */
1426 coap_session_reference(s);
1427 coap_read_session(ctx, s, now);
1428 if (s->ref == 1) {
1429 session_may_freed = 1;
1430 }
1431 coap_session_release(s);
1432 }
1433 if (((session_type != COAP_SESSION_TYPE_CLIENT) || (session_may_freed == 0)) &&
1434 (s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0) {
1435 /* Make sure the session object is not deleted in one of the callbacks */
1436 coap_session_reference(s);
1437 coap_write_session(ctx, s, now);
1438 coap_session_release(s);
1439 }
1440 }
1441 }
1442
1443 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1444 session_may_freed = 0;
1445 session_type = s->type;
1446 if ((s->sock.flags & COAP_SOCKET_CAN_CONNECT) != 0) {
1447 /* Make sure the session object is not deleted in one of the callbacks */
1448 coap_session_reference(s);
1449 coap_connect_session(ctx, s, now);
1450 if (s->ref == 1) {
1451 session_may_freed = 1;
1452 }
1453 coap_session_release( s );
1454 }
1455 if (((session_type != COAP_SESSION_TYPE_CLIENT) || (session_may_freed == 0)) &&
1456 (s->sock.flags & COAP_SOCKET_CAN_READ) != 0) {
1457 /* Make sure the session object is not deleted in one of the callbacks */
1458 coap_session_reference(s);
1459 coap_read_session(ctx, s, now);
1460 if (s->ref == 1) {
1461 session_may_freed = 1;
1462 }
1463 coap_session_release(s);
1464 }
1465 if (((session_type != COAP_SESSION_TYPE_CLIENT) || (session_may_freed == 0)) &&
1466 (s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0) {
1467 /* Make sure the session object is not deleted in one of the callbacks */
1468 coap_session_reference(s);
1469 coap_write_session(ctx, s, now);
1470 coap_session_release( s );
1471 }
1472 }
1473 #endif /* ! COAP_EPOLL_SUPPORT */
1474 }
1475
1476 /*
1477 * While this code in part replicates coap_read(), doing the functions
1478 * directly saves having to iterate through the endpoints / sessions.
1479 */
1480 void
coap_io_do_events(coap_context_t * ctx,struct epoll_event * events,size_t nevents)1481 coap_io_do_events(coap_context_t *ctx, struct epoll_event *events, size_t nevents) {
1482 #ifndef COAP_EPOLL_SUPPORT
1483 (void)ctx;
1484 (void)events;
1485 (void)nevents;
1486 coap_log(LOG_EMERG,
1487 "coap_io_do_events() requires libcoap compiled for using epoll\n");
1488 #else /* COAP_EPOLL_SUPPORT */
1489 coap_tick_t now;
1490 size_t j;
1491
1492 coap_ticks(&now);
1493 for(j = 0; j < nevents; j++) {
1494 coap_socket_t *sock = (coap_socket_t*)events[j].data.ptr;
1495
1496 /* Ignore 'timer trigger' ptr which is NULL */
1497 if (sock) {
1498 if (sock->endpoint) {
1499 coap_endpoint_t *endpoint = sock->endpoint;
1500 if ((sock->flags & COAP_SOCKET_WANT_READ) &&
1501 (events[j].events & EPOLLIN)) {
1502 sock->flags |= COAP_SOCKET_CAN_READ;
1503 coap_read_endpoint(endpoint->context, endpoint, now);
1504 }
1505
1506 if ((sock->flags & COAP_SOCKET_WANT_WRITE) &&
1507 (events[j].events & EPOLLOUT)) {
1508 /*
1509 * Need to update this to EPOLLIN as EPOLLOUT will normally always
1510 * be true causing epoll_wait to return early
1511 */
1512 coap_epoll_ctl_mod(sock, EPOLLIN, __func__);
1513 sock->flags |= COAP_SOCKET_CAN_WRITE;
1514 coap_write_endpoint(endpoint->context, endpoint, now);
1515 }
1516
1517 if ((sock->flags & COAP_SOCKET_WANT_ACCEPT) &&
1518 (events[j].events & EPOLLIN)) {
1519 sock->flags |= COAP_SOCKET_CAN_ACCEPT;
1520 coap_accept_endpoint(endpoint->context, endpoint, now);
1521 }
1522
1523 }
1524 else if (sock->session) {
1525 coap_session_t *session = sock->session;
1526
1527 if ((sock->flags & COAP_SOCKET_WANT_CONNECT) &&
1528 (events[j].events & (EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
1529 sock->flags |= COAP_SOCKET_CAN_CONNECT;
1530 /* Make sure the session object is not deleted
1531 in one of the callbacks */
1532 coap_session_reference(session);
1533 coap_connect_session(session->context, session, now);
1534 coap_session_release(session);
1535 }
1536
1537 if ((sock->flags & COAP_SOCKET_WANT_READ) &&
1538 (events[j].events & (EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
1539 sock->flags |= COAP_SOCKET_CAN_READ;
1540 /* Make sure the session object is not deleted
1541 in one of the callbacks */
1542 coap_session_reference(session);
1543 coap_read_session(session->context, session, now);
1544 coap_session_release(session);
1545 }
1546
1547 if ((sock->flags & COAP_SOCKET_WANT_WRITE) &&
1548 (events[j].events & (EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) {
1549 /*
1550 * Need to update this to EPOLLIN as EPOLLOUT will normally always
1551 * be true causing epoll_wait to return early
1552 */
1553 coap_epoll_ctl_mod(sock, EPOLLIN, __func__);
1554 sock->flags |= COAP_SOCKET_CAN_WRITE;
1555 /* Make sure the session object is not deleted
1556 in one of the callbacks */
1557 coap_session_reference(session);
1558 coap_write_session(session->context, session, now);
1559 coap_session_release(session);
1560 }
1561 }
1562 }
1563 else if (ctx->eptimerfd != -1) {
1564 /*
1565 * 'timer trigger' must have fired. eptimerfd needs to be read to clear
1566 * it so that it does not set EPOLLIN in the next epoll_wait().
1567 */
1568 uint64_t count;
1569
1570 read(ctx->eptimerfd, &count, sizeof(count));
1571 /* And process any timed out events */
1572 coap_ticks(&now);
1573 coap_io_prepare_epoll(ctx, now);
1574 }
1575 }
1576 #endif /* COAP_EPOLL_SUPPORT */
1577 }
1578
1579 int
coap_handle_dgram(coap_context_t * ctx,coap_session_t * session,uint8_t * msg,size_t msg_len)1580 coap_handle_dgram(coap_context_t *ctx, coap_session_t *session,
1581 uint8_t *msg, size_t msg_len) {
1582
1583 coap_pdu_t *pdu = NULL;
1584
1585 assert(COAP_PROTO_NOT_RELIABLE(session->proto));
1586
1587 pdu = coap_pdu_init(0, 0, 0, msg_len - 4);
1588 if (!pdu)
1589 goto error;
1590
1591 if (!coap_pdu_parse(session->proto, msg, msg_len, pdu)) {
1592 coap_log(LOG_WARNING, "discard malformed PDU\n");
1593 goto error;
1594 }
1595
1596 coap_dispatch(ctx, session, pdu);
1597 coap_delete_pdu(pdu);
1598 return 0;
1599
1600 error:
1601 /* FIXME: send back RST? */
1602 coap_delete_pdu(pdu);
1603 return -1;
1604 }
1605 #endif /* not WITH_LWIP */
1606
1607 int
coap_remove_from_queue(coap_queue_t ** queue,coap_session_t * session,coap_tid_t id,coap_queue_t ** node)1608 coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_tid_t id, coap_queue_t **node) {
1609 coap_queue_t *p, *q;
1610
1611 if (!queue || !*queue)
1612 return 0;
1613
1614 /* replace queue head if PDU's time is less than head's time */
1615
1616 if (session == (*queue)->session && id == (*queue)->id) { /* found transaction */
1617 *node = *queue;
1618 *queue = (*queue)->next;
1619 if (*queue) { /* adjust relative time of new queue head */
1620 (*queue)->t += (*node)->t;
1621 }
1622 (*node)->next = NULL;
1623 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1624 coap_session_str(session), id);
1625 return 1;
1626 }
1627
1628 /* search transaction to remove (only first occurence will be removed) */
1629 q = *queue;
1630 do {
1631 p = q;
1632 q = q->next;
1633 } while (q && (session != q->session || id != q->id));
1634
1635 if (q) { /* found transaction */
1636 p->next = q->next;
1637 if (p->next) { /* must update relative time of p->next */
1638 p->next->t += q->t;
1639 }
1640 q->next = NULL;
1641 *node = q;
1642 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1643 coap_session_str(session), id);
1644 return 1;
1645 }
1646
1647 return 0;
1648
1649 }
1650
1651 COAP_STATIC_INLINE int
token_match(const uint8_t * a,size_t alen,const uint8_t * b,size_t blen)1652 token_match(const uint8_t *a, size_t alen,
1653 const uint8_t *b, size_t blen) {
1654 return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0);
1655 }
1656
1657 void
coap_cancel_session_messages(coap_context_t * context,coap_session_t * session,coap_nack_reason_t reason)1658 coap_cancel_session_messages(coap_context_t *context, coap_session_t *session,
1659 coap_nack_reason_t reason) {
1660 coap_queue_t *p, *q;
1661
1662 while (context->sendqueue && context->sendqueue->session == session) {
1663 q = context->sendqueue;
1664 context->sendqueue = q->next;
1665 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1666 coap_session_str(session), q->id);
1667 if (q->pdu->type == COAP_MESSAGE_CON && context->nack_handler)
1668 context->nack_handler(context, session, q->pdu, reason, q->id);
1669 coap_delete_node(q);
1670 }
1671
1672 if (!context->sendqueue)
1673 return;
1674
1675 p = context->sendqueue;
1676 q = p->next;
1677
1678 while (q) {
1679 if (q->session == session) {
1680 p->next = q->next;
1681 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1682 coap_session_str(session), q->id);
1683 if (q->pdu->type == COAP_MESSAGE_CON && context->nack_handler)
1684 context->nack_handler(context, session, q->pdu, reason, q->id);
1685 coap_delete_node(q);
1686 q = p->next;
1687 } else {
1688 p = q;
1689 q = q->next;
1690 }
1691 }
1692 }
1693
1694 void
coap_cancel_all_messages(coap_context_t * context,coap_session_t * session,const uint8_t * token,size_t token_length)1695 coap_cancel_all_messages(coap_context_t *context, coap_session_t *session,
1696 const uint8_t *token, size_t token_length) {
1697 /* cancel all messages in sendqueue that belong to session
1698 * and use the specified token */
1699 coap_queue_t *p, *q;
1700
1701 while (context->sendqueue && context->sendqueue->session == session &&
1702 token_match(token, token_length,
1703 context->sendqueue->pdu->token,
1704 context->sendqueue->pdu->token_length)) {
1705 q = context->sendqueue;
1706 context->sendqueue = q->next;
1707 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1708 coap_session_str(session), q->id);
1709 coap_delete_node(q);
1710 }
1711
1712 if (!context->sendqueue)
1713 return;
1714
1715 p = context->sendqueue;
1716 q = p->next;
1717
1718 /* when q is not NULL, it does not match (dst, token), so we can skip it */
1719 while (q) {
1720 if (q->session == session &&
1721 token_match(token, token_length,
1722 q->pdu->token, q->pdu->token_length)) {
1723 p->next = q->next;
1724 coap_log(LOG_DEBUG, "** %s: tid=%d: removed\n",
1725 coap_session_str(session), q->id);
1726 coap_delete_node(q);
1727 q = p->next;
1728 } else {
1729 p = q;
1730 q = q->next;
1731 }
1732 }
1733 }
1734
1735 coap_queue_t *
coap_find_transaction(coap_queue_t * queue,coap_session_t * session,coap_tid_t id)1736 coap_find_transaction(coap_queue_t *queue, coap_session_t *session, coap_tid_t id) {
1737 while (queue && queue->session != session && queue->id != id)
1738 queue = queue->next;
1739
1740 return queue;
1741 }
1742
1743 coap_pdu_t *
coap_new_error_response(coap_pdu_t * request,unsigned char code,coap_opt_filter_t opts)1744 coap_new_error_response(coap_pdu_t *request, unsigned char code,
1745 coap_opt_filter_t opts) {
1746 coap_opt_iterator_t opt_iter;
1747 coap_pdu_t *response;
1748 size_t size = request->token_length;
1749 unsigned char type;
1750 coap_opt_t *option;
1751 uint16_t opt_type = 0; /* used for calculating delta-storage */
1752
1753 #if COAP_ERROR_PHRASE_LENGTH > 0
1754 const char *phrase = coap_response_phrase(code);
1755
1756 /* Need some more space for the error phrase and payload start marker */
1757 if (phrase)
1758 size += strlen(phrase) + 1;
1759 #endif
1760
1761 assert(request);
1762
1763 /* cannot send ACK if original request was not confirmable */
1764 type = request->type == COAP_MESSAGE_CON
1765 ? COAP_MESSAGE_ACK
1766 : COAP_MESSAGE_NON;
1767
1768 /* Estimate how much space we need for options to copy from
1769 * request. We always need the Token, for 4.02 the unknown critical
1770 * options must be included as well. */
1771 coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */
1772
1773 coap_option_iterator_init(request, &opt_iter, opts);
1774
1775 /* Add size of each unknown critical option. As known critical
1776 options as well as elective options are not copied, the delta
1777 value might grow.
1778 */
1779 while ((option = coap_option_next(&opt_iter))) {
1780 uint16_t delta = opt_iter.type - opt_type;
1781 /* calculate space required to encode (opt_iter.type - opt_type) */
1782 if (delta < 13) {
1783 size++;
1784 } else if (delta < 269) {
1785 size += 2;
1786 } else {
1787 size += 3;
1788 }
1789
1790 /* add coap_opt_length(option) and the number of additional bytes
1791 * required to encode the option length */
1792
1793 size += coap_opt_length(option);
1794 switch (*option & 0x0f) {
1795 case 0x0e:
1796 size++;
1797 /* fall through */
1798 case 0x0d:
1799 size++;
1800 break;
1801 default:
1802 ;
1803 }
1804
1805 opt_type = opt_iter.type;
1806 }
1807
1808 /* Now create the response and fill with options and payload data. */
1809 response = coap_pdu_init(type, code, request->tid, size);
1810 if (response) {
1811 /* copy token */
1812 if (!coap_add_token(response, request->token_length,
1813 request->token)) {
1814 coap_log(LOG_DEBUG, "cannot add token to error response\n");
1815 coap_delete_pdu(response);
1816 return NULL;
1817 }
1818
1819 /* copy all options */
1820 coap_option_iterator_init(request, &opt_iter, opts);
1821 while ((option = coap_option_next(&opt_iter))) {
1822 coap_add_option(response, opt_iter.type,
1823 coap_opt_length(option),
1824 coap_opt_value(option));
1825 }
1826
1827 #if COAP_ERROR_PHRASE_LENGTH > 0
1828 /* note that diagnostic messages do not need a Content-Format option. */
1829 if (phrase)
1830 coap_add_data(response, (size_t)strlen(phrase), (const uint8_t *)phrase);
1831 #endif
1832 }
1833
1834 return response;
1835 }
1836
1837 /**
1838 * Quick hack to determine the size of the resource description for
1839 * .well-known/core.
1840 */
1841 COAP_STATIC_INLINE size_t
get_wkc_len(coap_context_t * context,coap_opt_t * query_filter)1842 get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) {
1843 unsigned char buf[1];
1844 size_t len = 0;
1845
1846 if (coap_print_wellknown(context, buf, &len, UINT_MAX, query_filter)
1847 & COAP_PRINT_STATUS_ERROR) {
1848 coap_log(LOG_WARNING, "cannot determine length of /.well-known/core\n");
1849 return 0;
1850 }
1851
1852 coap_log(LOG_DEBUG, "get_wkc_len: coap_print_wellknown() returned %zu\n", len);
1853
1854 return len;
1855 }
1856
1857 #define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4)))
1858
1859 coap_pdu_t *
coap_wellknown_response(coap_context_t * context,coap_session_t * session,coap_pdu_t * request)1860 coap_wellknown_response(coap_context_t *context, coap_session_t *session,
1861 coap_pdu_t *request) {
1862 coap_pdu_t *resp;
1863 coap_opt_iterator_t opt_iter;
1864 size_t len, wkc_len;
1865 uint8_t buf[4];
1866 int result = 0;
1867 int need_block2 = 0; /* set to 1 if Block2 option is required */
1868 coap_block_t block;
1869 coap_opt_t *query_filter;
1870 size_t offset = 0;
1871 uint8_t *data;
1872
1873 resp = coap_pdu_init(request->type == COAP_MESSAGE_CON
1874 ? COAP_MESSAGE_ACK
1875 : COAP_MESSAGE_NON,
1876 COAP_RESPONSE_CODE(205),
1877 request->tid, coap_session_max_pdu_size(session));
1878 if (!resp) {
1879 coap_log(LOG_DEBUG, "coap_wellknown_response: cannot create PDU\n");
1880 return NULL;
1881 }
1882
1883 if (!coap_add_token(resp, request->token_length, request->token)) {
1884 coap_log(LOG_DEBUG, "coap_wellknown_response: cannot add token\n");
1885 goto error;
1886 }
1887
1888 query_filter = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
1889 wkc_len = get_wkc_len(context, query_filter);
1890
1891 /* The value of some resources is undefined and get_wkc_len will return 0.*/
1892 if (wkc_len == 0) {
1893 coap_log(LOG_DEBUG, "coap_wellknown_response: undefined resource\n");
1894 /* set error code 4.00 Bad Request*/
1895 resp->code = COAP_RESPONSE_CODE(400);
1896 resp->used_size = resp->token_length;
1897 return resp;
1898 }
1899
1900 /* check whether the request contains the Block2 option */
1901 if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
1902 coap_log(LOG_DEBUG, "create block\n");
1903 offset = block.num << (block.szx + 4);
1904 if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */
1905 resp->code = COAP_RESPONSE_CODE(400);
1906 return resp;
1907 } else if (block.szx > COAP_MAX_BLOCK_SZX) {
1908 block.szx = COAP_MAX_BLOCK_SZX;
1909 block.num = (unsigned int)(offset >> (block.szx + 4));
1910 }
1911
1912 need_block2 = 1;
1913 }
1914
1915 /* Check if there is sufficient space to add Content-Format option
1916 * and data. We do this before adding the Content-Format option to
1917 * avoid sending error responses with that option but no actual
1918 * content. */
1919 if (resp->max_size && resp->max_size <= resp->used_size + 8) {
1920 coap_log(LOG_DEBUG, "coap_wellknown_response: insufficient storage space\n");
1921 goto error;
1922 }
1923
1924 /* check if Block2 option is required even if not requested */
1925 if (!need_block2 && resp->max_size && resp->max_size - resp->used_size < wkc_len + 1) {
1926 assert(resp->used_size <= resp->max_size);
1927 const size_t payloadlen = resp->max_size - resp->used_size;
1928 /* yes, need block-wise transfer */
1929 block.num = 0;
1930 block.m = 0; /* the M bit is set by coap_write_block_opt() */
1931 block.szx = COAP_MAX_BLOCK_SZX;
1932 while (payloadlen < SZX_TO_BYTES(block.szx) + 6) {
1933 if (block.szx == 0) {
1934 coap_log(LOG_DEBUG,
1935 "coap_wellknown_response: message to small even for szx == 0\n");
1936 goto error;
1937 } else {
1938 block.szx--;
1939 }
1940 }
1941
1942 need_block2 = 1;
1943 }
1944
1945 if (need_block2) {
1946 /* Add in a pseudo etag (use wkc_len) in case .well-known/core
1947 changes over time */
1948 coap_add_option(resp,
1949 COAP_OPTION_ETAG,
1950 coap_encode_var_safe(buf, sizeof(buf), wkc_len),
1951 buf);
1952 }
1953
1954 /* Add Content-Format. As we have checked for available storage,
1955 * nothing should go wrong here. */
1956 assert(coap_encode_var_safe(buf, sizeof(buf),
1957 COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1);
1958 coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT,
1959 coap_encode_var_safe(buf, sizeof(buf),
1960 COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
1961
1962
1963 /* write Block2 option if necessary */
1964 if (need_block2) {
1965 if (coap_write_block_opt(&block, COAP_OPTION_BLOCK2, resp, wkc_len) < 0) {
1966 coap_log(LOG_DEBUG,
1967 "coap_wellknown_response: cannot add Block2 option\n");
1968 goto error;
1969 }
1970 }
1971
1972 coap_add_option(resp,
1973 COAP_OPTION_SIZE2,
1974 coap_encode_var_safe(buf, sizeof(buf), wkc_len),
1975 buf);
1976
1977 len = need_block2 ?
1978 min(SZX_TO_BYTES(block.szx), wkc_len - (block.num << (block.szx + 4))) :
1979 resp->max_size && resp->used_size + wkc_len + 1 > resp->max_size ?
1980 resp->max_size - resp->used_size - 1 : wkc_len;
1981 data = coap_add_data_after(resp, len);
1982 if (!data) {
1983 coap_log(LOG_DEBUG, "coap_wellknown_response: coap_add_data failed\n" );
1984 goto error;
1985 }
1986
1987 result = coap_print_wellknown(context, data, &len, offset, query_filter);
1988 if ((result & COAP_PRINT_STATUS_ERROR) != 0) {
1989 coap_log(LOG_DEBUG, "coap_print_wellknown failed\n");
1990 goto error;
1991 }
1992
1993 return resp;
1994
1995 error:
1996 /* set error code 5.03 and remove all options and data from response */
1997 resp->code = COAP_RESPONSE_CODE(503);
1998 resp->used_size = resp->token_length;
1999 return resp;
2000 }
2001
2002 /**
2003 * This function cancels outstanding messages for the session and
2004 * token specified in @p sent. Any observation relationship for
2005 * sent->session and the token are removed. Calling this function is
2006 * required when receiving an RST message (usually in response to a
2007 * notification) or a GET request with the Observe option set to 1.
2008 *
2009 * This function returns @c 0 when the token is unknown with this
2010 * peer, or a value greater than zero otherwise.
2011 */
2012 static int
coap_cancel(coap_context_t * context,const coap_queue_t * sent)2013 coap_cancel(coap_context_t *context, const coap_queue_t *sent) {
2014 #ifndef WITHOUT_OBSERVE
2015 coap_binary_t token = { 0, NULL };
2016 int num_cancelled = 0; /* the number of observers cancelled */
2017
2018 /* remove observer for this resource, if any
2019 * get token from sent and try to find a matching resource. Uh!
2020 */
2021
2022 COAP_SET_STR(&token, sent->pdu->token_length, sent->pdu->token);
2023
2024 RESOURCES_ITER(context->resources, r) {
2025 coap_cancel_all_messages(context, sent->session, token.s, token.length);
2026 num_cancelled += coap_delete_observer(r, sent->session, &token);
2027 }
2028
2029 return num_cancelled;
2030 #else /* WITOUT_OBSERVE */
2031 return 0;
2032 #endif /* WITOUT_OBSERVE */
2033 }
2034
2035 /**
2036 * Internal flags to control the treatment of responses (specifically
2037 * in presence of the No-Response option).
2038 */
2039 enum respond_t { RESPONSE_DEFAULT, RESPONSE_DROP, RESPONSE_SEND };
2040
2041 /**
2042 * Checks for No-Response option in given @p request and
2043 * returns @c 1 if @p response should be suppressed
2044 * according to RFC 7967.
2045 *
2046 * The value of the No-Response option is encoded as
2047 * follows:
2048 *
2049 * @verbatim
2050 * +-------+-----------------------+-----------------------------------+
2051 * | Value | Binary Representation | Description |
2052 * +-------+-----------------------+-----------------------------------+
2053 * | 0 | <empty> | Interested in all responses. |
2054 * +-------+-----------------------+-----------------------------------+
2055 * | 2 | 00000010 | Not interested in 2.xx responses. |
2056 * +-------+-----------------------+-----------------------------------+
2057 * | 8 | 00001000 | Not interested in 4.xx responses. |
2058 * +-------+-----------------------+-----------------------------------+
2059 * | 16 | 00010000 | Not interested in 5.xx responses. |
2060 * +-------+-----------------------+-----------------------------------+
2061 * @endverbatim
2062 *
2063 * @param request The CoAP request to check for the No-Response option.
2064 * This parameter must not be NULL.
2065 * @param response The response that is potentially suppressed.
2066 * This parameter must not be NULL.
2067 * @return RESPONSE_DEFAULT when no special treatment is requested,
2068 * RESPONSE_DROP when the response must be discarded, or
2069 * RESPONSE_SEND when the response must be sent.
2070 */
2071 static enum respond_t
no_response(coap_pdu_t * request,coap_pdu_t * response)2072 no_response(coap_pdu_t *request, coap_pdu_t *response) {
2073 coap_opt_t *nores;
2074 coap_opt_iterator_t opt_iter;
2075 unsigned int val = 0;
2076
2077 assert(request);
2078 assert(response);
2079
2080 if (COAP_RESPONSE_CLASS(response->code) > 0) {
2081 nores = coap_check_option(request, COAP_OPTION_NORESPONSE, &opt_iter);
2082
2083 if (nores) {
2084 val = coap_decode_var_bytes(coap_opt_value(nores), coap_opt_length(nores));
2085
2086 /* The response should be dropped when the bit corresponding to
2087 * the response class is set (cf. table in function
2088 * documentation). When a No-Response option is present and the
2089 * bit is not set, the sender explicitly indicates interest in
2090 * this response. */
2091 if (((1 << (COAP_RESPONSE_CLASS(response->code) - 1)) & val) > 0) {
2092 return RESPONSE_DROP;
2093 } else {
2094 return RESPONSE_SEND;
2095 }
2096 }
2097 }
2098
2099 /* Default behavior applies when we are not dealing with a response
2100 * (class == 0) or the request did not contain a No-Response option.
2101 */
2102 return RESPONSE_DEFAULT;
2103 }
2104
2105 static coap_str_const_t coap_default_uri_wellknown =
2106 { sizeof(COAP_DEFAULT_URI_WELLKNOWN)-1,
2107 (const uint8_t *)COAP_DEFAULT_URI_WELLKNOWN };
2108
2109 static void
handle_request(coap_context_t * context,coap_session_t * session,coap_pdu_t * pdu)2110 handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu) {
2111 coap_method_handler_t h = NULL;
2112 coap_pdu_t *response = NULL;
2113 coap_opt_filter_t opt_filter;
2114 coap_resource_t *resource;
2115 /* The respond field indicates whether a response must be treated
2116 * specially due to a No-Response option that declares disinterest
2117 * or interest in a specific response class. DEFAULT indicates that
2118 * No-Response has not been specified. */
2119 enum respond_t respond = RESPONSE_DEFAULT;
2120
2121 coap_option_filter_clear(opt_filter);
2122
2123 /* try to find the resource from the request URI */
2124 coap_string_t *uri_path = coap_get_uri_path(pdu);
2125 if (!uri_path)
2126 return;
2127 coap_str_const_t uri_path_c = { uri_path->length, uri_path->s };
2128 resource = coap_get_resource_from_uri_path(context, &uri_path_c);
2129
2130 if ((resource == NULL) || (resource->is_unknown == 1)) {
2131 /* The resource was not found or there is an unexpected match against the
2132 * resource defined for handling unknown URIs.
2133 * Check if the request URI happens to be the well-known URI, or if the
2134 * unknown resource handler is defined, a PUT or optionally other methods,
2135 * if configured, for the unknown handler.
2136 *
2137 * if well-known URI generate a default response
2138 *
2139 * else if unknown URI handler defined, call the unknown
2140 * URI handler (to allow for potential generation of resource
2141 * [RFC7272 5.8.3]) if the appropriate method is defined.
2142 *
2143 * else if DELETE return 2.02 (RFC7252: 5.8.4. DELETE)
2144 *
2145 * else return 4.04 */
2146
2147 if (coap_string_equal(uri_path, &coap_default_uri_wellknown)) {
2148 /* request for .well-known/core */
2149 if (pdu->code == COAP_REQUEST_GET) { /* GET */
2150 coap_log(LOG_INFO, "create default response for %s\n",
2151 COAP_DEFAULT_URI_WELLKNOWN);
2152 response = coap_wellknown_response(context, session, pdu);
2153 } else {
2154 coap_log(LOG_DEBUG, "method not allowed for .well-known/core\n");
2155 response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(405),
2156 opt_filter);
2157 }
2158 } else if ((context->unknown_resource != NULL) &&
2159 ((size_t)pdu->code - 1 <
2160 (sizeof(resource->handler) / sizeof(coap_method_handler_t))) &&
2161 (context->unknown_resource->handler[pdu->code - 1])) {
2162 /*
2163 * The unknown_resource can be used to handle undefined resources
2164 * for a PUT request and can support any other registered handler
2165 * defined for it
2166 * Example set up code:-
2167 * r = coap_resource_unknown_init(hnd_put_unknown);
2168 * coap_register_handler(r, COAP_REQUEST_POST, hnd_post_unknown);
2169 * coap_register_handler(r, COAP_REQUEST_GET, hnd_get_unknown);
2170 * coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_unknown);
2171 * coap_add_resource(ctx, r);
2172 *
2173 * Note: It is not possible to observe the unknown_resource, a separate
2174 * resource must be created (by PUT or POST) which has a GET
2175 * handler to be observed
2176 */
2177 resource = context->unknown_resource;
2178 } else if (pdu->code == COAP_REQUEST_DELETE) {
2179 /*
2180 * Request for DELETE on non-existant resource (RFC7252: 5.8.4. DELETE)
2181 */
2182 coap_log(LOG_DEBUG, "request for unknown resource '%*.*s',"
2183 " return 2.02\n",
2184 (int)uri_path->length,
2185 (int)uri_path->length,
2186 uri_path->s);
2187 response =
2188 coap_new_error_response(pdu, COAP_RESPONSE_CODE(202),
2189 opt_filter);
2190 } else { /* request for any another resource, return 4.04 */
2191
2192 coap_log(LOG_DEBUG, "request for unknown resource '%*.*s', return 4.04\n",
2193 (int)uri_path->length, (int)uri_path->length, uri_path->s);
2194 response =
2195 coap_new_error_response(pdu, COAP_RESPONSE_CODE(404),
2196 opt_filter);
2197 }
2198
2199 if (!resource) {
2200 if (response && (no_response(pdu, response) != RESPONSE_DROP)) {
2201 if (coap_send(session, response) == COAP_INVALID_TID)
2202 coap_log(LOG_WARNING, "cannot send response for transaction %u\n",
2203 pdu->tid);
2204 } else {
2205 coap_delete_pdu(response);
2206 }
2207
2208 response = NULL;
2209
2210 coap_delete_string(uri_path);
2211 return;
2212 } else {
2213 if (response) {
2214 /* Need to delete unused response - it will get re-created further on */
2215 coap_delete_pdu(response);
2216 }
2217 }
2218 }
2219
2220 /* the resource was found, check if there is a registered handler */
2221 if ((size_t)pdu->code - 1 <
2222 sizeof(resource->handler) / sizeof(coap_method_handler_t))
2223 h = resource->handler[pdu->code - 1];
2224
2225 if (h) {
2226 coap_string_t *query = coap_get_query(pdu);
2227 int owns_query = 1;
2228 coap_log(LOG_DEBUG, "call custom handler for resource '%*.*s'\n",
2229 (int)resource->uri_path->length, (int)resource->uri_path->length,
2230 resource->uri_path->s);
2231 response = coap_pdu_init(pdu->type == COAP_MESSAGE_CON
2232 ? COAP_MESSAGE_ACK
2233 : COAP_MESSAGE_NON,
2234 0, pdu->tid, coap_session_max_pdu_size(session));
2235
2236 /* Implementation detail: coap_add_token() immediately returns 0
2237 if response == NULL */
2238 if (coap_add_token(response, pdu->token_length, pdu->token)) {
2239 coap_binary_t token = { pdu->token_length, pdu->token };
2240 coap_opt_iterator_t opt_iter;
2241 coap_opt_t *observe = NULL;
2242 int observe_action = COAP_OBSERVE_CANCEL;
2243
2244 /* check for Observe option */
2245 if (resource->observable) {
2246 observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
2247 if (observe) {
2248 observe_action =
2249 coap_decode_var_bytes(coap_opt_value(observe),
2250 coap_opt_length(observe));
2251
2252 if ((observe_action & COAP_OBSERVE_CANCEL) == 0) {
2253 coap_subscription_t *subscription;
2254 coap_block_t block2;
2255 int has_block2 = 0;
2256
2257 if (coap_get_block(pdu, COAP_OPTION_BLOCK2, &block2)) {
2258 has_block2 = 1;
2259 }
2260 subscription = coap_add_observer(resource, session, &token, query, has_block2, block2);
2261 owns_query = 0;
2262 if (subscription) {
2263 coap_touch_observer(context, session, &token);
2264 }
2265 } else {
2266 coap_delete_observer(resource, session, &token);
2267 }
2268 }
2269 }
2270
2271 h(context, resource, session, pdu, &token, query, response);
2272
2273 if (query && owns_query)
2274 coap_delete_string(query);
2275
2276 respond = no_response(pdu, response);
2277 if (respond != RESPONSE_DROP) {
2278 if (observe && (COAP_RESPONSE_CLASS(response->code) > 2)) {
2279 coap_delete_observer(resource, session, &token);
2280 }
2281
2282 /* If original request contained a token, and the registered
2283 * application handler made no changes to the response, then
2284 * this is an empty ACK with a token, which is a malformed
2285 * PDU */
2286 if ((response->type == COAP_MESSAGE_ACK)
2287 && (response->code == 0)) {
2288 /* Remove token from otherwise-empty acknowledgment PDU */
2289 response->token_length = 0;
2290 response->used_size = 0;
2291 }
2292
2293 if ((respond == RESPONSE_SEND)
2294 || /* RESPOND_DEFAULT */
2295 (response->type != COAP_MESSAGE_NON ||
2296 (response->code >= 64
2297 && !coap_mcast_interface(&node->local_if)))) {
2298
2299 if (coap_send(session, response) == COAP_INVALID_TID)
2300 coap_log(LOG_DEBUG, "cannot send response for message %d\n",
2301 pdu->tid);
2302 } else {
2303 coap_delete_pdu(response);
2304 }
2305 } else {
2306 coap_delete_pdu(response);
2307 }
2308 response = NULL;
2309 } else {
2310 coap_log(LOG_WARNING, "cannot generate response\r\n");
2311 }
2312 } else {
2313 if (coap_string_equal(uri_path, &coap_default_uri_wellknown)) {
2314 /* request for .well-known/core */
2315 coap_log(LOG_DEBUG, "create default response for %s\n",
2316 COAP_DEFAULT_URI_WELLKNOWN);
2317 response = coap_wellknown_response(context, session, pdu);
2318 coap_log(LOG_DEBUG, "have wellknown response %p\n", (void *)response);
2319 } else
2320 response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(405),
2321 opt_filter);
2322
2323 if (response && (no_response(pdu, response) != RESPONSE_DROP)) {
2324 if (coap_send(session, response) == COAP_INVALID_TID)
2325 coap_log(LOG_DEBUG, "cannot send response for transaction %d\n",
2326 pdu->tid);
2327 } else {
2328 coap_delete_pdu(response);
2329 }
2330 response = NULL;
2331 }
2332
2333 assert(response == NULL);
2334 coap_delete_string(uri_path);
2335 }
2336
2337 static void
handle_response(coap_context_t * context,coap_session_t * session,coap_pdu_t * sent,coap_pdu_t * rcvd)2338 handle_response(coap_context_t *context, coap_session_t *session,
2339 coap_pdu_t *sent, coap_pdu_t *rcvd) {
2340
2341 coap_send_ack(session, rcvd);
2342
2343 /* In a lossy context, the ACK of a separate response may have
2344 * been lost, so we need to stop retransmitting requests with the
2345 * same token.
2346 */
2347 if (rcvd->token_length != 0) {
2348 coap_cancel_all_messages(context, session, rcvd->token, rcvd->token_length);
2349 }
2350
2351 /* Call application-specific response handler when available. */
2352 if (context->response_handler) {
2353 context->response_handler(context, session, sent, rcvd, rcvd->tid);
2354 }
2355 }
2356
2357 static void
handle_signaling(coap_context_t * context,coap_session_t * session,coap_pdu_t * pdu)2358 handle_signaling(coap_context_t *context, coap_session_t *session,
2359 coap_pdu_t *pdu) {
2360 coap_opt_iterator_t opt_iter;
2361 coap_opt_t *option;
2362 (void)context;
2363
2364 coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
2365
2366 if (pdu->code == COAP_SIGNALING_CSM) {
2367 while ((option = coap_option_next(&opt_iter))) {
2368 if (opt_iter.type == COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE) {
2369 coap_session_set_mtu(session, coap_decode_var_bytes(coap_opt_value(option),
2370 coap_opt_length(option)));
2371 } else if (opt_iter.type == COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER) {
2372 /* ... */
2373 }
2374 }
2375 if (session->state == COAP_SESSION_STATE_CSM)
2376 coap_session_connected(session);
2377 } else if (pdu->code == COAP_SIGNALING_PING) {
2378 coap_pdu_t *pong = coap_pdu_init(COAP_MESSAGE_CON, COAP_SIGNALING_PONG, 0, 1);
2379 if (context->ping_handler) {
2380 context->ping_handler(context, session, pdu, pdu->tid);
2381 }
2382 if (pong) {
2383 coap_add_option(pong, COAP_SIGNALING_OPTION_CUSTODY, 0, NULL);
2384 coap_send(session, pong);
2385 }
2386 } else if (pdu->code == COAP_SIGNALING_PONG) {
2387 session->last_pong = session->last_rx_tx;
2388 if (context->pong_handler) {
2389 context->pong_handler(context, session, pdu, pdu->tid);
2390 }
2391 } else if (pdu->code == COAP_SIGNALING_RELEASE
2392 || pdu->code == COAP_SIGNALING_ABORT) {
2393 coap_session_disconnected(session, COAP_NACK_RST);
2394 }
2395 }
2396
2397 void
coap_dispatch(coap_context_t * context,coap_session_t * session,coap_pdu_t * pdu)2398 coap_dispatch(coap_context_t *context, coap_session_t *session,
2399 coap_pdu_t *pdu) {
2400 coap_queue_t *sent = NULL;
2401 coap_pdu_t *response;
2402 coap_opt_filter_t opt_filter;
2403 int is_ping_rst;
2404
2405 if (LOG_DEBUG <= coap_get_log_level()) {
2406 #ifndef INET6_ADDRSTRLEN
2407 #define INET6_ADDRSTRLEN 40
2408 #endif
2409 /* FIXME: get debug to work again **
2410 unsigned char addr[INET6_ADDRSTRLEN+8], localaddr[INET6_ADDRSTRLEN+8];
2411 if (coap_print_addr(remote, addr, INET6_ADDRSTRLEN+8) &&
2412 coap_print_addr(&packet->dst, localaddr, INET6_ADDRSTRLEN+8) )
2413 coap_log(LOG_DEBUG, "** received %d bytes from %s on interface %s:\n",
2414 (int)msg_len, addr, localaddr);
2415
2416 */
2417 coap_show_pdu(LOG_DEBUG, pdu);
2418 }
2419
2420 memset(opt_filter, 0, sizeof(coap_opt_filter_t));
2421
2422 switch (pdu->type) {
2423 case COAP_MESSAGE_ACK:
2424 /* find transaction in sendqueue to stop retransmission */
2425 coap_remove_from_queue(&context->sendqueue, session, pdu->tid, &sent);
2426
2427 if (session->con_active) {
2428 session->con_active--;
2429 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
2430 /* Flush out any entries on session->delayqueue */
2431 coap_session_connected(session);
2432 }
2433 if (pdu->code == 0)
2434 goto cleanup;
2435
2436 /* if sent code was >= 64 the message might have been a
2437 * notification. Then, we must flag the observer to be alive
2438 * by setting obs->fail_cnt = 0. */
2439 if (sent && COAP_RESPONSE_CLASS(sent->pdu->code) == 2) {
2440 const coap_binary_t token =
2441 { sent->pdu->token_length, sent->pdu->token };
2442 coap_touch_observer(context, sent->session, &token);
2443 }
2444 break;
2445
2446 case COAP_MESSAGE_RST:
2447 /* We have sent something the receiver disliked, so we remove
2448 * not only the transaction but also the subscriptions we might
2449 * have. */
2450 is_ping_rst = 0;
2451 if (pdu->tid == session->last_ping_mid &&
2452 context->ping_timeout && session->last_ping > 0)
2453 is_ping_rst = 1;
2454
2455 if (!is_ping_rst)
2456 coap_log(LOG_ALERT, "got RST for message %d\n", pdu->tid);
2457
2458 if (session->con_active) {
2459 session->con_active--;
2460 if (session->state == COAP_SESSION_STATE_ESTABLISHED)
2461 /* Flush out any entries on session->delayqueue */
2462 coap_session_connected(session);
2463 }
2464
2465 /* find transaction in sendqueue to stop retransmission */
2466 coap_remove_from_queue(&context->sendqueue, session, pdu->tid, &sent);
2467
2468 if (sent) {
2469 coap_cancel(context, sent);
2470
2471 if (!is_ping_rst) {
2472 if(sent->pdu->type==COAP_MESSAGE_CON && context->nack_handler)
2473 context->nack_handler(context, sent->session, sent->pdu,
2474 COAP_NACK_RST, sent->id);
2475 }
2476 else {
2477 if (context->pong_handler) {
2478 context->pong_handler(context, session, pdu, pdu->tid);
2479 }
2480 session->last_pong = session->last_rx_tx;
2481 session->last_ping_mid = COAP_INVALID_TID;
2482 }
2483 }
2484 else {
2485 /* Need to check is there is a subscription active and delete it */
2486 RESOURCES_ITER(context->resources, r) {
2487 coap_subscription_t *obs, *tmp;
2488 LL_FOREACH_SAFE(r->subscribers, obs, tmp) {
2489 if (obs->tid == pdu->tid && obs->session == session) {
2490 coap_binary_t token = { 0, NULL };
2491 COAP_SET_STR(&token, obs->token_length, obs->token);
2492 coap_delete_observer(r, session, &token);
2493 goto cleanup;
2494 }
2495 }
2496 }
2497 }
2498 goto cleanup;
2499
2500 case COAP_MESSAGE_NON: /* check for unknown critical options */
2501 if (coap_option_check_critical(context, pdu, opt_filter) == 0)
2502 goto cleanup;
2503 break;
2504
2505 case COAP_MESSAGE_CON: /* check for unknown critical options */
2506 if (coap_option_check_critical(context, pdu, opt_filter) == 0) {
2507
2508 /* FIXME: send response only if we have received a request. Otherwise,
2509 * send RST. */
2510 response =
2511 coap_new_error_response(pdu, COAP_RESPONSE_CODE(402), opt_filter);
2512
2513 if (!response) {
2514 coap_log(LOG_WARNING,
2515 "coap_dispatch: cannot create error response\n");
2516 } else {
2517 if (coap_send(session, response) == COAP_INVALID_TID)
2518 coap_log(LOG_WARNING, "coap_dispatch: error sending response\n");
2519 }
2520
2521 goto cleanup;
2522 }
2523 default: break;
2524 }
2525
2526 /* Pass message to upper layer if a specific handler was
2527 * registered for a request that should be handled locally. */
2528 if (COAP_PDU_IS_SIGNALING(pdu))
2529 handle_signaling(context, session, pdu);
2530 else if (COAP_PDU_IS_REQUEST(pdu))
2531 handle_request(context, session, pdu);
2532 else if (COAP_PDU_IS_RESPONSE(pdu))
2533 handle_response(context, session, sent ? sent->pdu : NULL, pdu);
2534 else {
2535 if (COAP_PDU_IS_EMPTY(pdu)) {
2536 if (context->ping_handler) {
2537 context->ping_handler(context, session,
2538 pdu, pdu->tid);
2539 }
2540 }
2541 coap_log(LOG_DEBUG, "dropped message with invalid code (%d.%02d)\n",
2542 COAP_RESPONSE_CLASS(pdu->code),
2543 pdu->code & 0x1f);
2544
2545 if (!coap_is_mcast(&session->addr_info.local)) {
2546 if (COAP_PDU_IS_EMPTY(pdu)) {
2547 if (session->proto != COAP_PROTO_TCP && session->proto != COAP_PROTO_TLS) {
2548 coap_tick_t now;
2549 coap_ticks(&now);
2550 if (session->last_tx_rst + COAP_TICKS_PER_SECOND/4 < now) {
2551 coap_send_message_type(session, pdu, COAP_MESSAGE_RST);
2552 session->last_tx_rst = now;
2553 }
2554 }
2555 }
2556 else {
2557 coap_send_message_type(session, pdu, COAP_MESSAGE_RST);
2558 }
2559 }
2560 }
2561
2562 cleanup:
2563 coap_delete_node(sent);
2564 }
2565
2566 int
coap_handle_event(coap_context_t * context,coap_event_t event,coap_session_t * session)2567 coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session) {
2568 coap_log(LOG_DEBUG, "***EVENT: 0x%04x\n", event);
2569
2570 if (context->handle_event) {
2571 return context->handle_event(context, event, session);
2572 } else {
2573 return 0;
2574 }
2575 }
2576
2577 int
coap_can_exit(coap_context_t * context)2578 coap_can_exit(coap_context_t *context) {
2579 coap_endpoint_t *ep;
2580 coap_session_t *s, *rtmp;
2581 if (!context)
2582 return 1;
2583 if (context->sendqueue)
2584 return 0;
2585 LL_FOREACH(context->endpoint, ep) {
2586 SESSIONS_ITER(ep->sessions, s, rtmp) {
2587 if (s->delayqueue)
2588 return 0;
2589 }
2590 }
2591 SESSIONS_ITER(context->sessions, s, rtmp) {
2592 if (s->delayqueue)
2593 return 0;
2594 }
2595 return 1;
2596 }
2597
2598 static int coap_started = 0;
2599
coap_startup(void)2600 void coap_startup(void) {
2601 coap_tick_t now;
2602 uint64_t us;
2603 if (coap_started)
2604 return;
2605 coap_started = 1;
2606 #if defined(HAVE_WINSOCK2_H)
2607 WORD wVersionRequested = MAKEWORD(2, 2);
2608 WSADATA wsaData;
2609 WSAStartup(wVersionRequested, &wsaData);
2610 #endif
2611 coap_clock_init();
2612 coap_ticks(&now);
2613 us = coap_ticks_to_rt_us(now);
2614 /* Be accurate to the nearest (approx) us */
2615 prng_init(us);
2616 coap_dtls_startup();
2617 }
2618
coap_cleanup(void)2619 void coap_cleanup(void) {
2620 #if defined(HAVE_WINSOCK2_H)
2621 WSACleanup();
2622 #endif
2623 }
2624
2625 #if ! defined WITH_CONTIKI && ! defined WITH_LWIP
2626 int
coap_join_mcast_group(coap_context_t * ctx,const char * group_name)2627 coap_join_mcast_group(coap_context_t *ctx, const char *group_name) {
2628 struct ipv6_mreq mreq;
2629 struct addrinfo *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
2630 int result = -1;
2631 coap_endpoint_t *endpoint;
2632 int mgroup_setup = 0;
2633
2634 /* we have to resolve the link-local interface to get the interface id */
2635 memset(&hints, 0, sizeof(hints));
2636 hints.ai_family = AF_INET6;
2637 hints.ai_socktype = SOCK_DGRAM;
2638
2639 result = getaddrinfo("::", NULL, &hints, &reslocal);
2640 if (result != 0) {
2641 coap_log(LOG_ERR,
2642 "coap_join_mcast_group: cannot resolve link-local interface: %s\n",
2643 gai_strerror(result));
2644 goto finish;
2645 }
2646
2647 /* get the first suitable interface identifier */
2648 for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
2649 if (ainfo->ai_family == AF_INET6) {
2650 mreq.ipv6mr_interface =
2651 ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
2652 break;
2653 }
2654 }
2655
2656 memset(&hints, 0, sizeof(hints));
2657 hints.ai_family = AF_INET6;
2658 hints.ai_socktype = SOCK_DGRAM;
2659
2660 /* resolve the multicast group address */
2661 result = getaddrinfo(group_name, NULL, &hints, &resmulti);
2662
2663 if (result != 0) {
2664 coap_log(LOG_ERR,
2665 "coap_join_mcast_group: cannot resolve multicast address: %s\n",
2666 gai_strerror(result));
2667 goto finish;
2668 }
2669
2670 for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
2671 if (ainfo->ai_family == AF_INET6) {
2672 mreq.ipv6mr_multiaddr =
2673 ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
2674 break;
2675 }
2676 }
2677
2678 LL_FOREACH(ctx->endpoint, endpoint) {
2679 if (endpoint->proto == COAP_PROTO_UDP ||
2680 endpoint->proto == COAP_PROTO_DTLS) {
2681 result = setsockopt(endpoint->sock.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
2682 (char *)&mreq, sizeof(mreq));
2683 if (result == COAP_SOCKET_ERROR) {
2684 coap_log(LOG_ERR,
2685 "coap_join_mcast_group: setsockopt: %s: '%s'\n",
2686 coap_socket_strerror(), group_name);
2687 }
2688 else {
2689 mgroup_setup = 1;
2690 }
2691 }
2692 }
2693 if (!mgroup_setup) {
2694 result = -1;
2695 }
2696
2697 finish:
2698 freeaddrinfo(resmulti);
2699 freeaddrinfo(reslocal);
2700
2701 return result;
2702 }
2703 #else /* defined WITH_CONTIKI || defined WITH_LWIP */
2704 int
coap_join_mcast_group(coap_context_t * ctx,const char * group_name)2705 coap_join_mcast_group(coap_context_t *ctx, const char *group_name) {
2706 (void)ctx;
2707 (void)group_name;
2708 return -1;
2709 }
2710 #endif /* defined WITH_CONTIKI || defined WITH_LWIP */
2711
2712 #ifdef WITH_CONTIKI
2713
2714 /*---------------------------------------------------------------------------*/
2715 /* CoAP message retransmission */
2716 /*---------------------------------------------------------------------------*/
PROCESS_THREAD(coap_retransmit_process,ev,data)2717 PROCESS_THREAD(coap_retransmit_process, ev, data) {
2718 coap_tick_t now;
2719 coap_queue_t *nextpdu;
2720
2721 PROCESS_BEGIN();
2722
2723 coap_log(LOG_DEBUG, "Started retransmit process\n");
2724
2725 while (1) {
2726 PROCESS_YIELD();
2727 if (ev == PROCESS_EVENT_TIMER) {
2728 if (etimer_expired(&the_coap_context.retransmit_timer)) {
2729
2730 nextpdu = coap_peek_next(&the_coap_context);
2731
2732 coap_ticks(&now);
2733 while (nextpdu && nextpdu->t <= now) {
2734 coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context));
2735 nextpdu = coap_peek_next(&the_coap_context);
2736 }
2737
2738 /* need to set timer to some value even if no nextpdu is available */
2739 etimer_set(&the_coap_context.retransmit_timer,
2740 nextpdu ? nextpdu->t - now : 0xFFFF);
2741 }
2742 #ifndef WITHOUT_OBSERVE
2743 if (etimer_expired(&the_coap_context.notify_timer)) {
2744 coap_check_notify(&the_coap_context);
2745 etimer_reset(&the_coap_context.notify_timer);
2746 }
2747 #endif /* WITHOUT_OBSERVE */
2748 }
2749 }
2750
2751 PROCESS_END();
2752 }
2753 /*---------------------------------------------------------------------------*/
2754
2755 #endif /* WITH_CONTIKI */
2756
2757 #ifdef WITH_LWIP
2758 /* FIXME: retransmits that are not required any more due to incoming packages
2759 * do *not* get cleared at the moment, the wakeup when the transmission is due
2760 * is silently accepted. this is mainly due to the fact that the required
2761 * checks are similar in two places in the code (when receiving ACK and RST)
2762 * and that they cause more than one patch chunk, as it must be first checked
2763 * whether the sendqueue item to be dropped is the next one pending, and later
2764 * the restart function has to be called. nothing insurmountable, but it can
2765 * also be implemented when things have stabilized, and the performance
2766 * penality is minimal
2767 *
2768 * also, this completely ignores COAP_RESOURCE_CHECK_TIME.
2769 * */
2770
coap_retransmittimer_execute(void * arg)2771 static void coap_retransmittimer_execute(void *arg) {
2772 coap_context_t *ctx = (coap_context_t*)arg;
2773 coap_tick_t now;
2774 coap_tick_t elapsed;
2775 coap_queue_t *nextinqueue;
2776
2777 ctx->timer_configured = 0;
2778
2779 coap_ticks(&now);
2780
2781 elapsed = now - ctx->sendqueue_basetime; /* that's positive for sure, and unless we haven't been called for a complete wrapping cycle, did not wrap */
2782
2783 nextinqueue = coap_peek_next(ctx);
2784 while (nextinqueue != NULL) {
2785 if (nextinqueue->t > elapsed) {
2786 nextinqueue->t -= elapsed;
2787 break;
2788 } else {
2789 elapsed -= nextinqueue->t;
2790 coap_retransmit(ctx, coap_pop_next(ctx));
2791 nextinqueue = coap_peek_next(ctx);
2792 }
2793 }
2794
2795 ctx->sendqueue_basetime = now;
2796
2797 coap_retransmittimer_restart(ctx);
2798 }
2799
coap_retransmittimer_restart(coap_context_t * ctx)2800 static void coap_retransmittimer_restart(coap_context_t *ctx) {
2801 coap_tick_t now, elapsed, delay;
2802
2803 if (ctx->timer_configured) {
2804 printf("clearing\n");
2805 sys_untimeout(coap_retransmittimer_execute, (void*)ctx);
2806 ctx->timer_configured = 0;
2807 }
2808 if (ctx->sendqueue != NULL) {
2809 coap_ticks(&now);
2810 elapsed = now - ctx->sendqueue_basetime;
2811 if (ctx->sendqueue->t >= elapsed) {
2812 delay = ctx->sendqueue->t - elapsed;
2813 } else {
2814 /* a strange situation, but not completely impossible.
2815 *
2816 * this happens, for example, right after
2817 * coap_retransmittimer_execute, when a retransmission
2818 * was *just not yet* due, and the clock ticked before
2819 * our coap_ticks was called.
2820 *
2821 * not trying to retransmit anything now, as it might
2822 * cause uncontrollable recursion; let's just try again
2823 * with the next main loop run.
2824 * */
2825 delay = 0;
2826 }
2827
2828 printf("scheduling for %d ticks\n", delay);
2829 sys_timeout(delay, coap_retransmittimer_execute, (void*)ctx);
2830 ctx->timer_configured = 1;
2831 }
2832 }
2833 #endif
2834