libcoap 4.3.4-develop-214665a
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-2024 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
16#include "coap3/coap_internal.h"
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 COAP_EPOLL_SUPPORT
50#include <sys/epoll.h>
51#include <sys/timerfd.h>
52#ifdef HAVE_LIMITS_H
53#include <limits.h>
54#endif
55#endif /* COAP_EPOLL_SUPPORT */
56
57#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION) && !defined(WITH_LWIP)
58/* define generic PKTINFO for IPv4 */
59#if defined(IP_PKTINFO)
60# define GEN_IP_PKTINFO IP_PKTINFO
61#elif defined(IP_RECVDSTADDR)
62# define GEN_IP_PKTINFO IP_RECVDSTADDR
63#else
64# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
65#endif /* IP_PKTINFO */
66
67/* define generic PKTINFO for IPv6 */
68#ifdef IPV6_RECVPKTINFO
69# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
70#elif defined(IPV6_PKTINFO)
71# define GEN_IPV6_PKTINFO IPV6_PKTINFO
72#else
73# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
74#endif /* IPV6_RECVPKTINFO */
75#endif /* ! WITH_CONTIKI && ! RIOT_VERSION && ! WITH_LWIP */
76
77#if COAP_SERVER_SUPPORT
81}
82
83void
86}
87#endif /* COAP_SERVER_SUPPORT */
88
89#if !defined(WITH_CONTIKI) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
90
91#if COAP_SERVER_SUPPORT
92int
94 const coap_address_t *listen_addr,
95 coap_address_t *bound_addr) {
96#ifndef RIOT_VERSION
97 int on = 1;
98#if COAP_IPV6_SUPPORT
99 int off = 0;
100#endif /* COAP_IPV6_SUPPORT */
101#else /* ! RIOT_VERSION */
102 struct timeval timeout = {0, 0};
103#endif /* ! RIOT_VERSION */
104#ifdef _WIN32
105 u_long u_on = 1;
106#endif
107
108 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
109
110 if (sock->fd == COAP_INVALID_SOCKET) {
111 coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
112 goto error;
113 }
114#ifndef RIOT_VERSION
115#ifdef _WIN32
116 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
117#else
118 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
119#endif
120 {
121 coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
122 }
123
124 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
125 coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
127
128 switch (listen_addr->addr.sa.sa_family) {
129#if COAP_IPV4_SUPPORT
130 case AF_INET:
131 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
132 sizeof(on)) == COAP_SOCKET_ERROR)
133 coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
135 break;
136#endif /* COAP_IPV4_SUPPORT */
137#if COAP_IPV6_SUPPORT
138 case AF_INET6:
139 /* Configure the socket as dual-stacked */
140 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
141 sizeof(off)) == COAP_SOCKET_ERROR)
142 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
144#if !defined(ESPIDF_VERSION)
145 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
146 sizeof(on)) == COAP_SOCKET_ERROR)
147 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
149#endif /* !defined(ESPIDF_VERSION) */
150#endif /* COAP_IPV6_SUPPORT */
151 setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
152 /* ignore error, because likely cause is that IPv4 is disabled at the os
153 level */
154 break;
155#if COAP_AF_UNIX_SUPPORT
156 case AF_UNIX:
157 break;
158#endif /* COAP_AF_UNIX_SUPPORT */
159 default:
160 coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
161 break;
162 }
163#else /* RIOT_VERSION */
164 if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, OPTVAL_T(&timeout),
165 (socklen_t)sizeof(timeout)) == COAP_SOCKET_ERROR)
166 coap_log_alert("coap_socket_bind_udp: setsockopt SO_RCVTIMEO: %s\n",
168#endif /* RIOT_VERSION */
169
170 if (bind(sock->fd, &listen_addr->addr.sa,
172 listen_addr->addr.sa.sa_family == AF_INET ?
173 (socklen_t)sizeof(struct sockaddr_in) :
174#endif /* COAP_IPV4_SUPPORT */
175 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
176 coap_log_warn("coap_socket_bind_udp: bind: %s\n",
178 goto error;
179 }
180
181 bound_addr->size = (socklen_t)sizeof(*bound_addr);
182 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
183 coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
185 goto error;
186 }
187#if defined(RIOT_VERSION) && defined(COAP_SERVER_SUPPORT)
188 if (sock->endpoint &&
189 bound_addr->addr.sa.sa_family == AF_INET6) {
190 bound_addr->addr.sin6.sin6_scope_id =
191 listen_addr->addr.sin6.sin6_scope_id;
192 bound_addr->addr.sin6.sin6_flowinfo = 0;
193 }
194#endif /* RIOT_VERSION && COAP_SERVER_SUPPORT */
195
196 return 1;
197
198error:
199 coap_socket_close(sock);
200 return 0;
201}
202#endif /* COAP_SERVER_SUPPORT */
203
204#if COAP_CLIENT_SUPPORT
205int
207 const coap_address_t *local_if,
208 const coap_address_t *server,
209 int default_port,
210 coap_address_t *local_addr,
211 coap_address_t *remote_addr) {
212 int on = 1;
213#if COAP_IPV6_SUPPORT
214 int off = 0;
215#endif /* COAP_IPV6_SUPPORT */
216#ifdef _WIN32
217 u_long u_on = 1;
218#endif
219 coap_address_t connect_addr;
220 int is_mcast = coap_is_mcast(server);
221 coap_address_copy(&connect_addr, server);
222
224 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
225
226 if (sock->fd == COAP_INVALID_SOCKET) {
227 coap_log_warn("coap_socket_connect_udp: socket: %s\n",
229 goto error;
230 }
231
232#ifdef _WIN32
233 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
234#else
235 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
236#endif
237 {
238 coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s\n",
240 }
241
242 switch (connect_addr.addr.sa.sa_family) {
243#if COAP_IPV4_SUPPORT
244 case AF_INET:
245 if (connect_addr.addr.sin.sin_port == 0)
246 connect_addr.addr.sin.sin_port = htons(default_port);
247 break;
248#endif /* COAP_IPV4_SUPPORT */
249#if COAP_IPV6_SUPPORT
250 case AF_INET6:
251 if (connect_addr.addr.sin6.sin6_port == 0)
252 connect_addr.addr.sin6.sin6_port = htons(default_port);
253 /* Configure the socket as dual-stacked */
254 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
255 sizeof(off)) == COAP_SOCKET_ERROR)
256 coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
258#endif /* COAP_IPV6_SUPPORT */
259 break;
260#if COAP_AF_UNIX_SUPPORT
261 case AF_UNIX:
262 break;
263#endif /* COAP_AF_UNIX_SUPPORT */
264 default:
265 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
266 connect_addr.addr.sa.sa_family);
267 goto error;;
268 }
269
270 if (local_if && local_if->addr.sa.sa_family) {
271 if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
272 coap_log_warn("coap_socket_connect_udp: local address family != "
273 "remote address family\n");
274 goto error;
275 }
276 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
277 coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
279 if (bind(sock->fd, &local_if->addr.sa,
281 local_if->addr.sa.sa_family == AF_INET ?
282 (socklen_t)sizeof(struct sockaddr_in) :
283#endif /* COAP_IPV4_SUPPORT */
284 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
285 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
287 goto error;
288 }
289#if COAP_AF_UNIX_SUPPORT
290 } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
291 /* Need to bind to a local address for clarity over endpoints */
292 coap_log_warn("coap_socket_connect_udp: local address required\n");
293 goto error;
294#endif /* COAP_AF_UNIX_SUPPORT */
295 }
296
297 /* special treatment for sockets that are used for multicast communication */
298 if (is_mcast) {
299 if (!(local_if && local_if->addr.sa.sa_family)) {
300 /* Bind to a (unused) port to simplify logging */
301 coap_address_t bind_addr;
302
303 coap_address_init(&bind_addr);
304 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
305 if (bind(sock->fd, &bind_addr.addr.sa,
307 bind_addr.addr.sa.sa_family == AF_INET ?
308 (socklen_t)sizeof(struct sockaddr_in) :
309#endif /* COAP_IPV4_SUPPORT */
310 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
311 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
313 goto error;
314 }
315 }
316 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
317 coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
319 }
320 coap_address_copy(remote_addr, &connect_addr);
321 coap_address_copy(&sock->mcast_addr, &connect_addr);
323 if (coap_is_bcast(server) &&
324 setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
325 sizeof(on)) == COAP_SOCKET_ERROR)
326 coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
328 return 1;
329 }
330
331 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
332#if COAP_AF_UNIX_SUPPORT
333 if (connect_addr.addr.sa.sa_family == AF_UNIX) {
334 coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
335 connect_addr.addr.cun.sun_path, coap_socket_strerror());
336 } else
337#endif /* COAP_AF_UNIX_SUPPORT */
338 {
339 coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
340 coap_socket_strerror(), connect_addr.addr.sa.sa_family);
341 }
342 goto error;
343 }
344
345 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
346 coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
348 }
349
350 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
351 coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
353 }
354
356 return 1;
357
358error:
359 coap_socket_close(sock);
360 return 0;
361}
362#endif /* COAP_CLIENT_SUPPORT */
363
364void
366 if (sock->fd != COAP_INVALID_SOCKET) {
367#ifdef COAP_EPOLL_SUPPORT
368#if COAP_SERVER_SUPPORT
369 coap_context_t *context = sock->session ? sock->session->context :
370 sock->endpoint ? sock->endpoint->context : NULL;
371#else /* COAP_SERVER_SUPPORT */
372 coap_context_t *context = sock->session ? sock->session->context : NULL;
373#endif /* COAP_SERVER_SUPPORT */
374 if (context != NULL) {
375 int ret;
376 struct epoll_event event;
377
378 /* Kernels prior to 2.6.9 expect non NULL event parameter */
379 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
380 if (ret == -1 && errno != ENOENT) {
381 coap_log_err("%s: epoll_ctl DEL failed: %s (%d)\n",
382 "coap_socket_close",
383 coap_socket_strerror(), errno);
384 }
385 }
386#if COAP_SERVER_SUPPORT
387#if COAP_AF_UNIX_SUPPORT
388 if (sock->endpoint &&
389 sock->endpoint->bind_addr.addr.sa.sa_family == AF_UNIX) {
390 /* Clean up Unix endpoint */
391 unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
392 }
393#endif /* COAP_AF_UNIX_SUPPORT */
394 sock->endpoint = NULL;
395#endif /* COAP_SERVER_SUPPORT */
396#if COAP_CLIENT_SUPPORT
397#if COAP_AF_UNIX_SUPPORT
398 if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
399 sock->session->addr_info.local.addr.sa.sa_family == AF_UNIX) {
400 /* Clean up Unix endpoint */
401 unlink(sock->session->addr_info.local.addr.cun.sun_path);
402 }
403#endif /* COAP_AF_UNIX_SUPPORT */
404#endif /* COAP_CLIENT_SUPPORT */
405 sock->session = NULL;
406#endif /* COAP_EPOLL_SUPPORT */
407 coap_closesocket(sock->fd);
408 sock->fd = COAP_INVALID_SOCKET;
409 }
410 sock->flags = COAP_SOCKET_EMPTY;
411}
412
413#ifdef COAP_EPOLL_SUPPORT
414void
416 uint32_t events,
417 const char *func) {
418 int ret;
419 struct epoll_event event;
420 coap_context_t *context;
421
422#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
423 (void)func;
424#endif
425
426 if (sock == NULL)
427 return;
428
429#if COAP_SERVER_SUPPORT
430 context = sock->session ? sock->session->context :
431 sock->endpoint ? sock->endpoint->context : NULL;
432#else /* ! COAP_SERVER_SUPPORT */
433 context = sock->session ? sock->session->context : NULL;
434#endif /* ! COAP_SERVER_SUPPORT */
435 if (context == NULL)
436 return;
437
438 /* Needed if running 32bit as ptr is only 32bit */
439 memset(&event, 0, sizeof(event));
440 event.events = events;
441 event.data.ptr = sock;
442
443 ret = epoll_ctl(context->epfd, EPOLL_CTL_ADD, sock->fd, &event);
444 if (ret == -1) {
445 coap_log_err("%s: epoll_ctl ADD failed: %s (%d)\n",
446 func,
447 coap_socket_strerror(), errno);
448 }
449}
450
451void
453 uint32_t events,
454 const char *func) {
455 int ret;
456 struct epoll_event event;
457 coap_context_t *context;
458
459#if COAP_MAX_LOGGING_LEVEL < _COAP_LOG_ERR
460 (void)func;
461#endif
462
463 if (sock == NULL)
464 return;
465
466#if COAP_SERVER_SUPPORT
467 context = sock->session ? sock->session->context :
468 sock->endpoint ? sock->endpoint->context : NULL;
469#else /* COAP_SERVER_SUPPORT */
470 context = sock->session ? sock->session->context : NULL;
471#endif /* COAP_SERVER_SUPPORT */
472 if (context == NULL)
473 return;
474
475 event.events = events;
476 event.data.ptr = sock;
477
478 ret = epoll_ctl(context->epfd, EPOLL_CTL_MOD, sock->fd, &event);
479 if (ret == -1) {
480#if (COAP_MAX_LOGGING_LEVEL < COAP_LOG_ERR)
481 (void)func;
482#endif
483 coap_log_err("%s: epoll_ctl MOD failed: %s (%d)\n",
484 func,
485 coap_socket_strerror(), errno);
486 }
487}
488#endif /* COAP_EPOLL_SUPPORT */
489
490#endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! RIOT_VERSION*/
491
492#ifndef WITH_CONTIKI
493void
495#if COAP_EPOLL_SUPPORT
496 if (context->eptimerfd != -1) {
497 coap_tick_t now;
498
499 coap_ticks(&now);
500 if (context->next_timeout == 0 || context->next_timeout > now + delay) {
501 struct itimerspec new_value;
502 int ret;
503
504 context->next_timeout = now + delay;
505 memset(&new_value, 0, sizeof(new_value));
506 if (delay == 0) {
507 new_value.it_value.tv_nsec = 1; /* small but not zero */
508 } else {
509 new_value.it_value.tv_sec = delay / COAP_TICKS_PER_SECOND;
510 new_value.it_value.tv_nsec = (delay % COAP_TICKS_PER_SECOND) *
511 1000000;
512 }
513 ret = timerfd_settime(context->eptimerfd, 0, &new_value, NULL);
514 if (ret == -1) {
515 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
516 "coap_resource_notify_observers",
517 coap_socket_strerror(), errno);
518 }
519#ifdef COAP_DEBUG_WAKEUP_TIMES
520 else {
521 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
522 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
523 }
524#endif /* COAP_DEBUG_WAKEUP_TIMES */
525 }
526 }
527#else /* COAP_EPOLL_SUPPORT */
528 (void)context;
529 (void)delay;
530#endif /* COAP_EPOLL_SUPPORT */
531}
532#endif /* ! WITH_CONTIKI */
533
534#if !defined(WITH_CONTIKI) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
535
536#ifdef _WIN32
537static void
538coap_win_error_to_errno(void) {
539 int w_error = WSAGetLastError();
540 switch (w_error) {
541 case WSA_NOT_ENOUGH_MEMORY:
542 errno = ENOMEM;
543 break;
544 case WSA_INVALID_PARAMETER:
545 errno = EINVAL;
546 break;
547 case WSAEINTR:
548 errno = EINTR;
549 break;
550 case WSAEBADF:
551 errno = EBADF;
552 break;
553 case WSAEACCES:
554 errno = EACCES;
555 break;
556 case WSAEFAULT:
557 errno = EFAULT;
558 break;
559 case WSAEINVAL:
560 errno = EINVAL;
561 break;
562 case WSAEMFILE:
563 errno = EMFILE;
564 break;
565 case WSAEWOULDBLOCK:
566 errno = EWOULDBLOCK;
567 break;
568 case WSAENETDOWN:
569 errno = ENETDOWN;
570 break;
571 case WSAENETUNREACH:
572 errno = ENETUNREACH;
573 break;
574 case WSAENETRESET:
575 errno = ENETRESET;
576 break;
577 case WSAECONNABORTED:
578 errno = ECONNABORTED;
579 break;
580 case WSAECONNRESET:
581 errno = ECONNRESET;
582 break;
583 case WSAENOBUFS:
584 errno = ENOBUFS;
585 break;
586 case WSAETIMEDOUT:
587 errno = ETIMEDOUT;
588 break;
589 case WSAECONNREFUSED:
590 errno = ECONNREFUSED;
591 break;
592 default:
593 coap_log_err("WSAGetLastError: %d mapping to errno failed - please fix\n",
594 w_error);
595 errno = EPERM;
596 break;
597 }
598}
599#endif /* _WIN32 */
600
601/*
602 * strm
603 * return +ve Number of bytes written.
604 * 0 No data written.
605 * -1 Error (error in errno).
606 */
607ssize_t
608coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
609 ssize_t r;
610
612#ifdef _WIN32
613 r = send(sock->fd, (const char *)data, (int)data_len, 0);
614#else
615#ifndef MSG_NOSIGNAL
616#define MSG_NOSIGNAL 0
617#endif /* MSG_NOSIGNAL */
618 r = send(sock->fd, data, data_len, MSG_NOSIGNAL);
619#endif
620 if (r == COAP_SOCKET_ERROR) {
621#ifdef _WIN32
622 coap_win_error_to_errno();
623#endif /* _WIN32 */
624 if (errno==EAGAIN ||
625#if EAGAIN != EWOULDBLOCK
626 errno == EWOULDBLOCK ||
627#endif
628 errno == EINTR) {
630#ifdef COAP_EPOLL_SUPPORT
632 EPOLLOUT |
633 ((sock->flags & COAP_SOCKET_WANT_READ) ?
634 EPOLLIN : 0),
635 __func__);
636#endif /* COAP_EPOLL_SUPPORT */
637 return 0;
638 }
639 if (errno == EPIPE || errno == ECONNRESET) {
640 coap_log_info("coap_socket_write: send: %s\n",
642 } else {
643 coap_log_warn("coap_socket_write: send: %s\n",
645 }
646 return -1;
647 }
648 if (r < (ssize_t)data_len) {
650#ifdef COAP_EPOLL_SUPPORT
652 EPOLLOUT |
653 ((sock->flags & COAP_SOCKET_WANT_READ) ?
654 EPOLLIN : 0),
655 __func__);
656#endif /* COAP_EPOLL_SUPPORT */
657 }
658 return r;
659}
660
661/*
662 * strm
663 * return >=0 Number of bytes read.
664 * -1 Error (error in errno).
665 */
666ssize_t
667coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
668 ssize_t r;
669
670#ifdef _WIN32
671 r = recv(sock->fd, (char *)data, (int)data_len, 0);
672#else
673 r = recv(sock->fd, data, data_len, 0);
674#endif
675 if (r == 0) {
676 /* graceful shutdown */
677 sock->flags &= ~COAP_SOCKET_CAN_READ;
678 errno = ECONNRESET;
679 return -1;
680 } else if (r == COAP_SOCKET_ERROR) {
681 sock->flags &= ~COAP_SOCKET_CAN_READ;
682#ifdef _WIN32
683 coap_win_error_to_errno();
684#endif /* _WIN32 */
685 if (errno==EAGAIN ||
686#if EAGAIN != EWOULDBLOCK
687 errno == EWOULDBLOCK ||
688#endif
689 errno == EINTR) {
690 return 0;
691 }
692 if (errno != ECONNRESET) {
693 coap_log_warn("coap_socket_read: recv: %s\n",
695 }
696 return -1;
697 }
698 if (r < (ssize_t)data_len)
699 sock->flags &= ~COAP_SOCKET_CAN_READ;
700 return r;
701}
702
703#endif /* ! WITH_CONTIKI && ! WITH_LWIP && ! RIOT_VERSION */
704
705#if !defined(WITH_LWIP)
706#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
707/* define struct in6_pktinfo and struct in_pktinfo if not available
708 FIXME: check with configure
709*/
710#if !defined(__MINGW32__) && !defined(RIOT_VERSION)
712 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
713 unsigned int ipi6_ifindex; /* send/recv interface index */
714};
715
718 struct in_addr ipi_spec_dst;
719 struct in_addr ipi_addr;
720};
721#endif /* ! __MINGW32__ */
722#endif
723#endif /* ! WITH_LWIP */
724
725#if !defined(WITH_CONTIKI) && !defined(SOL_IP)
726/* Solaris expects level IPPROTO_IP for ancillary data. */
727#define SOL_IP IPPROTO_IP
728#endif
729#ifdef _WIN32
730#define COAP_SOL_IP IPPROTO_IP
731#else /* ! _WIN32 */
732#define COAP_SOL_IP SOL_IP
733#endif /* ! _WIN32 */
734
735#if defined(_WIN32)
736#include <mswsock.h>
737#if !defined(__MINGW32__)
738static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
739#endif /* ! __MINGW32__ */
740/* Map struct WSABUF fields to their posix counterpart */
741#define msghdr _WSAMSG
742#define msg_name name
743#define msg_namelen namelen
744#define msg_iov lpBuffers
745#define msg_iovlen dwBufferCount
746#define msg_control Control.buf
747#define msg_controllen Control.len
748#define iovec _WSABUF
749#define iov_base buf
750#define iov_len len
751#define iov_len_t u_long
752#undef CMSG_DATA
753#define CMSG_DATA WSA_CMSG_DATA
754#define ipi_spec_dst ipi_addr
755#if !defined(__MINGW32__)
756#pragma warning( disable : 4116 )
757#endif /* ! __MINGW32__ */
758#else
759#define iov_len_t size_t
760#endif
761
762#if defined(_CYGWIN_ENV) || defined(__QNXNTO__)
763#define ipi_spec_dst ipi_addr
764#endif
765
766#if !defined(RIOT_VERSION) && !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
767/*
768 * dgram
769 * return +ve Number of bytes written.
770 * -1 Error error in errno).
771 */
772ssize_t
774 const uint8_t *data, size_t datalen) {
775 ssize_t bytes_written = 0;
776
777 if (!coap_debug_send_packet()) {
778 bytes_written = (ssize_t)datalen;
779 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
780#ifdef _WIN32
781 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
782#else
783 bytes_written = send(sock->fd, data, datalen, 0);
784#endif
785 } else {
786#if defined(_WIN32) && !defined(__MINGW32__)
787 DWORD dwNumberOfBytesSent = 0;
788 int r;
789#endif /* _WIN32 && !__MINGW32__ */
790#ifdef HAVE_STRUCT_CMSGHDR
791 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
792 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
793 struct msghdr mhdr;
794 struct iovec iov[1];
795 const void *addr = &session->addr_info.remote.addr;
796
797 assert(session);
798
799 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
800 iov[0].iov_len = (iov_len_t)datalen;
801
802 memset(buf, 0, sizeof(buf));
803
804 memset(&mhdr, 0, sizeof(struct msghdr));
805 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
806 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
807 (socklen_t)sizeof(struct sockaddr_in) :
808 session->addr_info.remote.size;
809
810 mhdr.msg_iov = iov;
811 mhdr.msg_iovlen = 1;
812
813 if (!coap_address_isany(&session->addr_info.local) &&
814 !coap_is_mcast(&session->addr_info.local)) {
815 switch (session->addr_info.local.addr.sa.sa_family) {
816#if COAP_IPV6_SUPPORT
817 case AF_INET6: {
818 struct cmsghdr *cmsg;
819
820#if COAP_IPV4_SUPPORT
821 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
822#if defined(IP_PKTINFO)
823 struct in_pktinfo *pktinfo;
824 mhdr.msg_control = buf;
825 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
826
827 cmsg = CMSG_FIRSTHDR(&mhdr);
828 cmsg->cmsg_level = COAP_SOL_IP;
829 cmsg->cmsg_type = IP_PKTINFO;
830 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
831
832 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
833
834 pktinfo->ipi_ifindex = session->ifindex;
835 memcpy(&pktinfo->ipi_spec_dst,
836 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
837 sizeof(pktinfo->ipi_spec_dst));
838#elif defined(IP_SENDSRCADDR)
839 mhdr.msg_control = buf;
840 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
841
842 cmsg = CMSG_FIRSTHDR(&mhdr);
843 cmsg->cmsg_level = IPPROTO_IP;
844 cmsg->cmsg_type = IP_SENDSRCADDR;
845 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
846
847 memcpy(CMSG_DATA(cmsg),
848 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
849 sizeof(struct in_addr));
850#endif /* IP_PKTINFO */
851 } else {
852#endif /* COAP_IPV4_SUPPORT */
853 struct in6_pktinfo *pktinfo;
854 mhdr.msg_control = buf;
855 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
856
857 cmsg = CMSG_FIRSTHDR(&mhdr);
858 cmsg->cmsg_level = IPPROTO_IPV6;
859 cmsg->cmsg_type = IPV6_PKTINFO;
860 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
861
862 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
863
864 pktinfo->ipi6_ifindex = session->ifindex;
865 memcpy(&pktinfo->ipi6_addr,
866 &session->addr_info.local.addr.sin6.sin6_addr,
867 sizeof(pktinfo->ipi6_addr));
868#if COAP_IPV4_SUPPORT
869 }
870#endif /* COAP_IPV4_SUPPORT */
871 break;
872 }
873#endif /* COAP_IPV6_SUPPORT */
874#if COAP_IPV4_SUPPORT
875 case AF_INET: {
876#if defined(IP_PKTINFO)
877 struct cmsghdr *cmsg;
878 struct in_pktinfo *pktinfo;
879
880 mhdr.msg_control = buf;
881 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
882
883 cmsg = CMSG_FIRSTHDR(&mhdr);
884 cmsg->cmsg_level = COAP_SOL_IP;
885 cmsg->cmsg_type = IP_PKTINFO;
886 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
887
888 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
889
890 pktinfo->ipi_ifindex = session->ifindex;
891 memcpy(&pktinfo->ipi_spec_dst,
892 &session->addr_info.local.addr.sin.sin_addr,
893 sizeof(pktinfo->ipi_spec_dst));
894#elif defined(IP_SENDSRCADDR)
895 struct cmsghdr *cmsg;
896 mhdr.msg_control = buf;
897 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
898
899 cmsg = CMSG_FIRSTHDR(&mhdr);
900 cmsg->cmsg_level = IPPROTO_IP;
901 cmsg->cmsg_type = IP_SENDSRCADDR;
902 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
903
904 memcpy(CMSG_DATA(cmsg),
905 &session->addr_info.local.addr.sin.sin_addr,
906 sizeof(struct in_addr));
907#endif /* IP_PKTINFO */
908 break;
909 }
910#endif /* COAP_IPV4_SUPPORT */
911#if COAP_AF_UNIX_SUPPORT
912 case AF_UNIX:
913 break;
914#endif /* COAP_AF_UNIX_SUPPORT */
915 default:
916 /* error */
917 coap_log_warn("protocol not supported\n");
918 return -1;
919 }
920 }
921#endif /* HAVE_STRUCT_CMSGHDR */
922
923#if defined(_WIN32) && !defined(__MINGW32__)
924 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
925 NULL /*lpCompletionRoutine*/);
926 if (r == 0)
927 bytes_written = (ssize_t)dwNumberOfBytesSent;
928 else {
929 bytes_written = -1;
930 coap_win_error_to_errno();
931 }
932#else /* !_WIN32 || __MINGW32__ */
933#ifdef HAVE_STRUCT_CMSGHDR
934 bytes_written = sendmsg(sock->fd, &mhdr, 0);
935#else /* ! HAVE_STRUCT_CMSGHDR */
936 bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
937 &session->addr_info.remote.addr.sa,
938 session->addr_info.remote.size);
939#endif /* ! HAVE_STRUCT_CMSGHDR */
940#endif /* !_WIN32 || __MINGW32__ */
941 }
942
943 if (bytes_written < 0)
944 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
945
946 return bytes_written;
947}
948#endif /* ! RIOT_VERSION && ! WITH_LWIP && ! WITH_CONTIKI */
949
950#define SIN6(A) ((struct sockaddr_in6 *)(A))
951
952void
953coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
954 *address = packet->payload;
955 *length = packet->length;
956}
957
958#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
959/*
960 * dgram
961 * return +ve Number of bytes written.
962 * -1 Error error in errno).
963 * -2 ICMP error response
964 */
965ssize_t
967 ssize_t len = -1;
968
969 assert(sock);
970 assert(packet);
971
972 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
973 return -1;
974 } else {
975 /* clear has-data flag */
976 sock->flags &= ~COAP_SOCKET_CAN_READ;
977 }
978
979 if (sock->flags & COAP_SOCKET_CONNECTED) {
980#ifdef _WIN32
981 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
982#else
983 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
984#endif
985 if (len < 0) {
986#ifdef _WIN32
987 coap_win_error_to_errno();
988#endif /* _WIN32 */
989 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
990 /* client-side ICMP destination unreachable, ignore it */
991 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
992 sock->session ?
993 coap_session_str(sock->session) : "",
995 return -2;
996 }
997 if (errno != EAGAIN) {
998 coap_log_warn("** %s: coap_socket_recv: %s\n",
999 sock->session ?
1000 coap_session_str(sock->session) : "",
1002 }
1003 goto error;
1004 } else if (len > 0) {
1005 packet->length = (size_t)len;
1006 }
1007 } else {
1008#if defined(_WIN32) && !defined(__MINGW32__)
1009 DWORD dwNumberOfBytesRecvd = 0;
1010 int r;
1011#endif /* _WIN32 && !__MINGW32__ */
1012#ifdef HAVE_STRUCT_CMSGHDR
1013 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
1014 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1015 struct cmsghdr *cmsg;
1016 struct msghdr mhdr;
1017 struct iovec iov[1];
1018
1019 iov[0].iov_base = packet->payload;
1020 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
1021
1022 memset(&mhdr, 0, sizeof(struct msghdr));
1023
1024 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
1025 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
1026
1027 mhdr.msg_iov = iov;
1028 mhdr.msg_iovlen = 1;
1029
1030 mhdr.msg_control = buf;
1031 mhdr.msg_controllen = sizeof(buf);
1032 /* set a big first length incase recvmsg() does not implement updating
1033 msg_control as well as preset the first cmsg with bad data */
1034 cmsg = (struct cmsghdr *)buf;
1035 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
1036 cmsg->cmsg_level = -1;
1037 cmsg->cmsg_type = -1;
1038
1039#if defined(_WIN32)
1040 if (!lpWSARecvMsg) {
1041 GUID wsaid = WSAID_WSARECVMSG;
1042 DWORD cbBytesReturned = 0;
1043 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
1044 sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
1045 coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
1046 return -1;
1047 }
1048 }
1049 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
1050 NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
1051 if (r == 0)
1052 len = (ssize_t)dwNumberOfBytesRecvd;
1053 else if (r == COAP_SOCKET_ERROR)
1054 coap_win_error_to_errno();
1055#else
1056 len = recvmsg(sock->fd, &mhdr, 0);
1057#endif
1058
1059#else /* ! HAVE_STRUCT_CMSGHDR */
1060 len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
1061 &packet->addr_info.remote.addr.sa,
1062 &packet->addr_info.remote.size);
1063#endif /* ! HAVE_STRUCT_CMSGHDR */
1064
1065 if (len < 0) {
1066#ifdef _WIN32
1067 coap_win_error_to_errno();
1068#endif /* _WIN32 */
1069 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1070 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
1071 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1072 sock->session ?
1073 coap_session_str(sock->session) : "",
1075 return 0;
1076 }
1077 if (errno != EAGAIN) {
1078 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
1079 }
1080 goto error;
1081 } else {
1082#ifdef HAVE_STRUCT_CMSGHDR
1083 int dst_found = 0;
1084
1085 packet->addr_info.remote.size = mhdr.msg_namelen;
1086 packet->length = (size_t)len;
1087
1088 /* Walk through ancillary data records until the local interface
1089 * is found where the data was received. */
1090 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
1091
1092#if COAP_IPV6_SUPPORT
1093 /* get the local interface for IPv6 */
1094 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
1095 union {
1096 uint8_t *c;
1097 struct in6_pktinfo *p;
1098 } u;
1099 u.c = CMSG_DATA(cmsg);
1100 packet->ifindex = (int)(u.p->ipi6_ifindex);
1101 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
1102 &u.p->ipi6_addr, sizeof(struct in6_addr));
1103 dst_found = 1;
1104 break;
1105 }
1106#endif /* COAP_IPV6_SUPPORT */
1107
1108#if COAP_IPV4_SUPPORT
1109 /* local interface for IPv4 */
1110#if defined(IP_PKTINFO)
1111 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
1112 union {
1113 uint8_t *c;
1114 struct in_pktinfo *p;
1115 } u;
1116 u.c = CMSG_DATA(cmsg);
1117 packet->ifindex = u.p->ipi_ifindex;
1118#if COAP_IPV6_SUPPORT
1119 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
1120 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
1121 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
1122 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
1123 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
1124 &u.p->ipi_addr, sizeof(struct in_addr));
1125 } else
1126#endif /* COAP_IPV6_SUPPORT */
1127 {
1128 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1129 &u.p->ipi_addr, sizeof(struct in_addr));
1130 }
1131 dst_found = 1;
1132 break;
1133 }
1134#endif /* IP_PKTINFO */
1135#if defined(IP_RECVDSTADDR)
1136 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
1137 packet->ifindex = (int)sock->fd;
1138 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1139 CMSG_DATA(cmsg), sizeof(struct in_addr));
1140 dst_found = 1;
1141 break;
1142 }
1143#endif /* IP_RECVDSTADDR */
1144#endif /* COAP_IPV4_SUPPORT */
1145 if (!dst_found) {
1146 /* cmsg_level / cmsg_type combination we do not understand
1147 (ignore preset case for bad recvmsg() not updating cmsg) */
1148 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1149 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1150 cmsg->cmsg_level, cmsg->cmsg_type);
1151 }
1152 }
1153 }
1154 if (!dst_found) {
1155 /* Not expected, but cmsg_level and cmsg_type don't match above and
1156 may need a new case */
1157 packet->ifindex = (int)sock->fd;
1158 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1159 &packet->addr_info.local.size) < 0) {
1160 coap_log_debug("Cannot determine local port\n");
1161 }
1162 }
1163#else /* ! HAVE_STRUCT_CMSGHDR */
1164 packet->length = (size_t)len;
1165 packet->ifindex = 0;
1166 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1167 &packet->addr_info.local.size) < 0) {
1168 coap_log_debug("Cannot determine local port\n");
1169 goto error;
1170 }
1171#endif /* ! HAVE_STRUCT_CMSGHDR */
1172 }
1173 }
1174
1175 if (len >= 0)
1176 return len;
1177error:
1178 return -1;
1179}
1180#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION */
1181
1182unsigned int
1184#ifndef COAP_EPOLL_SUPPORT
1185 (void)ctx;
1186 (void)now;
1187 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1188 return 0;
1189#else /* COAP_EPOLL_SUPPORT */
1190 coap_socket_t *sockets[1];
1191 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1192 unsigned int num_sockets;
1193 unsigned int timeout;
1194
1196 /* Use the common logic */
1197 timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
1198 /* Save when the next expected I/O is to take place */
1199 ctx->next_timeout = timeout ? now + timeout : 0;
1200 if (ctx->eptimerfd != -1) {
1201 struct itimerspec new_value;
1202 int ret;
1203
1204 memset(&new_value, 0, sizeof(new_value));
1205 coap_ticks(&now);
1206 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1207 coap_tick_t rem_timeout = ctx->next_timeout - now;
1208 /* Need to trigger an event on ctx->eptimerfd in the future */
1209 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1210 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1211 1000000;
1212 }
1213#ifdef COAP_DEBUG_WAKEUP_TIMES
1214 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
1215 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1216#endif /* COAP_DEBUG_WAKEUP_TIMES */
1217 /* reset, or specify a future time for eptimerfd to trigger */
1218 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1219 if (ret == -1) {
1220 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
1221 "coap_io_prepare_epoll",
1222 coap_socket_strerror(), errno);
1223 }
1224 }
1225 return timeout;
1226#endif /* COAP_EPOLL_SUPPORT */
1227}
1228
1229/*
1230 * return 0 No i/o pending
1231 * +ve millisecs to next i/o activity
1232 */
1233unsigned int
1235 coap_socket_t *sockets[],
1236 unsigned int max_sockets,
1237 unsigned int *num_sockets,
1238 coap_tick_t now) {
1239 coap_queue_t *nextpdu;
1240 coap_session_t *s, *rtmp;
1241 coap_tick_t timeout = 0;
1242 coap_tick_t s_timeout;
1243#if COAP_SERVER_SUPPORT
1244 int check_dtls_timeouts = 0;
1245#endif /* COAP_SERVER_SUPPORT */
1246#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION)
1247 (void)sockets;
1248 (void)max_sockets;
1249#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/
1250
1252 *num_sockets = 0;
1253
1254#if COAP_SERVER_SUPPORT
1255 /* Check to see if we need to send off any Observe requests */
1256 coap_check_notify(ctx);
1257
1258#if COAP_ASYNC_SUPPORT
1259 /* Check to see if we need to send off any Async requests */
1260 timeout = coap_check_async(ctx, now);
1261#endif /* COAP_ASYNC_SUPPORT */
1262#endif /* COAP_SERVER_SUPPORT */
1263
1264 /* Check to see if we need to send off any retransmit request */
1265 nextpdu = coap_peek_next(ctx);
1266 while (nextpdu && now >= ctx->sendqueue_basetime &&
1267 nextpdu->t <= now - ctx->sendqueue_basetime) {
1268 coap_retransmit(ctx, coap_pop_next(ctx));
1269 nextpdu = coap_peek_next(ctx);
1270 }
1271 if (nextpdu && (timeout == 0 ||
1272 nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1273 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1274
1275 /* Check for DTLS timeouts */
1276 if (ctx->dtls_context) {
1279 if (tls_timeout > 0) {
1280 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1281 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1282 coap_log_debug("** DTLS global timeout set to %dms\n",
1283 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1284 if (timeout == 0 || tls_timeout - now < timeout)
1285 timeout = tls_timeout - now;
1286 }
1287#if COAP_SERVER_SUPPORT
1288 } else {
1289 check_dtls_timeouts = 1;
1290#endif /* COAP_SERVER_SUPPORT */
1291 }
1292 }
1293#if COAP_SERVER_SUPPORT
1294 coap_endpoint_t *ep;
1295 coap_tick_t session_timeout;
1296
1297 if (ctx->session_timeout > 0)
1298 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1299 else
1301
1302 LL_FOREACH(ctx->endpoint, ep) {
1303#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1305 if (*num_sockets < max_sockets)
1306 sockets[(*num_sockets)++] = &ep->sock;
1307 }
1308#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1309 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1310 /* Check whether any idle server sessions should be released */
1311 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1312 s->delayqueue == NULL &&
1313 (s->last_rx_tx + session_timeout <= now ||
1317 } else {
1318 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1319 s->delayqueue == NULL) {
1320 s_timeout = (s->last_rx_tx + session_timeout) - now;
1321 if (timeout == 0 || s_timeout < timeout)
1322 timeout = s_timeout;
1323 }
1324 /* Make sure the session object is not deleted in any callbacks */
1326 /* Check any DTLS timeouts and expire if appropriate */
1327 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1328 s->proto == COAP_PROTO_DTLS && s->tls) {
1329 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1330 while (tls_timeout > 0 && tls_timeout <= now) {
1331 coap_log_debug("** %s: DTLS retransmit timeout\n",
1332 coap_session_str(s));
1334 goto release_1;
1335
1336 if (s->tls)
1337 tls_timeout = coap_dtls_get_timeout(s, now);
1338 else {
1339 tls_timeout = 0;
1340 timeout = 1;
1341 }
1342 }
1343 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1344 timeout = tls_timeout - now;
1345 }
1346 /* Check if any server large receives are missing blocks */
1347 if (s->lg_srcv) {
1348 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1349 if (timeout == 0 || s_timeout < timeout)
1350 timeout = s_timeout;
1351 }
1352 }
1353 /* Check if any server large sending have timed out */
1354 if (s->lg_xmit) {
1355 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1356 if (timeout == 0 || s_timeout < timeout)
1357 timeout = s_timeout;
1358 }
1359 }
1360#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1362 if (*num_sockets < max_sockets)
1363 sockets[(*num_sockets)++] = &s->sock;
1364 }
1365#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1366#if COAP_Q_BLOCK_SUPPORT
1367 /*
1368 * Check if any server large transmits have hit MAX_PAYLOAD and need
1369 * restarting
1370 */
1371 if (s->lg_xmit) {
1372 s_timeout = coap_block_check_q_block2_xmit(s, now);
1373 if (timeout == 0 || s_timeout < timeout)
1374 timeout = s_timeout;
1375 }
1376#endif /* COAP_Q_BLOCK_SUPPORT */
1377release_1:
1379 }
1380 }
1381 }
1382#endif /* COAP_SERVER_SUPPORT */
1383#if COAP_CLIENT_SUPPORT
1384 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1385 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1387 ctx->ping_timeout > 0) {
1388 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1389 /* Time to send a ping */
1391 /* Some issue - not safe to continue processing */
1392 continue;
1393 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1395 }
1396 s->last_rx_tx = now;
1397 s->last_ping = now;
1398 }
1399 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1400 if (timeout == 0 || s_timeout < timeout)
1401 timeout = s_timeout;
1402 }
1403
1404#if !COAP_DISABLE_TCP
1406 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) {
1407 if (s->csm_tx == 0) {
1408 s->csm_tx = now;
1409 s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000;
1410 } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) {
1411 /* timed out */
1412 s_timeout = 0;
1413 } else {
1414 s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now;
1415 }
1416 if ((timeout == 0 || s_timeout < timeout) && s_timeout != 0)
1417 timeout = s_timeout;
1418 }
1419#endif /* !COAP_DISABLE_TCP */
1420
1421 /* Make sure the session object is not deleted in any callbacks */
1423 /* Check any DTLS timeouts and expire if appropriate */
1425 s->proto == COAP_PROTO_DTLS && s->tls) {
1426 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1427 while (tls_timeout > 0 && tls_timeout <= now) {
1428 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
1430 goto release_2;
1431
1432 if (s->tls)
1433 tls_timeout = coap_dtls_get_timeout(s, now);
1434 else {
1435 tls_timeout = 0;
1436 timeout = 1;
1437 }
1438 }
1439 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1440 timeout = tls_timeout - now;
1441 }
1442
1443 /* Check if any client large receives are missing blocks */
1444 if (s->lg_crcv) {
1445 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1446 if (timeout == 0 || s_timeout < timeout)
1447 timeout = s_timeout;
1448 }
1449 }
1450 /* Check if any client large sending have timed out */
1451 if (s->lg_xmit) {
1452 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1453 if (timeout == 0 || s_timeout < timeout)
1454 timeout = s_timeout;
1455 }
1456 }
1457#if COAP_Q_BLOCK_SUPPORT
1458 /*
1459 * Check if any client large transmits have hit MAX_PAYLOAD and need
1460 * restarting
1461 */
1462 if (s->lg_xmit) {
1463 s_timeout = coap_block_check_q_block1_xmit(s, now);
1464 if (timeout == 0 || s_timeout < timeout)
1465 timeout = s_timeout;
1466 }
1467#endif /* COAP_Q_BLOCK_SUPPORT */
1468
1469#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1470 assert(s->ref > 1);
1471 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1474 if (*num_sockets < max_sockets)
1475 sockets[(*num_sockets)++] = &s->sock;
1476 }
1477#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1478release_2:
1480 }
1481#endif /* COAP_CLIENT_SUPPORT */
1482
1483 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1484}
1485
1486#if !defined(WITH_LWIP) && !defined(CONTIKI) && !defined(RIOT_VERSION)
1487int
1488coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1489 return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL);
1490}
1491
1492int
1494 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1495 fd_set *eexceptfds) {
1496 coap_fd_t nfds = 0;
1497 coap_tick_t before, now;
1498 unsigned int timeout;
1499#ifndef COAP_EPOLL_SUPPORT
1500 struct timeval tv;
1501 int result;
1502 unsigned int i;
1503#endif /* ! COAP_EPOLL_SUPPORT */
1504
1506 coap_ticks(&before);
1507
1508#ifndef COAP_EPOLL_SUPPORT
1509
1510 timeout = coap_io_prepare_io(ctx, ctx->sockets,
1511 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
1512 &ctx->num_sockets, before);
1513
1514 if (ereadfds) {
1515 ctx->readfds = *ereadfds;
1516 nfds = enfds;
1517 } else {
1518 FD_ZERO(&ctx->readfds);
1519 }
1520 if (ewritefds) {
1521 ctx->writefds = *ewritefds;
1522 nfds = enfds;
1523 } else {
1524 FD_ZERO(&ctx->writefds);
1525 }
1526 if (eexceptfds) {
1527 ctx->exceptfds = *eexceptfds;
1528 nfds = enfds;
1529 } else {
1530 FD_ZERO(&ctx->exceptfds);
1531 }
1532 for (i = 0; i < ctx->num_sockets; i++) {
1533 if (ctx->sockets[i]->fd + 1 > nfds)
1534 nfds = ctx->sockets[i]->fd + 1;
1535 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1536 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1537 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1538 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1539#if !COAP_DISABLE_TCP
1540 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1541 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1542 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1543 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1544 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1545 }
1546#endif /* !COAP_DISABLE_TCP */
1547 }
1548
1549 if (timeout_ms == COAP_IO_NO_WAIT) {
1550 tv.tv_usec = 0;
1551 tv.tv_sec = 0;
1552 timeout = 1;
1553 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1554 ;
1555 } else {
1556 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1557 timeout = timeout_ms;
1558 tv.tv_usec = (timeout % 1000) * 1000;
1559 tv.tv_sec = (long)(timeout / 1000);
1560 }
1561
1562 /* Unlock so that other threads can lock/update ctx */
1563 coap_lock_unlock(ctx);
1564
1565 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds,
1566 timeout > 0 ? &tv : NULL);
1567
1568 coap_lock_lock(ctx, return -1);
1569
1570 if (result < 0) { /* error */
1571#ifdef _WIN32
1572 coap_win_error_to_errno();
1573#endif
1574 if (errno != EINTR) {
1576 return -1;
1577 }
1578 }
1579 if (ereadfds) {
1580 *ereadfds = ctx->readfds;
1581 }
1582 if (ewritefds) {
1583 *ewritefds = ctx->writefds;
1584 }
1585 if (eexceptfds) {
1586 *eexceptfds = ctx->exceptfds;
1587 }
1588
1589 if (result > 0) {
1590#if COAP_THREAD_SAFE
1591 /* Need to refresh what is available to read / write etc. */
1592 tv.tv_usec = 0;
1593 tv.tv_sec = 0;
1594 select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds, &tv);
1595#endif /* COAP_THREAD_SAFE */
1596 for (i = 0; i < ctx->num_sockets; i++) {
1597 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ) &&
1598 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1600#if !COAP_DISABLE_TCP
1601 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) &&
1602 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1604 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE) &&
1605 FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds))
1607 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) &&
1608 (FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds) ||
1609 FD_ISSET(ctx->sockets[i]->fd, &ctx->exceptfds)))
1611#endif /* !COAP_DISABLE_TCP */
1612 }
1613 }
1614
1615 coap_ticks(&now);
1616 coap_io_do_io(ctx, now);
1617
1618#else /* COAP_EPOLL_SUPPORT */
1619 (void)ereadfds;
1620 (void)ewritefds;
1621 (void)eexceptfds;
1622 (void)enfds;
1623
1624 timeout = coap_io_prepare_epoll(ctx, before);
1625
1626 do {
1627 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1628 int etimeout;
1629
1630 /* Potentially adjust based on what the caller wants */
1631 if (timeout_ms == COAP_IO_NO_WAIT) {
1632 /* Need to return immediately from epoll_wait() */
1633 etimeout = 0;
1634 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1635 /*
1636 * Nothing found in coap_io_prepare_epoll() and COAP_IO_WAIT set,
1637 * so wait forever in epoll_wait().
1638 */
1639 etimeout = -1;
1640 } else {
1641 etimeout = timeout;
1642 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1643 etimeout = timeout_ms;
1644 if (etimeout < 0) {
1645 /*
1646 * If timeout > INT_MAX, epoll_wait() cannot wait longer than this as
1647 * it has int timeout parameter
1648 */
1649 etimeout = INT_MAX;
1650 }
1651 }
1652
1653 /* Unlock so that other threads can lock/update ctx */
1654 coap_lock_unlock(ctx);
1655
1656 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1657 if (nfds < 0) {
1658 if (errno != EINTR) {
1659 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1660 coap_socket_strerror(), nfds);
1661 }
1662 coap_lock_lock(ctx, return -1);
1663 break;
1664 }
1665
1666#if COAP_THREAD_SAFE
1667 /* Need to refresh what is available to read / write etc. */
1668 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, 0);
1669 if (nfds < 0) {
1670 if (errno != EINTR) {
1671 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1672 coap_socket_strerror(), nfds);
1673 }
1674 coap_lock_lock(ctx, return -1);
1675 break;
1676 }
1677#endif /* COAP_THREAD_SAFE */
1678 coap_lock_lock(ctx, return -1);
1679
1680 coap_io_do_epoll(ctx, events, nfds);
1681
1682 /*
1683 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1684 * incase we have to do another iteration
1685 * (COAP_MAX_EPOLL_EVENTS insufficient)
1686 */
1687 timeout_ms = COAP_IO_NO_WAIT;
1688
1689 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1690 } while (nfds == COAP_MAX_EPOLL_EVENTS);
1691
1692#endif /* COAP_EPOLL_SUPPORT */
1693#if COAP_SERVER_SUPPORT
1695#endif /* COAP_SERVER_SUPPORT */
1696 coap_ticks(&now);
1697#if COAP_ASYNC_SUPPORT
1698 /* Check to see if we need to send off any Async requests as delay might
1699 have been updated */
1700 coap_check_async(ctx, now);
1701 coap_ticks(&now);
1702#endif /* COAP_ASYNC_SUPPORT */
1703
1704 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1705}
1706#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION*/
1707
1708/*
1709 * return 1 I/O pending
1710 * 0 No I/O pending
1711 */
1712int
1714 coap_session_t *s, *rtmp;
1715#if COAP_SERVER_SUPPORT
1716 coap_endpoint_t *ep;
1717#endif /* COAP_SERVER_SUPPORT */
1718
1719 if (!context)
1720 return 0;
1721 coap_lock_check_locked(context);
1722 if (coap_io_process(context, COAP_IO_NO_WAIT) < 0)
1723 return 0;
1724
1725 if (context->sendqueue)
1726 return 1;
1727#if COAP_SERVER_SUPPORT
1728 LL_FOREACH(context->endpoint, ep) {
1729 SESSIONS_ITER(ep->sessions, s, rtmp) {
1730 if (s->delayqueue)
1731 return 1;
1732 if (s->lg_xmit)
1733 return 1;
1734 if (s->lg_srcv)
1735 return 1;
1736 }
1737 }
1738#endif /* COAP_SERVER_SUPPORT */
1739#if COAP_CLIENT_SUPPORT
1740 SESSIONS_ITER(context->sessions, s, rtmp) {
1741 if (s->delayqueue)
1742 return 1;
1743 if (s->lg_xmit)
1744 return 1;
1745 if (s->lg_crcv)
1746 return 1;
1747 }
1748#endif /* COAP_CLIENT_SUPPORT */
1749 return 0;
1750}
1751
1752#ifdef _WIN32
1753const char *
1754coap_socket_format_errno(int error) {
1755 static char szError[256];
1756 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1757 NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL,
1758 SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError),
1759 NULL) == 0)
1760 strcpy(szError, "Unknown error");
1761 return szError;
1762}
1763
1764const char *
1766 return coap_socket_format_errno(WSAGetLastError());
1767}
1768#else /* _WIN32 */
1769const char *
1771 return strerror(error);
1772}
1773const char *
1775 return coap_socket_format_errno(errno);
1776}
1777#endif /* _WIN32 */
1778
1779#undef SIN6
int coap_is_bcast(const coap_address_t *a)
Checks if given address a denotes a broadcast address.
Definition: coap_address.c:164
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: coap_address.c:253
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
Definition: coap_address.c:119
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: coap_address.c:743
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
Definition: coap_address.h:296
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:1365
Pulls together all the internal only header files.
#define COAP_IPV4_SUPPORT
Definition: coap_internal.h:70
const char * coap_socket_format_errno(int error)
Definition: coap_io.c:1770
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:667
void coap_socket_close(coap_socket_t *sock)
Function interface to close off a socket.
Definition: coap_io.c:365
ssize_t coap_socket_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for data transmission.
Definition: coap_io.c:773
const char * coap_socket_strerror(void)
Definition: coap_io.c:1774
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition: coap_io.c:966
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:953
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:608
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:494
#define MSG_NOSIGNAL
#define iov_len_t
Definition: coap_io.c:759
#define COAP_SOL_IP
Definition: coap_io.c:732
#define coap_closesocket
Definition: coap_io.h:48
#define COAP_MAX_EPOLL_EVENTS
Definition: coap_io.h:38
#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_CAN_WRITE
non blocking socket can now write without blocking
#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
@ COAP_ENDPOINT
Definition: coap_mem.h:44
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().
#define coap_lock_check_locked(s)
#define coap_lock_unlock(s)
#define coap_lock_lock(s, failed)
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition: coap_notls.c:193
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition: coap_notls.c:188
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:202
coap_mid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
Definition: coap_session.c:744
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
void coap_io_do_io(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:2122
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:1183
void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition: coap_net.c:2180
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:1234
int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition: coap_io.c:1488
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:1493
#define COAP_IO_NO_WAIT
Definition: coap_net.h:596
#define COAP_IO_WAIT
Definition: coap_net.h:595
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:1713
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)
Definition: coap_block.c:1206
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
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition: coap_net.c:247
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:255
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition: coap_net.c:1690
int coap_handle_event(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:4073
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:183
@ 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_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
void coap_check_notify(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition: coap_pdu.h:266
@ COAP_PROTO_DTLS
Definition: coap_pdu.h:315
void coap_session_free(coap_session_t *session)
Definition: coap_session.c:549
#define COAP_PROTO_RELIABLE(p)
Definition: coap_session.h:38
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:355
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:348
@ COAP_SESSION_TYPE_SERVER
server-side
Definition: coap_session.h:47
@ COAP_SESSION_TYPE_CLIENT
client-side
Definition: coap_session.h:46
@ COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:58
@ COAP_SESSION_STATE_CSM
Definition: coap_session.h:59
@ COAP_SESSION_STATE_ESTABLISHED
Definition: coap_session.h:60
@ COAP_SESSION_STATE_NONE
Definition: coap_session.h:56
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.
Definition: coap_address.h:148
socklen_t size
size of addr
Definition: coap_address.h:149
struct sockaddr_in sin
Definition: coap_address.h:152
struct coap_sockaddr_un cun
Definition: coap_address.h:154
struct sockaddr_in6 sin6
Definition: coap_address.h:153
struct sockaddr sa
Definition: coap_address.h:151
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.
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()
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
coap_queue_t * sendqueue
coap_endpoint_t * endpoint
the endpoints used for listening
uint32_t csm_timeout_ms
Timeout for waiting for a CSM from the remote side.
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
coap_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationship with peer
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
unsigned ref
reference count from queues
void * tls
security parameters
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
int ifindex
interface index
char sun_path[COAP_UNIX_PATH_MAX]
Definition: coap_address.h:144
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:712
unsigned int ipi6_ifindex
Definition: coap_io.c:713
struct in_addr ipi_spec_dst
Definition: coap_io.c:718
struct in_addr ipi_addr
Definition: coap_io.c:719
int ipi_ifindex
Definition: coap_io.c:717