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