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