libcoap 4.3.5-develop-783b531
Loading...
Searching...
No Matches
coap_io.c
Go to the documentation of this file.
1/* coap_io.c -- Default network I/O functions for libcoap
2 *
3 * Copyright (C) 2012,2014,2016-2026 Olaf Bergmann <bergmann@tzi.org> and others
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
17
18#ifdef HAVE_STDIO_H
19# include <stdio.h>
20#endif
21#ifdef HAVE_UNISTD_H
22# include <unistd.h>
23#endif
24
25#ifndef __ZEPHYR__
26#ifdef HAVE_SYS_SELECT_H
27# include <sys/select.h>
28#endif
29#ifdef HAVE_SYS_SOCKET_H
30# include <sys/socket.h>
31#endif
32#ifdef HAVE_SYS_IOCTL_H
33#include <sys/ioctl.h>
34#endif
35#ifdef HAVE_NETINET_IN_H
36# include <netinet/in.h>
37#endif
38#ifdef HAVE_SYS_UIO_H
39# include <sys/uio.h>
40#endif
41#ifdef _WIN32
42#include <stdio.h>
43#endif /* _WIN32 */
44#ifdef COAP_EPOLL_SUPPORT
45#include <sys/epoll.h>
46#include <sys/timerfd.h>
47#ifdef HAVE_LIMITS_H
48#include <limits.h>
49#endif
50#endif /* COAP_EPOLL_SUPPORT */
51#else /* __ZEPHYR__ */
52#include <sys/ioctl.h>
53#include <sys/select.h>
54#endif /* __ZEPHYR__ */
55
56#if COAP_SERVER_SUPPORT
58coap_malloc_endpoint(void) {
60}
61
62void
63coap_mfree_endpoint(coap_endpoint_t *ep) {
65}
66#endif /* COAP_SERVER_SUPPORT */
67
68#ifndef WITH_CONTIKI
69void
71#if COAP_EPOLL_SUPPORT
72 if (context->eptimerfd != -1) {
73 coap_tick_t now;
74
75 coap_ticks(&now);
76 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
77 struct itimerspec new_value;
78 int ret;
79
80 context->next_timeout = now + delay;
81 memset(&new_value, 0, sizeof(new_value));
82 if (delay == 0) {
83 new_value.it_value.tv_nsec = 1; /* small but not zero */
84 } else {
85 new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND;
86 new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) *
87 1000000;
88 }
89 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
90 if (ret == -1) {
91 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
92 "coap_update_io_timer",
93 coap_socket_strerror(), errno);
94 }
95#ifdef COAP_DEBUG_WAKEUP_TIMES
96 else {
97 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
98 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
99 }
100#endif /* COAP_DEBUG_WAKEUP_TIMES */
101 }
102 }
103#else /* ! COAP_EPOLL_SUPPORT */
104 coap_tick_t now;
105
106 coap_ticks(&now);
107 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
108 context->next_timeout = now + delay;
109 }
110#endif /* ! COAP_EPOLL_SUPPORT */
111}
112#endif /* ! WITH_CONTIKI */
113
114#ifdef _WIN32
115void
116coap_win_error_to_errno(void) {
117 int w_error = WSAGetLastError();
118 switch (w_error) {
119 case WSA_NOT_ENOUGH_MEMORY:
120 errno = ENOMEM;
121 break;
122 case WSA_INVALID_PARAMETER:
123 errno = EINVAL;
124 break;
125 case WSAEINTR:
126 errno = EINTR;
127 break;
128 case WSAEBADF:
129 errno = EBADF;
130 break;
131 case WSAEACCES:
132 errno = EACCES;
133 break;
134 case WSAEFAULT:
135 errno = EFAULT;
136 break;
137 case WSAEINVAL:
138 errno = EINVAL;
139 break;
140 case WSAEMFILE:
141 errno = EMFILE;
142 break;
143 case WSAEWOULDBLOCK:
144 errno = EWOULDBLOCK;
145 break;
146 case WSAENETDOWN:
147 errno = ENETDOWN;
148 break;
149 case WSAENETUNREACH:
150 errno = ENETUNREACH;
151 break;
152 case WSAENETRESET:
153 errno = ENETRESET;
154 break;
155 case WSAECONNABORTED:
156 errno = ECONNABORTED;
157 break;
158 case WSAECONNRESET:
159 errno = ECONNRESET;
160 break;
161 case WSAENOBUFS:
162 errno = ENOBUFS;
163 break;
164 case WSAETIMEDOUT:
165 errno = ETIMEDOUT;
166 break;
167 case WSAECONNREFUSED:
168 errno = ECONNREFUSED;
169 break;
170 case WSAEADDRNOTAVAIL:
171 errno = EADDRNOTAVAIL;
172 break;
173 default:
174 coap_log_err("WSAGetLastError: %d mapping to errno failed - please fix\n",
175 w_error);
176 errno = EPERM;
177 break;
178 }
179}
180#endif /* _WIN32 */
181
182#if !defined(WITH_LWIP) && !defined(__ZEPHYR__)
183#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
184/* define struct in6_pktinfo and struct in_pktinfo if not available
185 FIXME: check with configure
186*/
187#if !defined(__MINGW32__) && !defined(RIOT_VERSION)
188struct in6_pktinfo {
189 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
190 unsigned int ipi6_ifindex; /* send/recv interface index */
191};
192
193struct in_pktinfo {
194 int ipi_ifindex;
195 struct in_addr ipi_spec_dst;
196 struct in_addr ipi_addr;
197};
198#endif /* ! __MINGW32__ && ! RIOT_VERSION */
199#endif
200#endif /* ! WITH_LWIP && ! __ZEPHYR__ */
201
202void
203coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
204 *address = packet->payload;
205 *length = packet->length;
206}
207
208COAP_API unsigned int
210 unsigned int ret;
211
212 coap_lock_lock(return 0);
213 ret = coap_io_prepare_epoll_lkd(ctx, now);
215 return ret;
216}
217
218unsigned int
220#ifndef COAP_EPOLL_SUPPORT
221 (void)ctx;
222 (void)now;
223 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
224 return 0;
225#else /* COAP_EPOLL_SUPPORT */
226 coap_socket_t *sockets[1];
227 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
228 unsigned int num_sockets;
229 unsigned int timeout;
230
232 /* Use the common logic */
233 timeout = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, &num_sockets, now);
234 /* Save when the next expected I/O is to take place */
235 ctx->next_timeout = timeout ? now + timeout : 0;
236 if (ctx->eptimerfd != -1) {
237 struct itimerspec new_value;
238 int ret;
239
240 memset(&new_value, 0, sizeof(new_value));
241 coap_ticks(&now);
242 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
243 coap_tick_t rem_timeout = ctx->next_timeout - now;
244 /* Need to trigger an event on ctx->eptimerfd in the future */
245 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
246 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
247 1000000;
248 }
249#ifdef COAP_DEBUG_WAKEUP_TIMES
250 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
251 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
252#endif /* COAP_DEBUG_WAKEUP_TIMES */
253 /* reset, or specify a future time for eptimerfd to trigger */
254 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
255 if (ret == -1) {
256 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
257 "coap_io_prepare_epoll",
258 coap_socket_strerror(), errno);
259 }
260 }
261 return timeout;
262#endif /* COAP_EPOLL_SUPPORT */
263}
264
265/*
266 * return 0 No i/o pending
267 * +ve millisecs to next i/o activity
268 */
269COAP_API unsigned int
271 coap_socket_t *sockets[],
272 unsigned int max_sockets,
273 unsigned int *num_sockets,
274 coap_tick_t now) {
275 unsigned int ret;
276
277 coap_lock_lock(return 0);
278 ret = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, num_sockets, now);
280 return ret;
281}
282
283#if COAP_CLIENT_SUPPORT
284static coap_tick_t
285coap_check_need_reconnect(coap_context_t *ctx, coap_session_t *s, coap_tick_t now,
286 coap_tick_t timeout) {
287 coap_tick_t s_timeout;
288
289 if (s->client_initiated && s->session_failed && ctx->reconnect_time) {
290 if (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND <= now) {
291 if (!coap_session_reconnect(s)) {
292 /* server is not back up yet - delay retry a while */
293 s->last_rx_tx = now;
294 s_timeout = ctx->reconnect_time * COAP_TICKS_PER_SECOND;
295 if (timeout == 0 || s_timeout < timeout)
296 timeout = s_timeout;
297 }
298 } else {
299 /* Always positive due to if() above */
300 s_timeout = (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND) - now;
301 if (s_timeout < timeout)
302 timeout = s_timeout;
303 }
304 }
305 return timeout;
306}
307
308void
310 if (session->doing_first) {
311 session->doing_first = 0;
312 while (!session->doing_first && session->doing_first_pdu) {
313 coap_pdu_t *k_pdu = session->doing_first_pdu;
314
315 LL_DELETE(session->doing_first_pdu, session->doing_first_pdu);
316 coap_log_debug("** %s: mid=0x%04x: released\n",
317 coap_session_str(session), k_pdu->mid);
318 if (coap_send_lkd(session, k_pdu) == COAP_INVALID_MID) {
320 }
321 }
322 }
323}
324#endif /* COAP_CLIENT_SUPPORT */
325
326/*
327 * return 0 No i/o pending
328 * +ve millisecs to next i/o activity
329 */
330unsigned int
332 coap_socket_t *sockets[],
333 unsigned int max_sockets,
334 unsigned int *num_sockets,
335 coap_tick_t now) {
336 coap_queue_t *nextpdu;
337 coap_session_t *s, *stmp;
339 coap_tick_t s_timeout;
340#if COAP_SERVER_SUPPORT
341 int check_dtls_timeouts = 0;
342#endif /* COAP_SERVER_SUPPORT */
343#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION)
344 (void)sockets;
345 (void)max_sockets;
346#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/
347
349 *num_sockets = 0;
350
351#if COAP_SERVER_SUPPORT
352 /* Check to see if we need to send off any Observe requests */
353 coap_check_notify_lkd(ctx);
354
355#if COAP_ASYNC_SUPPORT
356 /* Check to see if we need to send off any Async requests */
357 if (coap_check_async(ctx, now, &s_timeout)) {
358 if (s_timeout < timeout)
359 timeout = s_timeout;
360 }
361#endif /* COAP_ASYNC_SUPPORT */
362#endif /* COAP_SERVER_SUPPORT */
363
364 /* Check to see if we need to send off any retransmit request */
365 nextpdu = coap_peek_next(ctx);
366 while (nextpdu && now >= ctx->sendqueue_basetime &&
367 nextpdu->t <= now - ctx->sendqueue_basetime) {
369 nextpdu = coap_peek_next(ctx);
370 }
371 if (nextpdu && now >= ctx->sendqueue_basetime &&
372 (nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
373 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
374
375 /* Check for DTLS timeouts */
376 if (ctx->dtls_context) {
379 if (tls_timeout > 0) {
380 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
381 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
382 coap_log_debug("** DTLS global timeout set to %dms\n",
383 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
384 if (tls_timeout - now < timeout)
385 timeout = tls_timeout - now;
386 }
387#if COAP_SERVER_SUPPORT
388 } else {
389 check_dtls_timeouts = 1;
390#endif /* COAP_SERVER_SUPPORT */
391 }
392 }
393#if COAP_PROXY_SUPPORT
394 if (coap_proxy_check_timeouts(ctx, now, &s_timeout)) {
395 if (s_timeout < timeout)
396 timeout = s_timeout;
397 }
398#endif /* COAP_PROXY_SUPPORT */
399#if COAP_SERVER_SUPPORT
400 coap_endpoint_t *ep;
401 coap_tick_t session_timeout;
402
403 if (ctx->session_timeout > 0)
404 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
405 else
407
408 LL_FOREACH(ctx->endpoint, ep) {
409#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
411 if (*num_sockets < max_sockets)
412 sockets[(*num_sockets)++] = &ep->sock;
413 }
414#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
415 SESSIONS_ITER_SAFE(ep->sessions, s, stmp) {
416 /* Check whether any idle server sessions should be released */
417 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
418 s->delayqueue == NULL &&
420 !(s->client_initiated && ctx->reconnect_time) &&
421#endif /* COAP_CLIENT_SUPPORT */
422 (s->last_rx_tx + session_timeout <= now ||
426 continue;
427 } else if (s->is_rate_limiting) {
428 continue;
429 } else {
430 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
431 s->delayqueue == NULL && s->last_rx_tx + session_timeout <= now) {
432 /* Has to be positive based on if() above */
433 s_timeout = (s->last_rx_tx + session_timeout) - now;
434 if (s_timeout < timeout)
435 timeout = s_timeout;
436 }
437 /* Make sure the session object is not deleted in any callbacks */
439 /* Check any DTLS timeouts and expire if appropriate */
440 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
441 s->proto == COAP_PROTO_DTLS && s->tls) {
442 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
443 while (tls_timeout > 0 && tls_timeout <= now) {
444 coap_log_debug("** %s: DTLS retransmit timeout\n",
447 goto release_1;
448
449 if (s->tls)
450 tls_timeout = coap_dtls_get_timeout(s, now);
451 else {
452 tls_timeout = 0;
453 timeout = 1;
454 }
455 }
456 if (tls_timeout > 0 && tls_timeout - now < timeout)
457 timeout = tls_timeout - now;
458 }
459 /* Check if any server large receives are missing blocks */
460 if (s->lg_srcv) {
461 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
462 if (s_timeout < timeout)
463 timeout = s_timeout;
464 }
465 }
466 /* Check if any server large sending have timed out */
467 if (s->lg_xmit) {
468 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
469 if (s_timeout < timeout)
470 timeout = s_timeout;
471 }
472 }
473#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
475 if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE))
476 sockets[(*num_sockets)++] = &s->sock;
477 }
478#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
479#if COAP_Q_BLOCK_SUPPORT
480 /*
481 * Check if any server large transmits have hit MAX_PAYLOAD and need
482 * restarting
483 */
484 if (s->lg_xmit && !s->is_rate_limiting) {
485 if (coap_block_check_q_block2_xmit(s, now, &s_timeout)) {
486 if (s_timeout < timeout)
487 timeout = s_timeout;
488 }
489 }
490#endif /* COAP_Q_BLOCK_SUPPORT */
491release_1:
493 }
494 if (s->type == COAP_SESSION_TYPE_SERVER &&
496 (s->ref_subscriptions || s->ref_proxy_subs
498 || (s->client_initiated && ctx->reconnect_time)
499#endif /* COAP_CLIENT_SUPPORT */
500 ) &&
501 !s->con_active && ctx->ping_timeout > 0) {
502 /* Only do this if this session is observing or reconnecting */
503 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
504 /* Time to send a ping */
505 coap_mid_t mid;
506
508 /* Some issue - not safe to continue processing */
509 s->ping_failed++;
510 s->last_rx_tx = now;
511#if COAP_CLIENT_SUPPORT
512 if (s->client_initiated && ctx->reconnect_time) {
514 }
515#endif /* COAP_CLIENT_SUPPORT */
517 continue;
518 }
519 s->last_ping_mid = mid;
520 if ((s->last_ping > 0 && s->last_pong < s->last_ping) || s->ping_failed > COAP_MAX_PING_FAILURES) {
521#if COAP_CLIENT_SUPPORT
522 if (s->client_initiated && ctx->reconnect_time) {
524 } else {
525#endif /* COAP_CLIENT_SUPPORT */
527#if COAP_CLIENT_SUPPORT
528 }
529#endif /* COAP_CLIENT_SUPPORT */
530 /* check the next session */
531 continue;
532 }
533 s->last_rx_tx = now;
534 s->last_ping = now;
535 } else {
536 /* Always positive due to if() above */
537 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
538 if (s_timeout < timeout)
539 timeout = s_timeout;
540 }
541 }
542#if COAP_CLIENT_SUPPORT
543 timeout = coap_check_need_reconnect(ctx, s, now, timeout);
544#endif /* COAP_CLIENT_SUPPORT */
545 }
546 }
547#endif /* COAP_SERVER_SUPPORT */
548#if COAP_CLIENT_SUPPORT
549 SESSIONS_ITER_SAFE(ctx->sessions, s, stmp) {
550 if (s->is_rate_limiting) {
551 continue;
552 }
553 if (s->type == COAP_SESSION_TYPE_CLIENT &&
555 ctx->ping_timeout > 0) {
556 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
557 /* Time to send a ping */
558 coap_mid_t mid;
559
561 /* Some issue - not safe to continue processing */
562 s->ping_failed++;
563 s->last_rx_tx = now;
566 continue;
567 }
568 s->last_ping_mid = mid;
569 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
571 }
573#if COAP_CLIENT_SUPPORT
574 if (s->client_initiated) {
575 if (ctx->reconnect_time) {
577 } else {
579 }
580 } else {
581#endif /* COAP_CLIENT_SUPPORT */
582#if COAP_SERVER_SUPPORT
584#endif /* COAP_SERVER_SUPPORT */
585#if COAP_CLIENT_SUPPORT
586 }
587#endif /* COAP_CLIENT_SUPPORT */
588 continue;
589 } else {
590 s->last_rx_tx = now;
591 s->last_ping = now;
592 }
593 } else {
594 /* Always positive due to if() above */
595 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
596 if (s_timeout < timeout)
597 timeout = s_timeout;
598 }
599 }
600 timeout = coap_check_need_reconnect(ctx, s, now, timeout);
601
602#if !COAP_DISABLE_TCP
604 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) {
605 if (s->csm_tx == 0) {
606 s->csm_tx = now;
607 s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000;
608 } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) {
609 /* timed out - cannot handle 0, so has to be just +ve */
610 s_timeout = 1;
611 } else {
612 s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now;
613 }
614 if (s_timeout < timeout)
615 timeout = s_timeout;
616 }
617#endif /* !COAP_DISABLE_TCP */
618
619 /* Make sure the session object is not deleted in any callbacks */
621 /* Check any DTLS timeouts and expire if appropriate */
623 s->proto == COAP_PROTO_DTLS && s->tls) {
624 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
625 while (tls_timeout > 0 && tls_timeout <= now) {
626 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
628 goto release_2;
629
630 if (s->tls)
631 tls_timeout = coap_dtls_get_timeout(s, now);
632 else {
633 tls_timeout = 0;
634 timeout = 1;
635 }
636 }
637 if (tls_timeout > 0 && tls_timeout - now < timeout)
638 timeout = tls_timeout - now;
639 }
640
641 /* Check if any client large receives are missing blocks */
642 if (s->lg_crcv) {
643 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
644 if (s_timeout < timeout)
645 timeout = s_timeout;
646 }
647 }
648 /* Check if any client large sending have timed out */
649 if (s->lg_xmit) {
650 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
651 if (s_timeout < timeout)
652 timeout = s_timeout;
653 }
654 }
655 if (s->doing_first && s->doing_first_timeout) {
656 if ((s->doing_first_timeout + 5 * COAP_TICKS_PER_SECOND) > now) {
657 s_timeout = s->doing_first_timeout + 5 * COAP_TICKS_PER_SECOND - now;
658 if (s_timeout < timeout)
659 timeout = s_timeout;
660 } else {
661 /* Session set up has failed */
662 coap_queue_t *sent;
663 coap_queue_t *p = NULL;
664 coap_queue_t *q;
665 coap_queue_t *tmp;
666
667 if (s->state == COAP_SESSION_STATE_CSM) {
668 coap_log_debug("** %s: timeout waiting for CSM response\n",
670 s->csm_not_seen = 1;
671 } else {
672 coap_log_debug("** %s: timeout waiting for first response\n",
674 }
675#if COAP_Q_BLOCK_SUPPORT
676 /* Check if testing for Q-Block */
677 if (s->block_mode & COAP_BLOCK_PROBE_Q_BLOCK) {
678 coap_log_debug("Q-Block support assumed not available\n");
679 set_block_mode_drop_q(s->block_mode);
680 }
681#endif /* COAP_Q_BLOCK_SUPPORT */
682 /* Check if testing for Extended Token */
686 coap_log_debug("Extended Token support assumed not available\n");
687 }
688 /*
689 * Remove the test packet to stop re-transmission.
690 * The test packet may be in the delayqueue ((D)TLS has not been set up),
691 * or in the sendqueue if sent and is pending re-transmission.
692 */
693 LL_FOREACH_SAFE(s->delayqueue, q, tmp) {
694 if (q->pdu->mid == s->remote_test_mid) {
695 if (q->pdu->type==COAP_MESSAGE_CON) {
696 coap_handle_nack(s, q->pdu,
697 s->proto == COAP_PROTO_DTLS ?
699 q->id);
700 }
701 coap_log_debug("** %s: mid=0x%04x: removed\n",
702 coap_session_str(s), q->pdu->mid);
703 if (p) {
704 p->next = q->next;
705 } else {
706 s->delayqueue = q->next;
707 }
709 break;
710 }
711 p = q;
712 }
714 if (sent && sent->pdu && sent->pdu->type == COAP_MESSAGE_CON && COAP_PROTO_NOT_RELIABLE(s->proto)) {
715 if (s->con_active)
716 s->con_active--;
717 }
720 /* Flush out any entries on session->delayqueue */
722 }
723 }
724 }
725
726#if COAP_Q_BLOCK_SUPPORT
727 /*
728 * Check if any client large transmits have hit MAX_PAYLOAD and need
729 * restarting
730 */
731 if (s->lg_xmit) {
732 if (coap_block_check_q_block1_xmit(s, now, &s_timeout)) {
733 if (s_timeout < timeout)
734 timeout = s_timeout;
735 }
736 }
737#endif /* COAP_Q_BLOCK_SUPPORT */
738
739#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
740 assert(s->ref > 1);
744 if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE))
745 sockets[(*num_sockets)++] = &s->sock;
746 }
747#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
748release_2:
750 }
751#endif /* COAP_CLIENT_SUPPORT */
752
753 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
754}
755
756/*
757 * return 0 Insufficient space to hold fds, or fds not supported
758 * 1 All fds found
759 */
760COAP_API unsigned int
762 coap_fd_t read_fds[],
763 unsigned int *have_read_fds,
764 unsigned int max_read_fds,
765 coap_fd_t write_fds[],
766 unsigned int *have_write_fds,
767 unsigned int max_write_fds,
768 unsigned int *rem_timeout_ms) {
769 unsigned int ret;
770
771 coap_lock_lock(return 0);
772 ret = coap_io_get_fds_lkd(ctx, read_fds, have_read_fds, max_read_fds, write_fds,
773 have_write_fds, max_write_fds, rem_timeout_ms);
775 return ret;
776}
777
778#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
779static int
780coap_add_fd(coap_fd_t fd, coap_fd_t this_fds[], unsigned int *have_this_fds,
781 unsigned int max_this_fds) {
782 if (*have_this_fds < max_this_fds) {
783 this_fds[(*have_this_fds)++] = fd;
784 return 1;
785 }
786 coap_log_warn("coap_io_get_fds: Insufficient space for new fd (%u >= %u)\n", *have_this_fds,
787 max_this_fds);
788 return 0;
789}
790
791/*
792 * return 0 Insufficient space to hold fds, or fds not supported
793 * 1 All fds found
794 */
795unsigned int
797 coap_fd_t read_fds[],
798 unsigned int *have_read_fds,
799 unsigned int max_read_fds,
800 coap_fd_t write_fds[],
801 unsigned int *have_write_fds,
802 unsigned int max_write_fds,
803 unsigned int *rem_timeout_ms) {
804 *have_read_fds = 0;
805 *have_write_fds = 0;
806
807#ifdef COAP_EPOLL_SUPPORT
808 (void)write_fds;
809 (void)max_write_fds;;
810
811 if (!coap_add_fd(ctx->epfd, read_fds, have_read_fds, max_read_fds))
812 return 0;
813 /* epoll is making use of timerfd, so no need to return any timeout */
814 *rem_timeout_ms = 0;
815 return 1;
816#else /* ! COAP_EPOLL_SUPPORT */
817 coap_session_t *s, *rtmp;
818 coap_tick_t now;
819 unsigned int timeout_ms;
820#if COAP_SERVER_SUPPORT
821 coap_endpoint_t *ep;
822
823 LL_FOREACH(ctx->endpoint, ep) {
824 if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) {
825 if (!coap_add_fd(ep->sock.fd, read_fds, have_read_fds, max_read_fds))
826 return 0;
827 }
828 if (ep->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) {
829 if (!coap_add_fd(ep->sock.fd, write_fds, have_write_fds, max_write_fds))
830 return 0;
831 }
832 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
834 if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
835 return 0;
836 }
838 if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
839 return 0;
840 }
841 }
842 }
843#endif /* COAP_SERVER_SUPPORT */
844
845#if COAP_CLIENT_SUPPORT
846 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
848 if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
849 return 0;
850 }
852 if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
853 return 0;
854 }
855 }
856#endif /* COAP_CLIENT_SUPPORT */
857
858 coap_ticks(&now);
859 timeout_ms = (unsigned int)(ctx->next_timeout ? ctx->next_timeout > now ?
860 ctx->next_timeout - now : 0 : 0) *
862 *rem_timeout_ms = timeout_ms;
863 return 1;
864#endif /* ! COAP_EPOLL_SUPPORT */
865}
866
867#else /* WITH_LWIP || WITH_CONTIKI */
868
869/*
870 * return 0 Insufficient space to hold fds, or fds not supported
871 * 1 All fds found
872 */
873unsigned int
875 coap_fd_t read_fds[],
876 unsigned int *have_read_fds,
877 unsigned int max_read_fds,
878 coap_fd_t write_fds[],
879 unsigned int *have_write_fds,
880 unsigned int max_write_fds,
881 unsigned int *rem_timeout_ms) {
882 (void)ctx;
883 (void)read_fds;
884 (void)max_read_fds;
885 (void)write_fds;
886 (void)max_write_fds;
887
888 *have_read_fds = 0;
889 *have_write_fds = 0;
890 *rem_timeout_ms = 0;
891
892 coap_log_warn("coap_io_get_fds: Not supported\n");
893 return 0;
894}
895#endif /* WITH_LWIP || WITH_CONTIKI */
896
897COAP_API int
899 int ret;
900
901 coap_lock_lock(return 0);
902 ret = coap_io_pending_lkd(context);
904 return ret;
905}
906
907/*
908 * return 1 I/O pending
909 * 0 No I/O pending
910 */
911int
913 coap_session_t *s, *rtmp;
914#if COAP_SERVER_SUPPORT
915 coap_endpoint_t *ep;
916#endif /* COAP_SERVER_SUPPORT */
917
918 if (!context)
919 return 0;
921 if (coap_io_process_lkd(context, COAP_IO_NO_WAIT) < 0)
922 return 0;
923
924 if (context->sendqueue)
925 return 1;
926#if COAP_SERVER_SUPPORT
927 LL_FOREACH(context->endpoint, ep) {
928 SESSIONS_ITER(ep->sessions, s, rtmp) {
929 if (s->delayqueue)
930 return 1;
931 if (s->lg_xmit)
932 return 1;
933 if (s->lg_srcv)
934 return 1;
935 }
936 }
937#endif /* COAP_SERVER_SUPPORT */
938#if COAP_CLIENT_SUPPORT
939 SESSIONS_ITER(context->sessions, s, rtmp) {
940 if (s->delayqueue)
941 return 1;
942 if (s->lg_xmit)
943 return 1;
944 if (s->lg_crcv)
945 return 1;
946 }
947#endif /* COAP_CLIENT_SUPPORT */
948 return 0;
949}
950
951const char *
953 return strerror(error);
954}
955#ifdef _WIN32
956const char *
958 coap_win_error_to_errno();
959 return coap_socket_format_errno(errno);
960}
961#else /* _WIN32 */
962const char *
964 return coap_socket_format_errno(errno);
965}
966#endif /* _WIN32 */
967
970#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
971 return sock->fd;
972#else
973 (void)(sock);
974 return COAP_INVALID_SOCKET;
975#endif
976}
977
980 return sock->flags;
981}
982
983COAP_API void
985 sock->flags = flags;
986}
struct coap_endpoint_t coap_endpoint_t
#define COAP_CLIENT_SUPPORT
const char * coap_socket_format_errno(int error)
Definition coap_io.c:952
static int coap_add_fd(coap_fd_t fd, coap_fd_t this_fds[], unsigned int *have_this_fds, unsigned int max_this_fds)
Definition coap_io.c:780
const char * coap_socket_strerror(void)
Definition coap_io.c:963
void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
Given a packet, set msg and msg_len to an address and length of the packet's data in memory.
Definition coap_io.c:203
void coap_update_io_timer(coap_context_t *context, coap_tick_t delay)
Update when to continue with I/O processing, unless packets come in in the meantime.
Definition coap_io.c:70
uint16_t coap_socket_flags_t
Definition coap_io.h:55
@ COAP_NACK_NOT_DELIVERABLE
Definition coap_io.h:66
@ COAP_NACK_TLS_FAILED
Definition coap_io.h:68
int coap_fd_t
Definition coap_io.h:49
#define COAP_INVALID_SOCKET
Definition coap_io.h:52
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
#define COAP_SOCKET_SLAVE
socket is a slave socket - do not close
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
#define COAP_SOCKET_WANT_WRITE
non blocking socket is waiting for writing
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ COAP_ENDPOINT
Definition coap_mem.h:39
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition coap_notls.c:233
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:228
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:242
#define NULL
Definition coap_option.h:30
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
void coap_reset_doing_first(coap_session_t *session)
Reset doing the first packet state when testing for optional functionality.
int coap_io_pending_lkd(coap_context_t *context)
Check to see if there is any i/o pending for the context.
Definition coap_io.c:912
unsigned int coap_io_get_fds_lkd(coap_context_t *ctx, coap_fd_t read_fds[], unsigned int *have_read_fds, unsigned int max_read_fds, coap_fd_t write_fds[], unsigned int *have_write_fds, unsigned int max_write_fds, unsigned int *rem_timeout_ms)
Definition coap_io.c:796
int coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
unsigned int coap_io_prepare_io_lkd(coap_context_t *ctx, coap_socket_t *sockets[], unsigned int max_sockets, unsigned int *num_sockets, coap_tick_t now)
Iterates through all the coap_socket_t structures embedded in endpoints or sessions associated with t...
Definition coap_io.c:331
unsigned int coap_io_prepare_epoll_lkd(coap_context_t *ctx, coap_tick_t now)
Any now timed out delayed packet is transmitted, along with any packets associated with requested obs...
Definition coap_io.c:219
coap_mid_t coap_send_lkd(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition coap_net.c:1509
COAP_API int coap_io_pending(coap_context_t *context)
Check to see if there is any i/o pending for the context.
Definition coap_io.c:898
COAP_API unsigned int coap_io_get_fds(coap_context_t *ctx, coap_fd_t read_fds[], unsigned int *have_read_fds, unsigned int max_read_fds, coap_fd_t write_fds[], unsigned int *have_write_fds, unsigned int max_write_fds, unsigned int *rem_timeout_ms)
Definition coap_io.c:761
COAP_API unsigned int coap_io_prepare_io(coap_context_t *ctx, coap_socket_t *sockets[], unsigned int max_sockets, unsigned int *num_sockets, coap_tick_t now)
Iterates through all the coap_socket_t structures embedded in endpoints or sessions associated with t...
Definition coap_io.c:270
#define COAP_IO_NO_WAIT
Definition coap_net.h:841
COAP_API void coap_socket_set_flags(coap_socket_t *sock, coap_socket_flags_t flags)
Set the libcoap internal flags for a socket.
Definition coap_io.c:984
COAP_API unsigned int coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now)
Any now timed out delayed packet is transmitted, along with any packets associated with requested obs...
Definition coap_io.c:209
COAP_API coap_fd_t coap_socket_get_fd(coap_socket_t *sock)
Get the libcoap internal file descriptor for a socket.
Definition coap_io.c:969
COAP_API coap_socket_flags_t coap_socket_get_flags(coap_socket_t *sock)
Get the libcoap internal flags for a socket.
Definition coap_io.c:979
int coap_block_check_lg_xmit_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:149
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition coap_time.h:164
#define COAP_MAX_DELAY_TICKS
Definition coap_time.h:231
int coap_handle_event_lkd(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
Definition coap_net.c:5107
int coap_delete_node_lkd(coap_queue_t *node)
Destroys specified node.
Definition coap_net.c:214
int coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_mid_t id, coap_queue_t **node)
This function removes the element with given id from the list given list.
Definition coap_net.c:3078
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition coap_net.c:257
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition coap_net.c:265
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition coap_net.c:2365
void coap_ticks(coap_tick_t *t)
Returns the current value of an internal tick counter.
Definition coap_time.c:90
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition coap_notls.c:223
@ COAP_EVENT_FIRST_PDU_FAIL
Triggered when the initial app PDU cannot be transmitted.
Definition coap_event.h:114
@ COAP_EVENT_SERVER_SESSION_DEL
Called in the CoAP IO loop if a server session is deleted (e.g., due to inactivity or because the max...
Definition coap_event.h:98
@ COAP_EVENT_KEEPALIVE_FAILURE
Triggered when no response to a keep alive (ping) packet.
Definition coap_event.h:144
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:126
#define coap_log_emerg(...)
Definition coap_debug.h:87
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_err(...)
Definition coap_debug.h:102
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:267
#define COAP_TOKEN_DEFAULT_MAX
Definition coap_pdu.h:58
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:270
@ COAP_PROTO_DTLS
Definition coap_pdu.h:320
@ COAP_MESSAGE_CON
Definition coap_pdu.h:71
#define COAP_MAX_PING_FAILURES
void coap_handle_nack(coap_session_t *session, coap_pdu_t *sent, const coap_nack_reason_t reason, const coap_mid_t mid)
int coap_session_reconnect(coap_session_t *session)
Close the current session (if not already closed) and reconnect to server (client session only).
void coap_session_server_keepalive_failed(coap_session_t *session)
Clear down a session following a keepalive failure.
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
void coap_session_failed(coap_session_t *session)
Session has failed due to a socket error.
coap_mid_t coap_session_send_ping_lkd(coap_session_t *session)
Send a ping message for the session.
void coap_session_free(coap_session_t *session)
void coap_session_release_lkd(coap_session_t *session)
Decrement reference counter on a session.
coap_session_t * coap_session_reference_lkd(coap_session_t *session)
Increment reference counter on a session.
void coap_session_disconnected_lkd(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
@ COAP_EXT_T_CHECKING
Token size check request sent.
@ COAP_EXT_T_CHECKED
Token size valid.
#define COAP_PROTO_NOT_RELIABLE(p)
#define COAP_PROTO_RELIABLE(p)
@ COAP_SESSION_TYPE_SERVER
server-side
@ COAP_SESSION_TYPE_CLIENT
client-side
@ COAP_SESSION_STATE_HANDSHAKE
@ COAP_SESSION_STATE_CSM
@ COAP_SESSION_STATE_ESTABLISHED
@ COAP_SESSION_STATE_NONE
The CoAP stack's global state is stored in a coap_context_t object.
coap_tick_t sendqueue_basetime
The time stamp in the first element of the sendqeue is relative to sendqueue_basetime.
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
coap_queue_t * sendqueue
uint32_t csm_timeout_ms
Timeout for waiting for a CSM from the remote side.
coap_tick_t next_timeout
When the next timeout is to occur.
unsigned int session_timeout
Number of seconds of inactivity after which an unused session will be closed.
size_t length
length of payload
unsigned char * payload
payload
structure for CoAP PDUs
coap_mid_t mid
message id, if any, in regular host byte order
coap_pdu_type_t type
message type
Queue entry.
coap_pdu_t * pdu
the CoAP PDU to send
struct coap_queue_t * next
coap_mid_t id
CoAP message id.
coap_tick_t t
when to send PDU for the next time
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_lg_xmit_t * lg_xmit
list of large transmissions
volatile uint8_t max_token_checked
Check for max token size coap_ext_token_check_t.
uint8_t csm_not_seen
Set if timeout waiting for CSM.
uint32_t block_mode
Zero or more COAP_BLOCK_ or'd options.
coap_socket_t sock
socket object for the session, if any
uint32_t max_token_size
Largest token size supported RFC8974.
uint32_t ping_failed
Ping failure count.
coap_session_state_t state
current state of relationship with peer
uint8_t is_rate_limiting
Currently NON rate limiting.
coap_mid_t remote_test_mid
mid used for checking remote support
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
void * tls
security parameters
uint8_t con_active
Active CON request sent.
coap_queue_t * delayqueue
list of delayed messages waiting to be sent
coap_mid_t last_ping_mid
the last keepalive message id that was used in this session
coap_session_type_t type
client or server side socket
coap_context_t * context
session's context
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values
struct in6_addr ipi6_addr
unsigned int ipi6_ifindex
struct in_addr ipi_spec_dst
struct in_addr ipi_addr