libcoap 4.3.5-develop-79a0414
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-2025 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
22#ifndef __ZEPHYR__
23#ifdef HAVE_SYS_SELECT_H
24# include <sys/select.h>
25#endif
26#ifdef HAVE_SYS_SOCKET_H
27# include <sys/socket.h>
28# define OPTVAL_T(t) (t)
29# define OPTVAL_GT(t) (t)
30#endif
31#ifdef HAVE_SYS_IOCTL_H
32#include <sys/ioctl.h>
33#endif
34#ifdef HAVE_NETINET_IN_H
35# include <netinet/in.h>
36#endif
37#ifdef HAVE_WS2TCPIP_H
38#include <ws2tcpip.h>
39# define OPTVAL_T(t) (const char*)(t)
40# define OPTVAL_GT(t) (char*)(t)
41# undef CMSG_DATA
42# define CMSG_DATA WSA_CMSG_DATA
43#endif
44#ifdef HAVE_SYS_UIO_H
45# include <sys/uio.h>
46#endif
47#ifdef HAVE_UNISTD_H
48# include <unistd.h>
49#endif
50#ifdef _WIN32
51#include <stdio.h>
52#endif /* _WIN32 */
53#ifdef COAP_EPOLL_SUPPORT
54#include <sys/epoll.h>
55#include <sys/timerfd.h>
56#ifdef HAVE_LIMITS_H
57#include <limits.h>
58#endif
59#endif /* COAP_EPOLL_SUPPORT */
60#else /* __ZEPHYR__ */
61#include <zephyr/posix/sys/ioctl.h>
62#include <zephyr/posix/sys/select.h>
63#define OPTVAL_T(t) (const void*)(t)
64#define OPTVAL_GT(t) (void*)(t)
65
66#ifndef IPV6_PKTINFO
67#ifdef IPV6_RECVPKTINFO
68#define IPV6_PKTINFO IPV6_RECVPKTINFO
69#else
70#define IPV6_PKTINFO IP_PKTINFO
71#endif
72#ifndef IN6_IS_ADDR_V4MAPPED
73#define IN6_IS_ADDR_V4MAPPED(a) \
74 ((((a)->s6_addr32[0]) == 0) && (((a)->s6_addr32[1]) == 0) && \
75 (((a)->s6_addr32[2]) == htonl(0xffff)))
76#endif
77#endif
78#endif /* __ZEPHYR__ */
79
80#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION) && !defined(WITH_LWIP)
81/* define generic PKTINFO for IPv4 */
82#if defined(IP_PKTINFO)
83# define GEN_IP_PKTINFO IP_PKTINFO
84#elif defined(IP_RECVDSTADDR)
85# define GEN_IP_PKTINFO IP_RECVDSTADDR
86#else
87# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
88#endif /* IP_PKTINFO */
89
90/* define generic PKTINFO for IPv6 */
91#ifdef IPV6_RECVPKTINFO
92# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
93#elif defined(IPV6_PKTINFO)
94# define GEN_IPV6_PKTINFO IPV6_PKTINFO
95#else
96# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
97#endif /* IPV6_RECVPKTINFO */
98#endif /* ! WITH_CONTIKI && ! RIOT_VERSION && ! WITH_LWIP */
99
100#if COAP_SERVER_SUPPORT
104}
105
106void
109}
110#endif /* COAP_SERVER_SUPPORT */
111
112#if !defined(WITH_CONTIKI) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
113
114#if COAP_SERVER_SUPPORT
115int
117 const coap_address_t *listen_addr,
118 coap_address_t *bound_addr) {
119#ifndef RIOT_VERSION
120 int on = 1;
121#if COAP_IPV6_SUPPORT
122 int off = 0;
123#endif /* COAP_IPV6_SUPPORT */
124#else /* ! RIOT_VERSION */
125 struct timeval timeout = {0, 0};
126#endif /* ! RIOT_VERSION */
127#ifdef _WIN32
128 u_long u_on = 1;
129#endif
130
131 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
132
133 if (sock->fd == COAP_INVALID_SOCKET) {
134 coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
135 goto error;
136 }
137#ifndef RIOT_VERSION
138#ifdef _WIN32
139 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
140#else
141 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
142#endif
143 {
144 coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
145 }
146
147 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
148 coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
150
151 switch (listen_addr->addr.sa.sa_family) {
152#if COAP_IPV4_SUPPORT
153 case AF_INET:
154 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
155 sizeof(on)) == COAP_SOCKET_ERROR)
156 coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
158 break;
159#endif /* COAP_IPV4_SUPPORT */
160#if COAP_IPV6_SUPPORT
161 case AF_INET6:
162 /* Configure the socket as dual-stacked */
163 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
164 sizeof(off)) == COAP_SOCKET_ERROR)
165 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
167#if !defined(ESPIDF_VERSION)
168 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
169 sizeof(on)) == COAP_SOCKET_ERROR)
170 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
172#endif /* !defined(ESPIDF_VERSION) */
173#endif /* COAP_IPV6_SUPPORT */
174 setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
175 /* ignore error, because likely cause is that IPv4 is disabled at the os
176 level */
177 break;
178#if COAP_AF_UNIX_SUPPORT
179 case AF_UNIX:
180 break;
181#endif /* COAP_AF_UNIX_SUPPORT */
182 default:
183 coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
184 break;
185 }
186#else /* RIOT_VERSION */
187 if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, OPTVAL_T(&timeout),
188 (socklen_t)sizeof(timeout)) == COAP_SOCKET_ERROR)
189 coap_log_alert("coap_socket_bind_udp: setsockopt SO_RCVTIMEO: %s\n",
191#endif /* RIOT_VERSION */
192
193 if (bind(sock->fd, &listen_addr->addr.sa,
195 listen_addr->addr.sa.sa_family == AF_INET ?
196 (socklen_t)sizeof(struct sockaddr_in) :
197#endif /* COAP_IPV4_SUPPORT */
198 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
199 coap_log_warn("coap_socket_bind_udp: bind: %s\n",
201 goto error;
202 }
203
204 bound_addr->size = (socklen_t)sizeof(*bound_addr);
205 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
206 coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
208 goto error;
209 }
210#if defined(RIOT_VERSION) && defined(COAP_SERVER_SUPPORT)
211 if (sock->endpoint &&
212 bound_addr->addr.sa.sa_family == AF_INET6) {
213 bound_addr->addr.sin6.sin6_scope_id =
214 listen_addr->addr.sin6.sin6_scope_id;
215 bound_addr->addr.sin6.sin6_flowinfo = 0;
216 }
217#endif /* RIOT_VERSION && COAP_SERVER_SUPPORT */
218
219 return 1;
220
221error:
222 coap_socket_close(sock);
223 return 0;
224}
225#endif /* COAP_SERVER_SUPPORT */
226
227#if COAP_CLIENT_SUPPORT
228int
230 const coap_address_t *local_if,
231 const coap_address_t *server,
232 int default_port,
233 coap_address_t *local_addr,
234 coap_address_t *remote_addr) {
235 int on = 1;
236#if COAP_IPV6_SUPPORT
237 int off = 0;
238#endif /* COAP_IPV6_SUPPORT */
239#ifdef _WIN32
240 u_long u_on = 1;
241#endif
242 coap_address_t connect_addr;
243 int is_mcast = coap_is_mcast(server);
244 coap_address_copy(&connect_addr, server);
245
247 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
248
249 if (sock->fd == COAP_INVALID_SOCKET) {
250 coap_log_warn("coap_socket_connect_udp: socket: %s\n",
252 goto error;
253 }
254
255#ifdef _WIN32
256 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
257#else
258 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
259#endif
260 {
261 /* Ignore Zephyr unexpected Success response */
262 if (errno != 0) {
263 int keep_errno = errno;
264
265 coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s (%d)\n",
266 coap_socket_strerror(), keep_errno);
267 }
268 }
269
270 switch (connect_addr.addr.sa.sa_family) {
271#if COAP_IPV4_SUPPORT
272 case AF_INET:
273 if (connect_addr.addr.sin.sin_port == 0)
274 connect_addr.addr.sin.sin_port = htons(default_port);
275 break;
276#endif /* COAP_IPV4_SUPPORT */
277#if COAP_IPV6_SUPPORT
278 case AF_INET6:
279 if (connect_addr.addr.sin6.sin6_port == 0)
280 connect_addr.addr.sin6.sin6_port = htons(default_port);
281 /* Configure the socket as dual-stacked */
282 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
283 sizeof(off)) == COAP_SOCKET_ERROR)
284 if (errno != ENOSYS) {
285 coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
287 }
288#endif /* COAP_IPV6_SUPPORT */
289 break;
290#if COAP_AF_UNIX_SUPPORT
291 case AF_UNIX:
292 break;
293#endif /* COAP_AF_UNIX_SUPPORT */
294 default:
295 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
296 connect_addr.addr.sa.sa_family);
297 goto error;;
298 }
299
300 if (local_if && local_if->addr.sa.sa_family) {
301 if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
302 coap_log_warn("coap_socket_connect_udp: local address family != "
303 "remote address family\n");
304 goto error;
305 }
306 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
307 coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
309 if (bind(sock->fd, &local_if->addr.sa,
311 local_if->addr.sa.sa_family == AF_INET ?
312 (socklen_t)sizeof(struct sockaddr_in) :
313#endif /* COAP_IPV4_SUPPORT */
314 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
315 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
317 goto error;
318 }
319#if COAP_AF_UNIX_SUPPORT
320 } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
321 /* Need to bind to a local address for clarity over endpoints */
322 coap_log_warn("coap_socket_connect_udp: local address required\n");
323 goto error;
324#endif /* COAP_AF_UNIX_SUPPORT */
325 }
326
327 /* special treatment for sockets that are used for multicast communication */
328 if (is_mcast) {
329 if (!(local_if && local_if->addr.sa.sa_family)) {
330 /* Bind to a (unused) port to simplify logging */
331 coap_address_t bind_addr;
332
333 coap_address_init(&bind_addr);
334 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
335 if (bind(sock->fd, &bind_addr.addr.sa,
337 bind_addr.addr.sa.sa_family == AF_INET ?
338 (socklen_t)sizeof(struct sockaddr_in) :
339#endif /* COAP_IPV4_SUPPORT */
340 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
341 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
343 goto error;
344 }
345 }
346 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
347 coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
349 }
350 coap_address_copy(remote_addr, &connect_addr);
351 coap_address_copy(&sock->mcast_addr, &connect_addr);
353 if (coap_is_bcast(server) &&
354 setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
355 sizeof(on)) == COAP_SOCKET_ERROR)
356 coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
358 return 1;
359 }
360
361 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
362#if COAP_AF_UNIX_SUPPORT
363 if (connect_addr.addr.sa.sa_family == AF_UNIX) {
364 coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
365 connect_addr.addr.cun.sun_path, coap_socket_strerror());
366 } else
367#endif /* COAP_AF_UNIX_SUPPORT */
368 {
369 coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
370 coap_socket_strerror(), connect_addr.addr.sa.sa_family);
371 }
372 goto error;
373 }
374
375 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
376 coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
378 }
379
380 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
381 coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
383 }
384
386 return 1;
387
388error:
389 coap_socket_close(sock);
390 return 0;
391}
392#endif /* COAP_CLIENT_SUPPORT */
393
394void
396 if (sock->fd != COAP_INVALID_SOCKET && !(sock->flags & COAP_SOCKET_SLAVE)) {
397#ifdef COAP_EPOLL_SUPPORT
398#if COAP_SERVER_SUPPORT
399 coap_context_t *context = sock->session ? sock->session->context :
400 sock->endpoint ? sock->endpoint->context : NULL;
401#else /* COAP_SERVER_SUPPORT */
402 coap_context_t *context = sock->session ? sock->session->context : NULL;
403#endif /* COAP_SERVER_SUPPORT */
404 if (context != NULL) {
405 int ret;
406 struct epoll_event event;
407
408 /* Kernels prior to 2.6.9 expect non NULL event parameter */
409 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
410 if (ret == -1 && errno != ENOENT) {
411 coap_log_err("%s: epoll_ctl DEL failed: %d: %s (%d)\n",
412 "coap_socket_close",
413 sock->fd,
414 coap_socket_strerror(), errno);
415 }
416 }
417#endif /* COAP_EPOLL_SUPPORT */
418#if COAP_SERVER_SUPPORT
419#if COAP_AF_UNIX_SUPPORT
420 if (sock->endpoint &&
421 sock->endpoint->bind_addr.addr.sa.sa_family == AF_UNIX) {
422 /* Clean up Unix endpoint */
423#ifdef _WIN32
424 _unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
425#else /* ! _WIN32 */
426 unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
427#endif /* ! _WIN32 */
428 }
429#endif /* COAP_AF_UNIX_SUPPORT */
430 sock->endpoint = NULL;
431#endif /* COAP_SERVER_SUPPORT */
432#if COAP_CLIENT_SUPPORT
433#if COAP_AF_UNIX_SUPPORT
434 if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
435 sock->session->addr_info.local.addr.sa.sa_family == AF_UNIX) {
436 /* Clean up Unix endpoint */
437#ifdef _WIN32
438 _unlink(sock->session->addr_info.local.addr.cun.sun_path);
439#else /* ! _WIN32 */
440 unlink(sock->session->addr_info.local.addr.cun.sun_path);
441#endif /* ! _WIN32 */
442 }
443#endif /* COAP_AF_UNIX_SUPPORT */
444#endif /* COAP_CLIENT_SUPPORT */
445 sock->session = NULL;
446 coap_closesocket(sock->fd);
447 sock->fd = COAP_INVALID_SOCKET;
448 }
449 sock->flags = COAP_SOCKET_EMPTY;
450}
451
452#ifdef COAP_EPOLL_SUPPORT
453void
455 uint32_t events,
456 const char *func) {
457 int ret;
458 struct epoll_event event;
459 coap_context_t *context;
460
461#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
462 (void)func;
463#endif
464
465 if (sock == NULL)
466 return;
467
468#if COAP_SERVER_SUPPORT
469 context = sock->session ? sock->session->context :
470 sock->endpoint ? sock->endpoint->context : NULL;
471#else /* ! COAP_SERVER_SUPPORT */
472 context = sock->session ? sock->session->context : NULL;
473#endif /* ! COAP_SERVER_SUPPORT */
474 if (context == NULL)
475 return;
476
477 /* Needed if running 32bit as ptr is only 32bit */
478 memset(&event, 0, sizeof(event));
479 event.events = events;
480 event.data.ptr = sock;
481
482 ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
483 if (ret == -1) {
484 coap_log_err("%s: epoll_ctl ADD failed: %s (%d)\n",
485 func,
486 coap_socket_strerror(), errno);
487 }
488}
489
490void
492 uint32_t events,
493 const char *func) {
494 int ret;
495 struct epoll_event event;
496 coap_context_t *context;
497
498#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
499 (void)func;
500#endif
501
502 if (sock == NULL)
503 return;
504
505#if COAP_SERVER_SUPPORT
506 context = sock->session ? sock->session->context :
507 sock->endpoint ? sock->endpoint->context : NULL;
508#else /* COAP_SERVER_SUPPORT */
509 context = sock->session ? sock->session->context : NULL;
510#endif /* COAP_SERVER_SUPPORT */
511 if (context == NULL)
512 return;
513
514 event.events = events;
515 event.data.ptr = sock;
516
517 ret = epoll_ctl(context->epfd, EPOLL_CTL_MOD, sock->fd, &event);
518 if (ret == -1) {
519#if (COAP_MAX_LOGGING_LEVEL < COAP_LOG_ERR)
520 (void)func;
521#endif
522 coap_log_err("%s: epoll_ctl MOD failed: %s (%d)\n",
523 func,
524 coap_socket_strerror(), errno);
525 }
526}
527#endif /* COAP_EPOLL_SUPPORT */
528
529#endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! RIOT_VERSION*/
530
531#ifndef WITH_CONTIKI
532void
534#if COAP_EPOLL_SUPPORT
535 if (context->eptimerfd != -1) {
536 coap_tick_t now;
537
538 coap_ticks(&now);
539 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
540 struct itimerspec new_value;
541 int ret;
542
543 context->next_timeout = now + delay;
544 memset(&new_value, 0, sizeof(new_value));
545 if (delay == 0) {
546 new_value.it_value.tv_nsec = 1; /* small but not zero */
547 } else {
548 new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND;
549 new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) *
550 1000000;
551 }
552 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
553 if (ret == -1) {
554 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
555 "coap_update_io_timer",
556 coap_socket_strerror(), errno);
557 }
558#ifdef COAP_DEBUG_WAKEUP_TIMES
559 else {
560 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
561 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
562 }
563#endif /* COAP_DEBUG_WAKEUP_TIMES */
564 }
565 }
566#else /* ! COAP_EPOLL_SUPPORT */
567 coap_tick_t now;
568
569 coap_ticks(&now);
570 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
571 context->next_timeout = now + delay;
572 }
573#endif /* ! COAP_EPOLL_SUPPORT */
574}
575#endif /* ! WITH_CONTIKI */
576
577#if !defined(WITH_CONTIKI) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
578
579#ifdef _WIN32
580static void
581coap_win_error_to_errno(void) {
582 int w_error = WSAGetLastError();
583 switch (w_error) {
584 case WSA_NOT_ENOUGH_MEMORY:
585 errno = ENOMEM;
586 break;
587 case WSA_INVALID_PARAMETER:
588 errno = EINVAL;
589 break;
590 case WSAEINTR:
591 errno = EINTR;
592 break;
593 case WSAEBADF:
594 errno = EBADF;
595 break;
596 case WSAEACCES:
597 errno = EACCES;
598 break;
599 case WSAEFAULT:
600 errno = EFAULT;
601 break;
602 case WSAEINVAL:
603 errno = EINVAL;
604 break;
605 case WSAEMFILE:
606 errno = EMFILE;
607 break;
608 case WSAEWOULDBLOCK:
609 errno = EWOULDBLOCK;
610 break;
611 case WSAENETDOWN:
612 errno = ENETDOWN;
613 break;
614 case WSAENETUNREACH:
615 errno = ENETUNREACH;
616 break;
617 case WSAENETRESET:
618 errno = ENETRESET;
619 break;
620 case WSAECONNABORTED:
621 errno = ECONNABORTED;
622 break;
623 case WSAECONNRESET:
624 errno = ECONNRESET;
625 break;
626 case WSAENOBUFS:
627 errno = ENOBUFS;
628 break;
629 case WSAETIMEDOUT:
630 errno = ETIMEDOUT;
631 break;
632 case WSAECONNREFUSED:
633 errno = ECONNREFUSED;
634 break;
635 case WSAEADDRNOTAVAIL:
636 errno = EADDRNOTAVAIL;
637 break;
638 default:
639 coap_log_err("WSAGetLastError: %d mapping to errno failed - please fix\n",
640 w_error);
641 errno = EPERM;
642 break;
643 }
644}
645#endif /* _WIN32 */
646
647/*
648 * strm
649 * return +ve Number of bytes written.
650 * 0 No data written.
651 * -1 Error (error in errno).
652 */
653ssize_t
654coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
655 ssize_t r;
656
658#ifdef _WIN32
659 r = send(sock->fd, (const char *)data, (int)data_len, 0);
660#else
661#ifndef MSG_NOSIGNAL
662#define MSG_NOSIGNAL 0
663#endif /* MSG_NOSIGNAL */
664 r = send(sock->fd, data, data_len, MSG_NOSIGNAL);
665#endif
666 if (r == COAP_SOCKET_ERROR) {
667#ifdef _WIN32
668 coap_win_error_to_errno();
669#endif /* _WIN32 */
670 if (errno==EAGAIN ||
671#if EAGAIN != EWOULDBLOCK
672 errno == EWOULDBLOCK ||
673#endif
674 errno == EINTR) {
676#ifdef COAP_EPOLL_SUPPORT
678 EPOLLOUT |
679 ((sock->flags & COAP_SOCKET_WANT_READ) ?
680 EPOLLIN : 0),
681 __func__);
682#endif /* COAP_EPOLL_SUPPORT */
683 return 0;
684 }
685 if (errno == EPIPE || errno == ECONNRESET) {
686 coap_log_info("coap_socket_write: send: %s\n",
688 } else {
689 coap_log_warn("coap_socket_write: send: %s\n",
691 }
692 return -1;
693 }
694 if (r < (ssize_t)data_len) {
696#ifdef COAP_EPOLL_SUPPORT
698 EPOLLOUT |
699 ((sock->flags & COAP_SOCKET_WANT_READ) ?
700 EPOLLIN : 0),
701 __func__);
702#endif /* COAP_EPOLL_SUPPORT */
703 }
704 return r;
705}
706
707/*
708 * strm
709 * return >=0 Number of bytes read.
710 * -1 Error (error in errno).
711 */
712ssize_t
713coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
714 ssize_t r;
715
716#ifdef _WIN32
717 r = recv(sock->fd, (char *)data, (int)data_len, 0);
718#else
719 r = recv(sock->fd, data, data_len, 0);
720#endif
721 if (r == 0) {
722 /* graceful shutdown */
723 sock->flags &= ~COAP_SOCKET_CAN_READ;
724 errno = ECONNRESET;
725 return -1;
726 } else if (r == COAP_SOCKET_ERROR) {
727 sock->flags &= ~COAP_SOCKET_CAN_READ;
728#ifdef _WIN32
729 coap_win_error_to_errno();
730#endif /* _WIN32 */
731 if (errno==EAGAIN ||
732#if EAGAIN != EWOULDBLOCK
733 errno == EWOULDBLOCK ||
734#endif
735 errno == EINTR) {
736 return 0;
737 }
738 if (errno != ECONNRESET) {
739 coap_log_warn("coap_socket_read: recv: %s\n",
741 }
742 return -1;
743 }
744 if (r < (ssize_t)data_len)
745 sock->flags &= ~COAP_SOCKET_CAN_READ;
746 return r;
747}
748
749#endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! RIOT_VERSION */
750
751#if !defined(WITH_LWIP) && !defined(__ZEPHYR__)
752#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
753/* define struct in6_pktinfo and struct in_pktinfo if not available
754 FIXME: check with configure
755*/
756#if !defined(__MINGW32__) && !defined(RIOT_VERSION)
758 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
759 unsigned int ipi6_ifindex; /* send/recv interface index */
760};
761
764 struct in_addr ipi_spec_dst;
765 struct in_addr ipi_addr;
766};
767#endif /* ! __MINGW32__ && ! RIOT_VERSION */
768#endif
769#endif /* ! WITH_LWIP && ! __ZEPHYR__ */
770
771#if !defined(WITH_CONTIKI) && !defined(SOL_IP)
772/* Solaris expects level IPPROTO_IP for ancillary data. */
773#define SOL_IP IPPROTO_IP
774#endif
775#ifdef _WIN32
776#define COAP_SOL_IP IPPROTO_IP
777#else /* ! _WIN32 */
778#define COAP_SOL_IP SOL_IP
779#endif /* ! _WIN32 */
780
781#if defined(_WIN32)
782#include <mswsock.h>
783#if defined(__MINGW32__)
784static __thread LPFN_WSARECVMSG lpWSARecvMsg = NULL;
785#if(_WIN32_WINNT >= 0x0600)
786#define CMSG_FIRSTHDR WSA_CMSG_FIRSTHDR
787#define CMSG_NXTHDR WSA_CMSG_NXTHDR
788#define CMSG_LEN WSA_CMSG_LEN
789#define CMSG_SPACE WSA_CMSG_SPACE
790#if(_WIN32_WINNT < 0x0603 || _WIN32_WINNT == 0x0a00)
791#define cmsghdr _WSACMSGHDR
792#endif /* (_WIN32_WINNT<0x0603 || _WIN32_WINNT == 0x0a00) */
793#endif /* (_WIN32_WINNT>=0x0600) */
794#else /* ! __MINGW32__ */
795static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
796#endif /* ! __MINGW32__ */
797/* Map struct WSABUF fields to their posix counterpart */
798#define msghdr _WSAMSG
799#define msg_name name
800#define msg_namelen namelen
801#define msg_iov lpBuffers
802#define msg_iovlen dwBufferCount
803#define msg_control Control.buf
804#define msg_controllen Control.len
805#define iovec _WSABUF
806#define iov_base buf
807#define iov_len len
808#define iov_len_t u_long
809#undef CMSG_DATA
810#define CMSG_DATA WSA_CMSG_DATA
811#define ipi_spec_dst ipi_addr
812#if !defined(__MINGW32__)
813#pragma warning( disable : 4116 )
814#endif /* ! __MINGW32__ */
815#else
816#define iov_len_t size_t
817#endif
818
819#if defined(_CYGWIN_ENV) || defined(__QNXNTO__)
820#define ipi_spec_dst ipi_addr
821#endif
822
823#if !defined(RIOT_VERSION) && !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
824#if COAP_CLIENT_SUPPORT
825static uint32_t cid_track_counter;
826
827static void
828coap_test_cid_tuple_change(coap_session_t *session) {
829 if (session->type == COAP_SESSION_TYPE_CLIENT &&
830 session->negotiated_cid &&
832 session->proto == COAP_PROTO_DTLS && session->context->testing_cids) {
833 if ((++cid_track_counter) % session->context->testing_cids == 0) {
834 coap_address_t local_if = session->addr_info.local;
835 uint16_t port = coap_address_get_port(&local_if);
836
837 port++;
838 coap_address_set_port(&local_if, port);
839
840 coap_socket_close(&session->sock);
841 session->sock.session = session;
842 if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
843 port,
844 &session->addr_info.local,
845 &session->addr_info.remote)) {
846 coap_log_err("Tuple change for CID failed\n");
847 return;
848#ifdef COAP_EPOLL_SUPPORT
849 } else {
850 coap_epoll_ctl_add(&session->sock,
851 EPOLLIN |
852 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
853 EPOLLOUT : 0),
854 __func__);
855#endif /* COAP_EPOLL_SUPPORT */
856 }
858 }
859 }
860}
861#endif /* COAP_CLIENT_SUPPORT */
862
863/*
864 * dgram
865 * return +ve Number of bytes written.
866 * -1 Error error in errno).
867 */
868ssize_t
870 const uint8_t *data, size_t datalen) {
871 ssize_t bytes_written = 0;
872
873#if COAP_CLIENT_SUPPORT
874 coap_test_cid_tuple_change(session);
875#endif /* COAP_CLIENT_SUPPORT */
876
877 if (!coap_debug_send_packet()) {
878 bytes_written = (ssize_t)datalen;
879 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
880#ifdef _WIN32
881 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
882#else
883 bytes_written = send(sock->fd, data, datalen, 0);
884#endif
885 } else {
886#if defined(_WIN32)
887 DWORD dwNumberOfBytesSent = 0;
888 int r;
889#endif /* _WIN32 */
890#ifdef HAVE_STRUCT_CMSGHDR
891 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
892 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
893 struct msghdr mhdr;
894 struct iovec iov[1];
895 const void *addr = &session->addr_info.remote.addr;
896
897 assert(session);
898
899 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
900 iov[0].iov_len = (iov_len_t)datalen;
901
902 memset(buf, 0, sizeof(buf));
903
904 memset(&mhdr, 0, sizeof(struct msghdr));
905 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
906 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
907 (socklen_t)sizeof(struct sockaddr_in) :
908 session->addr_info.remote.size;
909
910 mhdr.msg_iov = iov;
911 mhdr.msg_iovlen = 1;
912
913 if (!coap_address_isany(&session->addr_info.local) &&
914 !coap_is_mcast(&session->addr_info.local)) {
915 switch (session->addr_info.local.addr.sa.sa_family) {
916#if COAP_IPV6_SUPPORT
917 case AF_INET6: {
918 struct cmsghdr *cmsg;
919
920#if COAP_IPV4_SUPPORT
921 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
922#if defined(IP_PKTINFO)
923 struct in_pktinfo *pktinfo;
924 mhdr.msg_control = buf;
925 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
926
927 cmsg = CMSG_FIRSTHDR(&mhdr);
928 cmsg->cmsg_level = COAP_SOL_IP;
929 cmsg->cmsg_type = IP_PKTINFO;
930 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
931
932 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
933
934 pktinfo->ipi_ifindex = session->ifindex;
935 memcpy(&pktinfo->ipi_spec_dst,
936 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
937 sizeof(pktinfo->ipi_spec_dst));
938#elif defined(IP_SENDSRCADDR)
939 mhdr.msg_control = buf;
940 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
941
942 cmsg = CMSG_FIRSTHDR(&mhdr);
943 cmsg->cmsg_level = IPPROTO_IP;
944 cmsg->cmsg_type = IP_SENDSRCADDR;
945 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
946
947 memcpy(CMSG_DATA(cmsg),
948 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
949 sizeof(struct in_addr));
950#endif /* IP_PKTINFO */
951 } else {
952#endif /* COAP_IPV4_SUPPORT */
953 struct in6_pktinfo *pktinfo;
954 mhdr.msg_control = buf;
955 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
956
957 cmsg = CMSG_FIRSTHDR(&mhdr);
958 cmsg->cmsg_level = IPPROTO_IPV6;
959 cmsg->cmsg_type = IPV6_PKTINFO;
960 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
961
962 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
963
964 if (coap_is_mcast(&session->addr_info.remote)) {
965 pktinfo->ipi6_ifindex = session->addr_info.remote.addr.sin6.sin6_scope_id;
966 } else {
967 pktinfo->ipi6_ifindex = session->ifindex;
968 }
969 memcpy(&pktinfo->ipi6_addr,
970 &session->addr_info.local.addr.sin6.sin6_addr,
971 sizeof(pktinfo->ipi6_addr));
972#if COAP_IPV4_SUPPORT
973 }
974#endif /* COAP_IPV4_SUPPORT */
975 break;
976 }
977#endif /* COAP_IPV6_SUPPORT */
978#if COAP_IPV4_SUPPORT
979 case AF_INET: {
980#if defined(IP_PKTINFO)
981 struct cmsghdr *cmsg;
982 struct in_pktinfo *pktinfo;
983
984 mhdr.msg_control = buf;
985 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
986
987 cmsg = CMSG_FIRSTHDR(&mhdr);
988 cmsg->cmsg_level = COAP_SOL_IP;
989 cmsg->cmsg_type = IP_PKTINFO;
990 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
991
992 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
993
994 pktinfo->ipi_ifindex = session->ifindex;
995 memcpy(&pktinfo->ipi_spec_dst,
996 &session->addr_info.local.addr.sin.sin_addr,
997 sizeof(pktinfo->ipi_spec_dst));
998#elif defined(IP_SENDSRCADDR)
999 struct cmsghdr *cmsg;
1000 mhdr.msg_control = buf;
1001 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
1002
1003 cmsg = CMSG_FIRSTHDR(&mhdr);
1004 cmsg->cmsg_level = IPPROTO_IP;
1005 cmsg->cmsg_type = IP_SENDSRCADDR;
1006 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1007
1008 memcpy(CMSG_DATA(cmsg),
1009 &session->addr_info.local.addr.sin.sin_addr,
1010 sizeof(struct in_addr));
1011#endif /* IP_PKTINFO */
1012 break;
1013 }
1014#endif /* COAP_IPV4_SUPPORT */
1015#if COAP_AF_UNIX_SUPPORT
1016 case AF_UNIX:
1017 break;
1018#endif /* COAP_AF_UNIX_SUPPORT */
1019 default:
1020 /* error */
1021 coap_log_warn("protocol not supported\n");
1022 return -1;
1023 }
1024 }
1025#endif /* HAVE_STRUCT_CMSGHDR */
1026
1027#if defined(_WIN32)
1028 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
1029 NULL /*lpCompletionRoutine*/);
1030 if (r == 0)
1031 bytes_written = (ssize_t)dwNumberOfBytesSent;
1032 else {
1033 bytes_written = -1;
1034 coap_win_error_to_errno();
1035 }
1036#else /* !_WIN32 */
1037#ifdef HAVE_STRUCT_CMSGHDR
1038 bytes_written = sendmsg(sock->fd, &mhdr, 0);
1039#else /* ! HAVE_STRUCT_CMSGHDR */
1040 bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
1041 &session->addr_info.remote.addr.sa,
1042 session->addr_info.remote.size);
1043#endif /* ! HAVE_STRUCT_CMSGHDR */
1044#endif /* !_WIN32 */
1045 }
1046
1047 if (bytes_written < 0)
1048 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
1049
1050 return bytes_written;
1051}
1052#endif /* ! RIOT_VERSION && ! WITH_LWIP && ! WITH_CONTIKI */
1053
1054#define SIN6(A) ((struct sockaddr_in6 *)(A))
1055
1056void
1057coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
1058 *address = packet->payload;
1059 *length = packet->length;
1060}
1061
1062#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
1063/*
1064 * dgram
1065 * return +ve Number of bytes written.
1066 * -1 Error error in errno).
1067 * -2 ICMP error response
1068 */
1069ssize_t
1071 ssize_t len = -1;
1072
1073 assert(sock);
1074 assert(packet);
1075
1076 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
1077 return -1;
1078 } else {
1079 /* clear has-data flag */
1080 sock->flags &= ~COAP_SOCKET_CAN_READ;
1081 }
1082
1083 if (sock->flags & COAP_SOCKET_CONNECTED) {
1084#ifdef _WIN32
1085 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
1086#else
1087 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
1088#endif
1089 if (len < 0) {
1090#ifdef _WIN32
1091 coap_win_error_to_errno();
1092#endif /* _WIN32 */
1093 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1094 /* client-side ICMP destination unreachable, ignore it */
1095 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1096 sock->session ?
1097 coap_session_str(sock->session) : "",
1099 return -2;
1100 }
1101 if (errno != EAGAIN) {
1102 coap_log_warn("** %s: coap_socket_recv: %s\n",
1103 sock->session ?
1104 coap_session_str(sock->session) : "",
1106 }
1107 goto error;
1108 } else if (len > 0) {
1109 packet->length = (size_t)len;
1110 }
1111 } else {
1112#if defined(_WIN32)
1113 DWORD dwNumberOfBytesRecvd = 0;
1114 int r;
1115#endif /* _WIN32 */
1116#ifdef HAVE_STRUCT_CMSGHDR
1117 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
1118 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1119 struct cmsghdr *cmsg;
1120 struct msghdr mhdr;
1121 struct iovec iov[1];
1122
1123#if defined(__MINGW32__)
1124 iov[0].iov_base = (char *) packet->payload;
1125#else /* ! __MINGW32__ */
1126 iov[0].iov_base = packet->payload;
1127#endif /* defined(__MINGW32__) */
1128 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
1129
1130 memset(&mhdr, 0, sizeof(struct msghdr));
1131
1132 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
1133 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
1134
1135 mhdr.msg_iov = iov;
1136 mhdr.msg_iovlen = 1;
1137
1138 mhdr.msg_control = buf;
1139 mhdr.msg_controllen = sizeof(buf);
1140 /* set a big first length incase recvmsg() does not implement updating
1141 msg_control as well as preset the first cmsg with bad data */
1142 cmsg = (struct cmsghdr *)buf;
1143 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
1144 cmsg->cmsg_level = -1;
1145 cmsg->cmsg_type = -1;
1146
1147#if defined(_WIN32)
1148 if (!lpWSARecvMsg) {
1149 GUID wsaid = WSAID_WSARECVMSG;
1150 DWORD cbBytesReturned = 0;
1151 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
1152 sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
1153 coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
1154 return -1;
1155 }
1156 }
1157 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
1158 NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
1159 if (r == 0)
1160 len = (ssize_t)dwNumberOfBytesRecvd;
1161 else if (r == COAP_SOCKET_ERROR)
1162 coap_win_error_to_errno();
1163#else
1164 len = recvmsg(sock->fd, &mhdr, 0);
1165#endif
1166
1167#else /* ! HAVE_STRUCT_CMSGHDR */
1168 len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
1169 &packet->addr_info.remote.addr.sa,
1170 &packet->addr_info.remote.size);
1171#endif /* ! HAVE_STRUCT_CMSGHDR */
1172
1173 if (len < 0) {
1174#ifdef _WIN32
1175 coap_win_error_to_errno();
1176#endif /* _WIN32 */
1177 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1178 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
1179 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1180 sock->session ?
1181 coap_session_str(sock->session) : "",
1183 return 0;
1184 }
1185 if (errno != EAGAIN) {
1186 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
1187 }
1188 goto error;
1189 } else {
1190#ifdef HAVE_STRUCT_CMSGHDR
1191 int dst_found = 0;
1192
1193 packet->addr_info.remote.size = mhdr.msg_namelen;
1194 packet->length = (size_t)len;
1195
1196 /* Walk through ancillary data records until the local interface
1197 * is found where the data was received. */
1198 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
1199
1200#if COAP_IPV6_SUPPORT
1201 /* get the local interface for IPv6 */
1202 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
1203 union {
1204 uint8_t *c;
1205 struct in6_pktinfo *p;
1206 } u;
1207 u.c = CMSG_DATA(cmsg);
1208 packet->ifindex = (int)(u.p->ipi6_ifindex);
1209 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
1210 &u.p->ipi6_addr, sizeof(struct in6_addr));
1211 dst_found = 1;
1212 break;
1213 }
1214#endif /* COAP_IPV6_SUPPORT */
1215
1216#if COAP_IPV4_SUPPORT
1217 /* local interface for IPv4 */
1218#if defined(IP_PKTINFO)
1219 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
1220 union {
1221 uint8_t *c;
1222 struct in_pktinfo *p;
1223 } u;
1224 u.c = CMSG_DATA(cmsg);
1225 packet->ifindex = u.p->ipi_ifindex;
1226#if COAP_IPV6_SUPPORT
1227 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
1228 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
1229 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
1230 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
1231 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
1232 &u.p->ipi_addr, sizeof(struct in_addr));
1233 } else
1234#endif /* COAP_IPV6_SUPPORT */
1235 {
1236 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1237 &u.p->ipi_addr, sizeof(struct in_addr));
1238 }
1239 dst_found = 1;
1240 break;
1241 }
1242#endif /* IP_PKTINFO */
1243#if defined(IP_RECVDSTADDR)
1244 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
1245 packet->ifindex = (int)sock->fd;
1246 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1247 CMSG_DATA(cmsg), sizeof(struct in_addr));
1248 dst_found = 1;
1249 break;
1250 }
1251#endif /* IP_RECVDSTADDR */
1252#endif /* COAP_IPV4_SUPPORT */
1253 if (!dst_found) {
1254 /* cmsg_level / cmsg_type combination we do not understand
1255 (ignore preset case for bad recvmsg() not updating cmsg) */
1256 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1257 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1258 cmsg->cmsg_level, cmsg->cmsg_type);
1259 }
1260 }
1261 }
1262 if (!dst_found) {
1263 /* Not expected, but cmsg_level and cmsg_type don't match above and
1264 may need a new case */
1265 packet->ifindex = (int)sock->fd;
1266 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1267 &packet->addr_info.local.size) < 0) {
1268 coap_log_debug("Cannot determine local port\n");
1269 }
1270 }
1271#else /* ! HAVE_STRUCT_CMSGHDR */
1272 packet->length = (size_t)len;
1273 packet->ifindex = 0;
1274 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1275 &packet->addr_info.local.size) < 0) {
1276 coap_log_debug("Cannot determine local port\n");
1277 goto error;
1278 }
1279#endif /* ! HAVE_STRUCT_CMSGHDR */
1280 }
1281 }
1282
1283 if (len >= 0)
1284 return len;
1285error:
1286 return -1;
1287}
1288#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION */
1289
1290COAP_API unsigned int
1292 unsigned int ret;
1293
1294 coap_lock_lock(return 0);
1295 ret = coap_io_prepare_epoll_lkd(ctx, now);
1297 return ret;
1298}
1299
1300unsigned int
1302#ifndef COAP_EPOLL_SUPPORT
1303 (void)ctx;
1304 (void)now;
1305 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1306 return 0;
1307#else /* COAP_EPOLL_SUPPORT */
1308 coap_socket_t *sockets[1];
1309 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1310 unsigned int num_sockets;
1311 unsigned int timeout;
1312
1314 /* Use the common logic */
1315 timeout = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, &num_sockets, now);
1316 /* Save when the next expected I/O is to take place */
1317 ctx->next_timeout = timeout ? now + timeout : 0;
1318 if (ctx->eptimerfd != -1) {
1319 struct itimerspec new_value;
1320 int ret;
1321
1322 memset(&new_value, 0, sizeof(new_value));
1323 coap_ticks(&now);
1324 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1325 coap_tick_t rem_timeout = ctx->next_timeout - now;
1326 /* Need to trigger an event on ctx->eptimerfd in the future */
1327 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1328 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1329 1000000;
1330 }
1331#ifdef COAP_DEBUG_WAKEUP_TIMES
1332 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
1333 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1334#endif /* COAP_DEBUG_WAKEUP_TIMES */
1335 /* reset, or specify a future time for eptimerfd to trigger */
1336 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1337 if (ret == -1) {
1338 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
1339 "coap_io_prepare_epoll",
1340 coap_socket_strerror(), errno);
1341 }
1342 }
1343 return timeout;
1344#endif /* COAP_EPOLL_SUPPORT */
1345}
1346
1347/*
1348 * return 0 No i/o pending
1349 * +ve millisecs to next i/o activity
1350 */
1351COAP_API unsigned int
1353 coap_socket_t *sockets[],
1354 unsigned int max_sockets,
1355 unsigned int *num_sockets,
1356 coap_tick_t now) {
1357 unsigned int ret;
1358
1359 coap_lock_lock(return 0);
1360 ret = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, num_sockets, now);
1362 return ret;
1363}
1364
1365/*
1366 * return 0 No i/o pending
1367 * +ve millisecs to next i/o activity
1368 */
1369unsigned int
1371 coap_socket_t *sockets[],
1372 unsigned int max_sockets,
1373 unsigned int *num_sockets,
1374 coap_tick_t now) {
1375 coap_queue_t *nextpdu;
1376 coap_session_t *s, *stmp;
1378 coap_tick_t s_timeout;
1379#if COAP_SERVER_SUPPORT
1380 int check_dtls_timeouts = 0;
1381#endif /* COAP_SERVER_SUPPORT */
1382#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION)
1383 (void)sockets;
1384 (void)max_sockets;
1385#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/
1386
1388 *num_sockets = 0;
1389
1390#if COAP_SERVER_SUPPORT
1391 /* Check to see if we need to send off any Observe requests */
1393
1394#if COAP_ASYNC_SUPPORT
1395 /* Check to see if we need to send off any Async requests */
1396 if (coap_check_async(ctx, now, &s_timeout)) {
1397 if (s_timeout < timeout)
1398 timeout = s_timeout;
1399 }
1400#endif /* COAP_ASYNC_SUPPORT */
1401#endif /* COAP_SERVER_SUPPORT */
1402
1403 /* Check to see if we need to send off any retransmit request */
1404 nextpdu = coap_peek_next(ctx);
1405 while (nextpdu && now >= ctx->sendqueue_basetime &&
1406 nextpdu->t <= now - ctx->sendqueue_basetime) {
1407 coap_retransmit(ctx, coap_pop_next(ctx));
1408 nextpdu = coap_peek_next(ctx);
1409 }
1410 if (nextpdu && now >= ctx->sendqueue_basetime &&
1411 (nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1412 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1413
1414 /* Check for DTLS timeouts */
1415 if (ctx->dtls_context) {
1418 if (tls_timeout > 0) {
1419 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1420 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1421 coap_log_debug("** DTLS global timeout set to %dms\n",
1422 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1423 if (tls_timeout - now < timeout)
1424 timeout = tls_timeout - now;
1425 }
1426#if COAP_SERVER_SUPPORT
1427 } else {
1428 check_dtls_timeouts = 1;
1429#endif /* COAP_SERVER_SUPPORT */
1430 }
1431 }
1432#if COAP_PROXY_SUPPORT
1433 if (coap_proxy_check_timeouts(ctx, now, &s_timeout)) {
1434 if (s_timeout < timeout)
1435 timeout = s_timeout;
1436 }
1437#endif /* COAP_PROXY_SUPPORT */
1438#if COAP_SERVER_SUPPORT
1439 coap_endpoint_t *ep;
1440 coap_tick_t session_timeout;
1441
1442 if (ctx->session_timeout > 0)
1443 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1444 else
1446
1447 LL_FOREACH(ctx->endpoint, ep) {
1448#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1450 if (*num_sockets < max_sockets)
1451 sockets[(*num_sockets)++] = &ep->sock;
1452 }
1453#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1454 SESSIONS_ITER_SAFE(ep->sessions, s, stmp) {
1455 /* Check whether any idle server sessions should be released */
1456 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1457 s->delayqueue == NULL &&
1458 (s->last_rx_tx + session_timeout <= now ||
1462 continue;
1463 } else {
1464 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1465 s->delayqueue == NULL) {
1466 /* Has to be positive based on if() above */
1467 s_timeout = (s->last_rx_tx + session_timeout) - now;
1468 if (s_timeout < timeout)
1469 timeout = s_timeout;
1470 }
1471 /* Make sure the session object is not deleted in any callbacks */
1473 /* Check any DTLS timeouts and expire if appropriate */
1474 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1475 s->proto == COAP_PROTO_DTLS && s->tls) {
1476 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1477 while (tls_timeout > 0 && tls_timeout <= now) {
1478 coap_log_debug("** %s: DTLS retransmit timeout\n",
1479 coap_session_str(s));
1481 goto release_1;
1482
1483 if (s->tls)
1484 tls_timeout = coap_dtls_get_timeout(s, now);
1485 else {
1486 tls_timeout = 0;
1487 timeout = 1;
1488 }
1489 }
1490 if (tls_timeout > 0 && tls_timeout - now < timeout)
1491 timeout = tls_timeout - now;
1492 }
1493 /* Check if any server large receives are missing blocks */
1494 if (s->lg_srcv) {
1495 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1496 if (s_timeout < timeout)
1497 timeout = s_timeout;
1498 }
1499 }
1500 /* Check if any server large sending have timed out */
1501 if (s->lg_xmit) {
1502 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1503 if (s_timeout < timeout)
1504 timeout = s_timeout;
1505 }
1506 }
1507#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1509 if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE))
1510 sockets[(*num_sockets)++] = &s->sock;
1511 }
1512#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1513#if COAP_Q_BLOCK_SUPPORT
1514 /*
1515 * Check if any server large transmits have hit MAX_PAYLOAD and need
1516 * restarting
1517 */
1518 if (s->lg_xmit) {
1519 if (coap_block_check_q_block2_xmit(s, now, &s_timeout)) {
1520 if (s_timeout < timeout)
1521 timeout = s_timeout;
1522 }
1523 }
1524#endif /* COAP_Q_BLOCK_SUPPORT */
1525release_1:
1527 }
1528 if (s->type == COAP_SESSION_TYPE_SERVER &&
1530 (s->ref_subscriptions || s->ref_proxy_subs) && !s->con_active &&
1531 ctx->ping_timeout > 0) {
1532 /* Only do this if this session is observing */
1533 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1534 /* Time to send a ping */
1535 coap_mid_t mid;
1536
1537 if ((mid = coap_session_send_ping_lkd(s)) == COAP_INVALID_MID) {
1538 /* Some issue - not safe to continue processing */
1539 s->last_rx_tx = now;
1540 continue;
1541 }
1542 s->last_ping_mid = mid;
1543 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1545 /* check the next session */
1546 continue;
1547 }
1548 s->last_rx_tx = now;
1549 s->last_ping = now;
1550 } else {
1551 /* Always positive due to if() above */
1552 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1553 if (s_timeout < timeout)
1554 timeout = s_timeout;
1555 }
1556 }
1557 }
1558 }
1559#endif /* COAP_SERVER_SUPPORT */
1560#if COAP_CLIENT_SUPPORT
1561 SESSIONS_ITER_SAFE(ctx->sessions, s, stmp) {
1562 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1564 ctx->ping_timeout > 0) {
1565 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1566 /* Time to send a ping */
1567 coap_mid_t mid;
1568
1569 if ((mid = coap_session_send_ping_lkd(s)) == COAP_INVALID_MID) {
1570 /* Some issue - not safe to continue processing */
1571 s->last_rx_tx = now;
1573 continue;
1574 }
1575 s->last_ping_mid = mid;
1576 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1578 }
1579 s->last_rx_tx = now;
1580 s->last_ping = now;
1581 } else {
1582 /* Always positive due to if() above */
1583 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1584 if (s_timeout < timeout)
1585 timeout = s_timeout;
1586 }
1587 }
1588 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1589 s->session_failed && ctx->reconnect_time) {
1590 if (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND <= now) {
1591 if (!coap_session_reconnect(s)) {
1592 /* server is not back up yet - delay retry a while */
1593 s->last_rx_tx = now;
1594 s_timeout = ctx->reconnect_time * COAP_TICKS_PER_SECOND;
1595 if (timeout == 0 || s_timeout < timeout)
1596 timeout = s_timeout;
1597 }
1598 } else {
1599 /* Always positive due to if() above */
1600 s_timeout = (s->last_rx_tx + ctx->reconnect_time * COAP_TICKS_PER_SECOND) - now;
1601 if (s_timeout < timeout)
1602 timeout = s_timeout;
1603 }
1604 }
1605
1606#if !COAP_DISABLE_TCP
1608 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) {
1609 if (s->csm_tx == 0) {
1610 s->csm_tx = now;
1611 s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000;
1612 } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) {
1613 /* timed out - cannot handle 0, so has to be just +ve */
1614 s_timeout = 1;
1615 } else {
1616 s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now;
1617 }
1618 if (s_timeout < timeout)
1619 timeout = s_timeout;
1620 }
1621#endif /* !COAP_DISABLE_TCP */
1622
1623 /* Make sure the session object is not deleted in any callbacks */
1625 /* Check any DTLS timeouts and expire if appropriate */
1627 s->proto == COAP_PROTO_DTLS && s->tls) {
1628 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1629 while (tls_timeout > 0 && tls_timeout <= now) {
1630 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
1632 goto release_2;
1633
1634 if (s->tls)
1635 tls_timeout = coap_dtls_get_timeout(s, now);
1636 else {
1637 tls_timeout = 0;
1638 timeout = 1;
1639 }
1640 }
1641 if (tls_timeout > 0 && tls_timeout - now < timeout)
1642 timeout = tls_timeout - now;
1643 }
1644
1645 /* Check if any client large receives are missing blocks */
1646 if (s->lg_crcv) {
1647 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1648 if (s_timeout < timeout)
1649 timeout = s_timeout;
1650 }
1651 }
1652 /* Check if any client large sending have timed out */
1653 if (s->lg_xmit) {
1654 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1655 if (s_timeout < timeout)
1656 timeout = s_timeout;
1657 }
1658 }
1659#if COAP_Q_BLOCK_SUPPORT
1660 /*
1661 * Check if any client large transmits have hit MAX_PAYLOAD and need
1662 * restarting
1663 */
1664 if (s->lg_xmit) {
1665 if (coap_block_check_q_block1_xmit(s, now, &s_timeout)) {
1666 if (s_timeout < timeout)
1667 timeout = s_timeout;
1668 }
1669 }
1670#endif /* COAP_Q_BLOCK_SUPPORT */
1671
1672#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1673 assert(s->ref > 1);
1674 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1677 if (*num_sockets < max_sockets && !(s->sock.flags & COAP_SOCKET_SLAVE))
1678 sockets[(*num_sockets)++] = &s->sock;
1679 }
1680#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1681release_2:
1683 }
1684#endif /* COAP_CLIENT_SUPPORT */
1685
1686 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1687}
1688
1689/*
1690 * return 0 Insufficient space to hold fds, or fds not supported
1691 * 1 All fds found
1692 */
1693COAP_API unsigned int
1695 coap_fd_t read_fds[],
1696 unsigned int *have_read_fds,
1697 unsigned int max_read_fds,
1698 coap_fd_t write_fds[],
1699 unsigned int *have_write_fds,
1700 unsigned int max_write_fds,
1701 unsigned int *rem_timeout_ms) {
1702 unsigned int ret;
1703
1704 coap_lock_lock(return 0);
1705 ret = coap_io_get_fds_lkd(ctx, read_fds, have_read_fds, max_read_fds, write_fds,
1706 have_write_fds, max_write_fds, rem_timeout_ms);
1708 return ret;
1709}
1710
1711#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
1712static int
1713coap_add_fd(coap_fd_t fd, coap_fd_t this_fds[], unsigned int *have_this_fds,
1714 unsigned int max_this_fds) {
1715 if (*have_this_fds < max_this_fds) {
1716 this_fds[(*have_this_fds)++] = fd;
1717 return 1;
1718 }
1719 coap_log_warn("coap_io_get_fds: Insufficient space for new fd (%u >= %u)\n", *have_this_fds,
1720 max_this_fds);
1721 return 0;
1722}
1723
1724/*
1725 * return 0 Insufficient space to hold fds, or fds not supported
1726 * 1 All fds found
1727 */
1728unsigned int
1730 coap_fd_t read_fds[],
1731 unsigned int *have_read_fds,
1732 unsigned int max_read_fds,
1733 coap_fd_t write_fds[],
1734 unsigned int *have_write_fds,
1735 unsigned int max_write_fds,
1736 unsigned int *rem_timeout_ms) {
1737 *have_read_fds = 0;
1738 *have_write_fds = 0;
1739
1740#ifdef COAP_EPOLL_SUPPORT
1741 (void)write_fds;
1742 (void)max_write_fds;;
1743
1744 if (!coap_add_fd(ctx->epfd, read_fds, have_read_fds, max_read_fds))
1745 return 0;
1746 /* epoll is making use of timerfd, so no need to return any timeout */
1747 *rem_timeout_ms = 0;
1748 return 1;
1749#else /* ! COAP_EPOLL_SUPPORT */
1750 coap_session_t *s, *rtmp;
1751 coap_tick_t now;
1752 unsigned int timeout_ms;
1753#if COAP_SERVER_SUPPORT
1754 coap_endpoint_t *ep;
1755
1756 LL_FOREACH(ctx->endpoint, ep) {
1758 if (!coap_add_fd(ep->sock.fd, read_fds, have_read_fds, max_read_fds))
1759 return 0;
1760 }
1762 if (!coap_add_fd(ep->sock.fd, write_fds, have_write_fds, max_write_fds))
1763 return 0;
1764 }
1765 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1767 if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
1768 return 0;
1769 }
1771 if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
1772 return 0;
1773 }
1774 }
1775 }
1776#endif /* COAP_SERVER_SUPPORT */
1777
1778#if COAP_CLIENT_SUPPORT
1779 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1781 if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
1782 return 0;
1783 }
1785 if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
1786 return 0;
1787 }
1788 }
1789#endif /* COAP_CLIENT_SUPPORT */
1790
1791 coap_ticks(&now);
1792 timeout_ms = (unsigned int)(ctx->next_timeout ? ctx->next_timeout > now ?
1793 ctx->next_timeout - now : 0 : 0) *
1794 1000 / COAP_TICKS_PER_SECOND;
1795 *rem_timeout_ms = timeout_ms;
1796 return 1;
1797#endif /* ! COAP_EPOLL_SUPPORT */
1798}
1799
1800#else /* WITH_LWIP || WITH_CONTIKI */
1801
1802/*
1803 * return 0 Insufficient space to hold fds, or fds not supported
1804 * 1 All fds found
1805 */
1806unsigned int
1808 coap_fd_t read_fds[],
1809 unsigned int *have_read_fds,
1810 unsigned int max_read_fds,
1811 coap_fd_t write_fds[],
1812 unsigned int *have_write_fds,
1813 unsigned int max_write_fds,
1814 unsigned int *rem_timeout_ms) {
1815 (void)ctx;
1816 (void)read_fds;
1817 (void)max_read_fds;
1818 (void)write_fds;
1819 (void)max_write_fds;
1820
1821 *have_read_fds = 0;
1822 *have_write_fds = 0;
1823 *rem_timeout_ms = 0;
1824
1825 coap_log_warn("coap_io_get_fds: Not supported\n");
1826 return 0;
1827}
1828#endif /* WITH_LWIP || WITH_CONTIKI */
1829
1830#if !defined(WITH_LWIP) && !defined(CONTIKI) && !defined(RIOT_VERSION)
1831COAP_API int
1832coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1833 int ret;
1834
1835 coap_lock_lock(return 0);
1836 ret = coap_io_process_lkd(ctx, timeout_ms);
1838 return ret;
1839}
1840
1841int
1842coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms) {
1843 return coap_io_process_with_fds_lkd(ctx, timeout_ms, 0, NULL, NULL, NULL);
1844}
1845
1846COAP_API int
1848 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1849 fd_set *eexceptfds) {
1850 int ret;
1851
1852 coap_lock_lock(return 0);
1853 ret = coap_io_process_with_fds_lkd(ctx, timeout_ms, enfds, ereadfds, ewritefds,
1854 eexceptfds);
1856 return ret;
1857}
1858
1859#if !defined(COAP_EPOLL_SUPPORT) && COAP_THREAD_SAFE
1860static unsigned int
1861coap_io_prepare_fds(coap_context_t *ctx,
1862 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1863 fd_set *eexceptfds) {
1864 coap_session_t *s, *stmp;
1865 unsigned int max_sockets = sizeof(ctx->sockets) / sizeof(ctx->sockets[0]);
1866 coap_fd_t nfds = 0;
1867 unsigned int i;
1868
1869 ctx->num_sockets = 0;
1870#if COAP_SERVER_SUPPORT
1871 coap_endpoint_t *ep;
1872
1873 LL_FOREACH(ctx->endpoint, ep) {
1875 if (ctx->num_sockets < max_sockets)
1876 ctx->sockets[ctx->num_sockets++] = &ep->sock;
1877 }
1878 SESSIONS_ITER(ep->sessions, s, stmp) {
1880 if (ctx->num_sockets < max_sockets)
1881 ctx->sockets[ctx->num_sockets++] = &s->sock;
1882 }
1883 }
1884 }
1885#endif /* COAP_SERVER_SUPPORT */
1886#if COAP_CLIENT_SUPPORT
1887 SESSIONS_ITER(ctx->sessions, s, stmp) {
1888 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1891 if (ctx->num_sockets < max_sockets)
1892 ctx->sockets[ctx->num_sockets++] = &s->sock;
1893 }
1894 }
1895#endif /* COAP_CLIENT_SUPPORT */
1896 if (ereadfds) {
1897 ctx->readfds = *ereadfds;
1898 nfds = enfds;
1899 } else {
1900 FD_ZERO(&ctx->readfds);
1901 }
1902 if (ewritefds) {
1903 ctx->writefds = *ewritefds;
1904 nfds = enfds;
1905 } else {
1906 FD_ZERO(&ctx->writefds);
1907 }
1908 if (eexceptfds) {
1909 ctx->exceptfds = *eexceptfds;
1910 nfds = enfds;
1911 } else {
1912 FD_ZERO(&ctx->exceptfds);
1913 }
1914 for (i = 0; i < ctx->num_sockets; i++) {
1915 if (ctx->sockets[i]->fd + 1 > nfds)
1916 nfds = ctx->sockets[i]->fd + 1;
1917 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1918 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1919 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1920 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1921#if !COAP_DISABLE_TCP
1922 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1923 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1924 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1925 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1926 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1927 }
1928#endif /* !COAP_DISABLE_TCP */
1929 }
1930 return nfds;
1931}
1932#endif /* ! COAP_EPOLL_SUPPORT && COAP_THREAD_SAFE */
1933
1934int
1936 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1937 fd_set *eexceptfds) {
1938 coap_fd_t nfds = 0;
1939 coap_tick_t before, now;
1940 unsigned int timeout;
1941#ifndef COAP_EPOLL_SUPPORT
1942 struct timeval tv;
1943 int result;
1944 unsigned int i;
1945#endif /* ! COAP_EPOLL_SUPPORT */
1946
1948 coap_ticks(&before);
1949
1950#ifndef COAP_EPOLL_SUPPORT
1951
1952 timeout = coap_io_prepare_io_lkd(ctx, ctx->sockets,
1953 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
1954 &ctx->num_sockets, before);
1955 ctx->next_timeout = timeout ? timeout + before : 0;
1956
1957 if (ereadfds) {
1958 ctx->readfds = *ereadfds;
1959 nfds = enfds;
1960 } else {
1961 FD_ZERO(&ctx->readfds);
1962 }
1963 if (ewritefds) {
1964 ctx->writefds = *ewritefds;
1965 nfds = enfds;
1966 } else {
1967 FD_ZERO(&ctx->writefds);
1968 }
1969 if (eexceptfds) {
1970 ctx->exceptfds = *eexceptfds;
1971 nfds = enfds;
1972 } else {
1973 FD_ZERO(&ctx->exceptfds);
1974 }
1975 for (i = 0; i < ctx->num_sockets; i++) {
1976 if (ctx->sockets[i]->fd + 1 > nfds)
1977 nfds = ctx->sockets[i]->fd + 1;
1978 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1979 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1980 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1981 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1982#if !COAP_DISABLE_TCP
1983 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1984 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1985 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1986 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1987 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1988 }
1989#endif /* !COAP_DISABLE_TCP */
1990 }
1991
1992 if (timeout_ms == COAP_IO_NO_WAIT) {
1993 tv.tv_usec = 0;
1994 tv.tv_sec = 0;
1995 timeout = 1;
1996 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1997 ;
1998 } else {
1999 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
2000 timeout = timeout_ms;
2001 tv.tv_usec = (timeout % 1000) * 1000;
2002 tv.tv_sec = (long)(timeout / 1000);
2003 }
2004
2005 /* on Windows select will return an error if called without FDs */
2006 if (nfds > 0) {
2007 /* Unlock so that other threads can lock/update ctx */
2009
2010 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds,
2011 timeout > 0 ? &tv : NULL);
2012
2013 coap_lock_lock(return -1);
2014 } else {
2015 goto all_over;
2016 }
2017
2018 if (result < 0) { /* error */
2019#ifdef _WIN32
2020 coap_win_error_to_errno();
2021#endif
2022 if (errno != EINTR) {
2023#if COAP_THREAD_SAFE
2024 if (errno == EBADF) {
2025 coap_log_debug("select: %s\n", coap_socket_strerror());
2026 goto all_over;
2027 }
2028#endif /* COAP_THREAD_SAFE */
2029 coap_log_err("select: %s\n", coap_socket_strerror());
2030 return -1;
2031 }
2032 goto all_over;
2033 }
2034#if COAP_THREAD_SAFE
2035 /* Need to refresh what is available to read / write etc. */
2036 nfds = coap_io_prepare_fds(ctx, enfds, ereadfds, ewritefds, eexceptfds);
2037 tv.tv_usec = 0;
2038 tv.tv_sec = 0;
2039 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds, &tv);
2040 if (result < 0) { /* error */
2041#ifdef _WIN32
2042 coap_win_error_to_errno();
2043#endif
2044 if (errno != EINTR) {
2045 if (errno == EBADF) {
2046 coap_log_debug("select: %s\n", coap_socket_strerror());
2047 goto all_over;
2048 }
2049 coap_log_err("select: %s\n", coap_socket_strerror());
2050 return -1;
2051 }
2052 goto all_over;
2053 }
2054#endif /* COAP_THREAD_SAFE */
2055 if (ereadfds) {
2056 *ereadfds = ctx->readfds;
2057 }
2058 if (ewritefds) {
2059 *ewritefds = ctx->writefds;
2060 }
2061 if (eexceptfds) {
2062 *eexceptfds = ctx->exceptfds;
2063 }
2064
2065 if (result > 0) {
2066 for (i = 0; i < ctx->num_sockets; i++) {
2067 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ) &&
2068 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
2070#if !COAP_DISABLE_TCP
2071 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) &&
2072 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
2074 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE) &&
2075 FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds))
2077 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) &&
2078 (FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds) ||
2079 FD_ISSET(ctx->sockets[i]->fd, &ctx->exceptfds)))
2081#endif /* !COAP_DISABLE_TCP */
2082 }
2083 }
2084
2085 coap_ticks(&now);
2086 coap_io_do_io_lkd(ctx, now);
2087 coap_ticks(&now);
2088 timeout = coap_io_prepare_io_lkd(ctx, ctx->sockets,
2089 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
2090 &ctx->num_sockets, now);
2091 ctx->next_timeout = timeout ? timeout + now : 0;
2092
2093#else /* COAP_EPOLL_SUPPORT */
2094 (void)ereadfds;
2095 (void)ewritefds;
2096 (void)eexceptfds;
2097 (void)enfds;
2098
2099 timeout = coap_io_prepare_epoll_lkd(ctx, before);
2100
2101 do {
2102 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
2103 int etimeout;
2104
2105 /* Potentially adjust based on what the caller wants */
2106 if (timeout_ms == COAP_IO_NO_WAIT) {
2107 /* Need to return immediately from epoll_wait() */
2108 etimeout = 0;
2109 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
2110 /*
2111 * Nothing found in coap_io_prepare_epoll_lkd() and COAP_IO_WAIT set,
2112 * so wait forever in epoll_wait().
2113 */
2114 etimeout = -1;
2115 } else {
2116 etimeout = timeout;
2117 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
2118 etimeout = timeout_ms;
2119 if (etimeout < 0) {
2120 /*
2121 * If timeout > INT_MAX, epoll_wait() cannot wait longer than this as
2122 * it has int timeout parameter
2123 */
2124 etimeout = INT_MAX;
2125 }
2126 }
2127
2128 /* Unlock so that other threads can lock/update ctx */
2130
2131 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
2132 if (nfds < 0) {
2133 if (errno != EINTR) {
2134 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
2135 coap_socket_strerror(), nfds);
2136 }
2137 coap_lock_lock(return -1);
2138 break;
2139 }
2140
2141 coap_lock_lock(return -1);
2142#if COAP_THREAD_SAFE
2143 /* Need to refresh what is available to read / write etc. */
2144 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, 0);
2145 if (nfds < 0) {
2146 if (errno != EINTR) {
2147 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
2148 coap_socket_strerror(), nfds);
2149 }
2150 break;
2151 }
2152#endif /* COAP_THREAD_SAFE */
2153
2154 coap_io_do_epoll_lkd(ctx, events, nfds);
2155
2156 /*
2157 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
2158 * incase we have to do another iteration
2159 * (COAP_MAX_EPOLL_EVENTS insufficient)
2160 */
2161 timeout_ms = COAP_IO_NO_WAIT;
2162
2163 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
2164 } while (nfds == COAP_MAX_EPOLL_EVENTS);
2165
2166#endif /* COAP_EPOLL_SUPPORT */
2167#if COAP_SERVER_SUPPORT
2169#endif /* COAP_SERVER_SUPPORT */
2170#if COAP_ASYNC_SUPPORT
2171 /* Check to see if we need to send off any Async requests as delay might
2172 have been updated */
2173 coap_ticks(&now);
2174 coap_check_async(ctx, now, NULL);
2175#endif /* COAP_ASYNC_SUPPORT */
2176
2177#ifndef COAP_EPOLL_SUPPORT
2178all_over:
2179#endif /* COAP_EPOLL_SUPPORT */
2180 coap_ticks(&now);
2181 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
2182}
2183
2184volatile int coap_thread_quit = 0;
2185
2186void
2191
2192COAP_API int
2194 coap_io_process_thread_t main_loop_code,
2195 void *main_loop_code_arg, uint32_t timeout_ms,
2196 uint32_t thread_count) {
2197 int ret;
2198
2199 if (!context)
2200 return 0;
2201 coap_lock_lock(return 0);
2202 ret = coap_io_process_loop_lkd(context, main_loop_code,
2203 main_loop_code_arg, timeout_ms,
2204 thread_count);
2206 return ret;
2207}
2208
2209int
2211 coap_io_process_thread_t main_loop_code,
2212 void *main_loop_code_arg, uint32_t timeout_ms,
2213 uint32_t thread_count) {
2214 int ret = 0;;
2215
2216#if COAP_THREAD_SAFE
2217 if (thread_count > 1) {
2218 if (!coap_io_process_configure_threads(context, thread_count - 1))
2219 return 0;
2220 }
2221#else /* COAP_THREAD_SAFE */
2222 thread_count = 1;
2223#endif /* COAP_THREAD_SAFE */
2224 while (!coap_thread_quit) {
2225 if (main_loop_code) {
2226 coap_tick_t begin, end;
2227 uint32_t used_ms;
2228
2229 coap_ticks(&begin);
2230 /*
2231 * main_loop_codecode should not be blocking for any time, and not calling
2232 * coap_io_process().
2233 */
2234 coap_lock_callback_release(main_loop_code(main_loop_code_arg),
2235 /* On re-lock failure */
2236 ret = 0; break);
2237 /*
2238 * Need to delay for the remainder of timeout_ms. In case main_loop_code()
2239 * is time sensitive (e.g Observe subscription to /time), delay to the
2240 * start of the a second boundary
2241 */
2242 coap_ticks(&end);
2243 used_ms = (uint32_t)(end - begin) * 1000 / COAP_TICKS_PER_SECOND;
2244 if (timeout_ms == COAP_IO_NO_WAIT || timeout_ms == COAP_IO_WAIT) {
2245 ret = coap_io_process_lkd(context, timeout_ms);
2246 } else if (timeout_ms > used_ms) {
2247 /* Wait for remaining time rounded up to next second start */
2248 coap_tick_t next_time = end + (timeout_ms - used_ms) * COAP_TICKS_PER_SECOND / 1000;
2249 unsigned int next_sec_us;
2250 unsigned int next_sec_ms;
2251
2252 next_sec_us = (timeout_ms - used_ms) * 1000000 / COAP_TICKS_PER_SECOND + 1000000 -
2253 (coap_ticks_to_rt_us(next_time) % 1000000);
2254 next_sec_ms = (next_sec_us + 999) / 1000;
2255 if (next_sec_ms > timeout_ms && next_sec_ms > 1000)
2256 next_sec_ms -= 1000;
2257 ret = coap_io_process_lkd(context, next_sec_ms ? next_sec_ms : 1);
2258 } else {
2259 /* timeout_ms has expired */
2260 ret = coap_io_process_lkd(context, COAP_IO_NO_WAIT);
2261 }
2262
2263 if (thread_count == 1) {
2264 /*
2265 * Need to delay if only one thread until the remainder of
2266 * timeout_ms is used up. Otherwise, another thread will be
2267 * waiting on coap_io_process() to do any input / timeout work.
2268 */
2269 coap_ticks(&end);
2270 used_ms = (uint32_t)(end - begin) * 1000 / COAP_TICKS_PER_SECOND;
2271 if (timeout_ms > 0 && timeout_ms < used_ms) {
2272 ret = coap_io_process_lkd(context, used_ms - timeout_ms);
2273 } else {
2274 ret = coap_io_process_lkd(context, COAP_IO_NO_WAIT);
2275 }
2276 }
2277 } else {
2278 ret = coap_io_process_lkd(context, timeout_ms);
2279 }
2280 /* coap_io_process_lkd() can return 0 */
2281 if (ret >= 0)
2282 ret = 1;
2283
2284 if (ret < 0) {
2285 ret = 0;
2286 break;
2287 }
2288 }
2289#if COAP_THREAD_SAFE
2291#endif /* COAP_THREAD_SAFE */
2292 coap_thread_quit = 0;
2293 return ret;
2294}
2295
2296#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION*/
2297
2298COAP_API int
2300 int ret;
2301
2302 coap_lock_lock(return 0);
2303 ret = coap_io_pending_lkd(context);
2305 return ret;
2306}
2307
2308/*
2309 * return 1 I/O pending
2310 * 0 No I/O pending
2311 */
2312int
2314 coap_session_t *s, *rtmp;
2315#if COAP_SERVER_SUPPORT
2316 coap_endpoint_t *ep;
2317#endif /* COAP_SERVER_SUPPORT */
2318
2319 if (!context)
2320 return 0;
2322 if (coap_io_process_lkd(context, COAP_IO_NO_WAIT) < 0)
2323 return 0;
2324
2325 if (context->sendqueue)
2326 return 1;
2327#if COAP_SERVER_SUPPORT
2328 LL_FOREACH(context->endpoint, ep) {
2329 SESSIONS_ITER(ep->sessions, s, rtmp) {
2330 if (s->delayqueue)
2331 return 1;
2332 if (s->lg_xmit)
2333 return 1;
2334 if (s->lg_srcv)
2335 return 1;
2336 }
2337 }
2338#endif /* COAP_SERVER_SUPPORT */
2339#if COAP_CLIENT_SUPPORT
2340 SESSIONS_ITER(context->sessions, s, rtmp) {
2341 if (s->delayqueue)
2342 return 1;
2343 if (s->lg_xmit)
2344 return 1;
2345 if (s->lg_crcv)
2346 return 1;
2347 }
2348#endif /* COAP_CLIENT_SUPPORT */
2349 return 0;
2350}
2351
2352const char *
2354 return strerror(error);
2355}
2356#ifdef _WIN32
2357const char *
2359 coap_win_error_to_errno();
2360 return coap_socket_format_errno(errno);
2361}
2362#else /* _WIN32 */
2363const char *
2365 return coap_socket_format_errno(errno);
2366}
2367#endif /* _WIN32 */
2368
2371#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
2372 return sock->fd;
2373#else
2374 (void)(sock);
2375 return COAP_INVALID_SOCKET;
2376#endif
2377}
2378
2381 return sock->flags;
2382}
2383
2384COAP_API void
2386 sock->flags = flags;
2387}
2388
2389#undef SIN6
void coap_address_set_port(coap_address_t *addr, uint16_t port)
Set the port field of addr to port (in host byte order).
int coap_is_bcast(const coap_address_t *a)
Checks if given address a denotes a broadcast address.
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
uint16_t coap_address_get_port(const coap_address_t *addr)
Returns the port from addr in host byte order.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
#define COAP_IPV4_SUPPORT
const char * coap_socket_format_errno(int error)
Definition coap_io.c:2353
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
Function interface for data stream receiving off a socket.
Definition coap_io.c:713
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:1713
void coap_socket_close(coap_socket_t *sock)
Function interface to close off a socket.
Definition coap_io.c:395
const char * coap_socket_strerror(void)
Definition coap_io.c:2364
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition coap_io.c:1070
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for data transmission.
Definition coap_io.c:869
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:1057
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Function interface for data stream sending off a socket.
Definition coap_io.c:654
volatile int coap_thread_quit
Definition coap_io.c:2184
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:533
#define MSG_NOSIGNAL
#define iov_len_t
Definition coap_io.c:816
#define COAP_SOL_IP
Definition coap_io.c:778
#define coap_closesocket
Definition coap_io.h:48
#define COAP_MAX_EPOLL_EVENTS
Definition coap_io.h:38
uint16_t coap_socket_flags_t
Definition coap_io.h:53
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:29
#define COAP_SOCKET_ERROR
Definition coap_io.h:49
int coap_fd_t
Definition coap_io.h:47
#define COAP_INVALID_SOCKET
Definition coap_io.h:50
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
void coap_epoll_ctl_add(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to add the state of events that epoll is to track for the appropriate file de...
int coap_socket_connect_udp(coap_socket_t *sock, const coap_address_t *local_if, const coap_address_t *server, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr)
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
#define COAP_SOCKET_NOT_EMPTY
the socket is not empty
#define COAP_SOCKET_CAN_WRITE
non blocking socket can now write without blocking
#define COAP_SOCKET_BOUND
the socket is bound
#define COAP_SOCKET_SLAVE
socket is a slave socket - do not close
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
#define COAP_SOCKET_CAN_ACCEPT
non blocking server socket can now accept without blocking
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
#define COAP_SOCKET_WANT_WRITE
non blocking socket is waiting for writing
#define COAP_SOCKET_CAN_CONNECT
non blocking client socket can now connect without blocking
coap_endpoint_t * coap_malloc_endpoint(void)
void coap_epoll_ctl_mod(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to modify the state of events that epoll is tracking on the appropriate file ...
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
void coap_mfree_endpoint(coap_endpoint_t *ep)
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
#define COAP_SOCKET_CONNECTED
the socket is connected
#define COAP_SOCKET_EMPTY
coap_socket_flags_t values
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ COAP_ENDPOINT
Definition coap_mem.h:45
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:229
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:224
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:238
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
void coap_io_do_epoll_lkd(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition coap_net.c:2776
int coap_io_process_loop_lkd(coap_context_t *context, coap_io_process_thread_t main_loop_code, void *main_loop_code_arg, uint32_t timeout_ms, uint32_t thread_count)
Do the coap_io_process() across thread_count threads.
Definition coap_io.c:2210
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:2313
void coap_io_do_io_lkd(coap_context_t *ctx, coap_tick_t now)
Processes any outstanding read, write, accept or connect I/O as indicated in the coap_socket_t struct...
Definition coap_net.c:2711
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:1729
int coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1842
int coap_io_process_with_fds_lkd(coap_context_t *ctx, uint32_t timeout_ms, int enfds, fd_set *ereadfds, fd_set *ewritefds, fd_set *eexceptfds)
The main message processing loop with additional fds for internal select.
Definition coap_io.c:1935
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:1370
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:1301
COAP_API int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1832
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:2299
int coap_io_process_configure_threads(coap_context_t *context, uint32_t thread_count)
Configure a defined number of threads to do the alternate coap_io_process() work with traffic load ba...
void coap_io_process_terminate_loop(void)
Terminate all the additional threads created by coap_io_process_loop() and break out of the main thre...
Definition coap_io.c:2187
void coap_io_process_remove_threads(coap_context_t *context)
Release the coap_io_process() worker threads.
COAP_API int coap_io_process_loop(coap_context_t *context, coap_io_process_thread_t main_loop_code, void *main_loop_code_arg, uint32_t timeout_ms, uint32_t thread_count)
Do the coap_io_process() across thread_count threads.
Definition coap_io.c:2193
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:1694
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:1352
#define COAP_IO_NO_WAIT
Definition coap_net.h:761
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:2385
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:1291
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:2370
COAP_API int coap_io_process_with_fds(coap_context_t *ctx, uint32_t timeout_ms, int enfds, fd_set *ereadfds, fd_set *ewritefds, fd_set *eexceptfds)
The main message processing loop with additional fds for internal select.
Definition coap_io.c:1847
#define COAP_IO_WAIT
Definition coap_net.h:760
void(* coap_io_process_thread_t)(void *arg)
Main thread coap_io_process_loop activity.
Definition coap_net.h:942
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:2380
int coap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
int coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
int coap_block_check_lg_xmit_timeouts(coap_session_t *session, coap_tick_t now, coap_tick_t *tim_rem)
void coap_expire_cache_entries(coap_context_t *context)
Expire coap_cache_entry_t entries.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:143
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition coap_time.h:158
#define COAP_MAX_DELAY_TICKS
Definition coap_time.h:221
uint64_t coap_ticks_to_rt_us(coap_tick_t t)
Helper function that converts coap ticks to POSIX wallclock time in us.
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:4911
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition coap_net.c:273
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:281
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition coap_net.c:2252
void coap_send_recv_terminate(void)
Terminate any active coap_send_recv() sessions.
Definition coap_net.c:2108
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition coap_notls.c:219
@ 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:94
@ COAP_EVENT_KEEPALIVE_FAILURE
Triggered when no response to a keep alive (ping) packet.
Definition coap_event.h:138
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_callback_release(func, failed)
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:120
#define coap_log_alert(...)
Definition coap_debug.h:84
#define coap_log_emerg(...)
Definition coap_debug.h:81
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_info(...)
Definition coap_debug.h:108
#define coap_log_warn(...)
Definition coap_debug.h:102
#define coap_log_err(...)
Definition coap_debug.h:96
#define coap_log_crit(...)
Definition coap_debug.h:90
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition coap_pdu.h:264
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:267
@ COAP_PROTO_DTLS
Definition coap_pdu.h:316
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_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.
#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
void coap_check_notify_lkd(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
coap_address_t remote
remote address and port
Definition coap_io.h:56
coap_address_t local
local address and port
Definition coap_io.h:57
Multi-purpose address abstraction.
socklen_t size
size of addr
struct sockaddr_in sin
struct coap_sockaddr_un cun
struct sockaddr_in6 sin6
struct sockaddr sa
union coap_address_t::@0 addr
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.
coap_socket_t * sockets[64]
Track different socket information in coap_io_process_with_fds_lkd()
unsigned int reconnect_time
Time to wait before reconnecting a failed client session.
unsigned int num_sockets
Number of sockets being tracked.
coap_session_t * sessions
client sessions
fd_set exceptfds
Used for select call in coap_io_process_with_fds_lkd()
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
coap_queue_t * sendqueue
uint8_t testing_cids
Change client's source port every testing_cids.
coap_endpoint_t * endpoint
the endpoints used for listening
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.
Abstraction of virtual endpoint that can be attached to coap_context_t.
coap_context_t * context
endpoint's context
coap_session_t * sessions
hash table or list of active sessions
coap_address_t bind_addr
local interface address
coap_socket_t sock
socket object for the interface, if any
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
int ifindex
the interface index
Queue entry.
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
unsigned ref_subscriptions
reference count of current subscriptions
coap_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationship with peer
unsigned ref_proxy_subs
reference count of current proxy subscriptions
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
uint8_t negotiated_cid
Set for a client if CID negotiated.
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_lg_srcv_t * lg_srcv
Server list of expected large receives.
coap_lg_crcv_t * lg_crcv
Client list of expected large receives.
coap_session_type_t type
client or server side socket
coap_context_t * context
session's context
uint8_t session_failed
Set if session failed and can try re-connect.
int ifindex
interface index
char sun_path[COAP_UNIX_PATH_MAX]
coap_session_t * session
Used to determine session owner.
coap_endpoint_t * endpoint
Used by the epoll logic for a listening endpoint.
coap_address_t mcast_addr
remote address and port (multicast track)
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values
struct in6_addr ipi6_addr
Definition coap_io.c:758
unsigned int ipi6_ifindex
Definition coap_io.c:759
struct in_addr ipi_spec_dst
Definition coap_io.c:764
struct in_addr ipi_addr
Definition coap_io.c:765
int ipi_ifindex
Definition coap_io.c:763