libcoap 4.3.5rc1
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-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
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_update_io_timer",
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
1182COAP_API unsigned int
1184 unsigned int ret;
1185
1186 coap_lock_lock(ctx, return 0);
1187 ret = coap_io_prepare_epoll_lkd(ctx, now);
1188 coap_lock_unlock(ctx);
1189 return ret;
1190}
1191
1192unsigned int
1194#ifndef COAP_EPOLL_SUPPORT
1195 (void)ctx;
1196 (void)now;
1197 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1198 return 0;
1199#else /* COAP_EPOLL_SUPPORT */
1200 coap_socket_t *sockets[1];
1201 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1202 unsigned int num_sockets;
1203 unsigned int timeout;
1204
1206 /* Use the common logic */
1207 timeout = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, &num_sockets, now);
1208 /* Save when the next expected I/O is to take place */
1209 ctx->next_timeout = timeout ? now + timeout : 0;
1210 if (ctx->eptimerfd != -1) {
1211 struct itimerspec new_value;
1212 int ret;
1213
1214 memset(&new_value, 0, sizeof(new_value));
1215 coap_ticks(&now);
1216 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1217 coap_tick_t rem_timeout = ctx->next_timeout - now;
1218 /* Need to trigger an event on ctx->eptimerfd in the future */
1219 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1220 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1221 1000000;
1222 }
1223#ifdef COAP_DEBUG_WAKEUP_TIMES
1224 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
1225 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1226#endif /* COAP_DEBUG_WAKEUP_TIMES */
1227 /* reset, or specify a future time for eptimerfd to trigger */
1228 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1229 if (ret == -1) {
1230 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
1231 "coap_io_prepare_epoll",
1232 coap_socket_strerror(), errno);
1233 }
1234 }
1235 return timeout;
1236#endif /* COAP_EPOLL_SUPPORT */
1237}
1238
1239/*
1240 * return 0 No i/o pending
1241 * +ve millisecs to next i/o activity
1242 */
1243COAP_API unsigned int
1245 coap_socket_t *sockets[],
1246 unsigned int max_sockets,
1247 unsigned int *num_sockets,
1248 coap_tick_t now) {
1249 unsigned int ret;
1250
1251 coap_lock_lock(ctx, return 0);
1252 ret = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, num_sockets, now);
1253 coap_lock_unlock(ctx);
1254 return ret;
1255}
1256
1257/*
1258 * return 0 No i/o pending
1259 * +ve millisecs to next i/o activity
1260 */
1261unsigned int
1263 coap_socket_t *sockets[],
1264 unsigned int max_sockets,
1265 unsigned int *num_sockets,
1266 coap_tick_t now) {
1267 coap_queue_t *nextpdu;
1268 coap_session_t *s, *rtmp;
1269 coap_tick_t timeout = 0;
1270 coap_tick_t s_timeout;
1271#if COAP_SERVER_SUPPORT
1272 int check_dtls_timeouts = 0;
1273#endif /* COAP_SERVER_SUPPORT */
1274#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION)
1275 (void)sockets;
1276 (void)max_sockets;
1277#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/
1278
1280 *num_sockets = 0;
1281
1282#if COAP_SERVER_SUPPORT
1283 /* Check to see if we need to send off any Observe requests */
1285
1286#if COAP_ASYNC_SUPPORT
1287 /* Check to see if we need to send off any Async requests */
1288 timeout = coap_check_async(ctx, now);
1289#endif /* COAP_ASYNC_SUPPORT */
1290#endif /* COAP_SERVER_SUPPORT */
1291
1292 /* Check to see if we need to send off any retransmit request */
1293 nextpdu = coap_peek_next(ctx);
1294 while (nextpdu && now >= ctx->sendqueue_basetime &&
1295 nextpdu->t <= now - ctx->sendqueue_basetime) {
1296 coap_retransmit(ctx, coap_pop_next(ctx));
1297 nextpdu = coap_peek_next(ctx);
1298 }
1299 if (nextpdu && (timeout == 0 ||
1300 nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1301 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1302
1303 /* Check for DTLS timeouts */
1304 if (ctx->dtls_context) {
1307 if (tls_timeout > 0) {
1308 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1309 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1310 coap_log_debug("** DTLS global timeout set to %dms\n",
1311 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1312 if (timeout == 0 || tls_timeout - now < timeout)
1313 timeout = tls_timeout - now;
1314 }
1315#if COAP_SERVER_SUPPORT
1316 } else {
1317 check_dtls_timeouts = 1;
1318#endif /* COAP_SERVER_SUPPORT */
1319 }
1320 }
1321#if COAP_SERVER_SUPPORT
1322 coap_endpoint_t *ep;
1323 coap_tick_t session_timeout;
1324
1325 if (ctx->session_timeout > 0)
1326 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1327 else
1329
1330 LL_FOREACH(ctx->endpoint, ep) {
1331#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1333 if (*num_sockets < max_sockets)
1334 sockets[(*num_sockets)++] = &ep->sock;
1335 }
1336#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1337 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1338 /* Check whether any idle server sessions should be released */
1339 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1340 s->delayqueue == NULL &&
1341 (s->last_rx_tx + session_timeout <= now ||
1345 } else {
1346 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1347 s->delayqueue == NULL) {
1348 s_timeout = (s->last_rx_tx + session_timeout) - now;
1349 if (timeout == 0 || s_timeout < timeout)
1350 timeout = s_timeout;
1351 }
1352 /* Make sure the session object is not deleted in any callbacks */
1354 /* Check any DTLS timeouts and expire if appropriate */
1355 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1356 s->proto == COAP_PROTO_DTLS && s->tls) {
1357 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1358 while (tls_timeout > 0 && tls_timeout <= now) {
1359 coap_log_debug("** %s: DTLS retransmit timeout\n",
1360 coap_session_str(s));
1362 goto release_1;
1363
1364 if (s->tls)
1365 tls_timeout = coap_dtls_get_timeout(s, now);
1366 else {
1367 tls_timeout = 0;
1368 timeout = 1;
1369 }
1370 }
1371 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1372 timeout = tls_timeout - now;
1373 }
1374 /* Check if any server large receives are missing blocks */
1375 if (s->lg_srcv) {
1376 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1377 if (timeout == 0 || s_timeout < timeout)
1378 timeout = s_timeout;
1379 }
1380 }
1381 /* Check if any server large sending have timed out */
1382 if (s->lg_xmit) {
1383 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1384 if (timeout == 0 || s_timeout < timeout)
1385 timeout = s_timeout;
1386 }
1387 }
1388#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1390 if (*num_sockets < max_sockets)
1391 sockets[(*num_sockets)++] = &s->sock;
1392 }
1393#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1394#if COAP_Q_BLOCK_SUPPORT
1395 /*
1396 * Check if any server large transmits have hit MAX_PAYLOAD and need
1397 * restarting
1398 */
1399 if (s->lg_xmit) {
1400 s_timeout = coap_block_check_q_block2_xmit(s, now);
1401 if (timeout == 0 || s_timeout < timeout)
1402 timeout = s_timeout;
1403 }
1404#endif /* COAP_Q_BLOCK_SUPPORT */
1405release_1:
1407 }
1408 }
1409 }
1410#endif /* COAP_SERVER_SUPPORT */
1411#if COAP_CLIENT_SUPPORT
1412 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1413 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1415 ctx->ping_timeout > 0) {
1416 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1417 /* Time to send a ping */
1419 /* Some issue - not safe to continue processing */
1420 continue;
1421 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1423 }
1424 s->last_rx_tx = now;
1425 s->last_ping = now;
1426 }
1427 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1428 if (timeout == 0 || s_timeout < timeout)
1429 timeout = s_timeout;
1430 }
1431
1432#if !COAP_DISABLE_TCP
1434 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) {
1435 if (s->csm_tx == 0) {
1436 s->csm_tx = now;
1437 s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000;
1438 } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) {
1439 /* timed out */
1440 s_timeout = 0;
1441 } else {
1442 s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now;
1443 }
1444 if ((timeout == 0 || s_timeout < timeout) && s_timeout != 0)
1445 timeout = s_timeout;
1446 }
1447#endif /* !COAP_DISABLE_TCP */
1448
1449 /* Make sure the session object is not deleted in any callbacks */
1451 /* Check any DTLS timeouts and expire if appropriate */
1453 s->proto == COAP_PROTO_DTLS && s->tls) {
1454 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1455 while (tls_timeout > 0 && tls_timeout <= now) {
1456 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
1458 goto release_2;
1459
1460 if (s->tls)
1461 tls_timeout = coap_dtls_get_timeout(s, now);
1462 else {
1463 tls_timeout = 0;
1464 timeout = 1;
1465 }
1466 }
1467 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1468 timeout = tls_timeout - now;
1469 }
1470
1471 /* Check if any client large receives are missing blocks */
1472 if (s->lg_crcv) {
1473 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1474 if (timeout == 0 || s_timeout < timeout)
1475 timeout = s_timeout;
1476 }
1477 }
1478 /* Check if any client large sending have timed out */
1479 if (s->lg_xmit) {
1480 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1481 if (timeout == 0 || s_timeout < timeout)
1482 timeout = s_timeout;
1483 }
1484 }
1485#if COAP_Q_BLOCK_SUPPORT
1486 /*
1487 * Check if any client large transmits have hit MAX_PAYLOAD and need
1488 * restarting
1489 */
1490 if (s->lg_xmit) {
1491 s_timeout = coap_block_check_q_block1_xmit(s, now);
1492 if (timeout == 0 || s_timeout < timeout)
1493 timeout = s_timeout;
1494 }
1495#endif /* COAP_Q_BLOCK_SUPPORT */
1496
1497#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1498 assert(s->ref > 1);
1499 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1502 if (*num_sockets < max_sockets)
1503 sockets[(*num_sockets)++] = &s->sock;
1504 }
1505#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1506release_2:
1508 }
1509#endif /* COAP_CLIENT_SUPPORT */
1510
1511 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1512}
1513
1514#if !defined(WITH_LWIP) && !defined(CONTIKI) && !defined(RIOT_VERSION)
1515COAP_API int
1516coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1517 int ret;
1518
1519 coap_lock_lock(ctx, return 0);
1520 ret = coap_io_process_lkd(ctx, timeout_ms);
1521 coap_lock_unlock(ctx);
1522 return ret;
1523}
1524
1525int
1526coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms) {
1527 return coap_io_process_with_fds_lkd(ctx, timeout_ms, 0, NULL, NULL, NULL);
1528}
1529
1530COAP_API int
1532 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1533 fd_set *eexceptfds) {
1534 int ret;
1535
1536 coap_lock_lock(ctx, return 0);
1537 ret = coap_io_process_with_fds_lkd(ctx, timeout_ms, enfds, ereadfds, ewritefds,
1538 eexceptfds);
1539 coap_lock_unlock(ctx);
1540 return ret;
1541}
1542
1543int
1545 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1546 fd_set *eexceptfds) {
1547 coap_fd_t nfds = 0;
1548 coap_tick_t before, now;
1549 unsigned int timeout;
1550#ifndef COAP_EPOLL_SUPPORT
1551 struct timeval tv;
1552 int result;
1553 unsigned int i;
1554#endif /* ! COAP_EPOLL_SUPPORT */
1555
1557 coap_ticks(&before);
1558
1559#ifndef COAP_EPOLL_SUPPORT
1560
1561 timeout = coap_io_prepare_io_lkd(ctx, ctx->sockets,
1562 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
1563 &ctx->num_sockets, before);
1564
1565 if (ereadfds) {
1566 ctx->readfds = *ereadfds;
1567 nfds = enfds;
1568 } else {
1569 FD_ZERO(&ctx->readfds);
1570 }
1571 if (ewritefds) {
1572 ctx->writefds = *ewritefds;
1573 nfds = enfds;
1574 } else {
1575 FD_ZERO(&ctx->writefds);
1576 }
1577 if (eexceptfds) {
1578 ctx->exceptfds = *eexceptfds;
1579 nfds = enfds;
1580 } else {
1581 FD_ZERO(&ctx->exceptfds);
1582 }
1583 for (i = 0; i < ctx->num_sockets; i++) {
1584 if (ctx->sockets[i]->fd + 1 > nfds)
1585 nfds = ctx->sockets[i]->fd + 1;
1586 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1587 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1588 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1589 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1590#if !COAP_DISABLE_TCP
1591 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1592 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1593 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1594 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1595 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1596 }
1597#endif /* !COAP_DISABLE_TCP */
1598 }
1599
1600 if (timeout_ms == COAP_IO_NO_WAIT) {
1601 tv.tv_usec = 0;
1602 tv.tv_sec = 0;
1603 timeout = 1;
1604 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1605 ;
1606 } else {
1607 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1608 timeout = timeout_ms;
1609 tv.tv_usec = (timeout % 1000) * 1000;
1610 tv.tv_sec = (long)(timeout / 1000);
1611 }
1612
1613 /* Unlock so that other threads can lock/update ctx */
1614 coap_lock_unlock(ctx);
1615
1616 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds,
1617 timeout > 0 ? &tv : NULL);
1618
1619 coap_lock_lock(ctx, return -1);
1620
1621 if (result < 0) { /* error */
1622#ifdef _WIN32
1623 coap_win_error_to_errno();
1624#endif
1625 if (errno != EINTR) {
1627 return -1;
1628 }
1629 }
1630 if (ereadfds) {
1631 *ereadfds = ctx->readfds;
1632 }
1633 if (ewritefds) {
1634 *ewritefds = ctx->writefds;
1635 }
1636 if (eexceptfds) {
1637 *eexceptfds = ctx->exceptfds;
1638 }
1639
1640 if (result > 0) {
1641#if COAP_THREAD_SAFE
1642 /* Need to refresh what is available to read / write etc. */
1643 tv.tv_usec = 0;
1644 tv.tv_sec = 0;
1645 select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds, &tv);
1646#endif /* COAP_THREAD_SAFE */
1647 for (i = 0; i < ctx->num_sockets; i++) {
1648 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ) &&
1649 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1651#if !COAP_DISABLE_TCP
1652 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) &&
1653 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1655 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE) &&
1656 FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds))
1658 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) &&
1659 (FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds) ||
1660 FD_ISSET(ctx->sockets[i]->fd, &ctx->exceptfds)))
1662#endif /* !COAP_DISABLE_TCP */
1663 }
1664 }
1665
1666 coap_ticks(&now);
1667 coap_io_do_io_lkd(ctx, now);
1668
1669#else /* COAP_EPOLL_SUPPORT */
1670 (void)ereadfds;
1671 (void)ewritefds;
1672 (void)eexceptfds;
1673 (void)enfds;
1674
1675 timeout = coap_io_prepare_epoll_lkd(ctx, before);
1676
1677 do {
1678 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1679 int etimeout;
1680
1681 /* Potentially adjust based on what the caller wants */
1682 if (timeout_ms == COAP_IO_NO_WAIT) {
1683 /* Need to return immediately from epoll_wait() */
1684 etimeout = 0;
1685 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1686 /*
1687 * Nothing found in coap_io_prepare_epoll_lkd() and COAP_IO_WAIT set,
1688 * so wait forever in epoll_wait().
1689 */
1690 etimeout = -1;
1691 } else {
1692 etimeout = timeout;
1693 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1694 etimeout = timeout_ms;
1695 if (etimeout < 0) {
1696 /*
1697 * If timeout > INT_MAX, epoll_wait() cannot wait longer than this as
1698 * it has int timeout parameter
1699 */
1700 etimeout = INT_MAX;
1701 }
1702 }
1703
1704 /* Unlock so that other threads can lock/update ctx */
1705 coap_lock_unlock(ctx);
1706
1707 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1708 if (nfds < 0) {
1709 if (errno != EINTR) {
1710 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1711 coap_socket_strerror(), nfds);
1712 }
1713 coap_lock_lock(ctx, return -1);
1714 break;
1715 }
1716
1717#if COAP_THREAD_SAFE
1718 /* Need to refresh what is available to read / write etc. */
1719 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, 0);
1720 if (nfds < 0) {
1721 if (errno != EINTR) {
1722 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1723 coap_socket_strerror(), nfds);
1724 }
1725 coap_lock_lock(ctx, return -1);
1726 break;
1727 }
1728#endif /* COAP_THREAD_SAFE */
1729 coap_lock_lock(ctx, return -1);
1730
1731 coap_io_do_epoll_lkd(ctx, events, nfds);
1732
1733 /*
1734 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1735 * incase we have to do another iteration
1736 * (COAP_MAX_EPOLL_EVENTS insufficient)
1737 */
1738 timeout_ms = COAP_IO_NO_WAIT;
1739
1740 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1741 } while (nfds == COAP_MAX_EPOLL_EVENTS);
1742
1743#endif /* COAP_EPOLL_SUPPORT */
1744#if COAP_SERVER_SUPPORT
1746#endif /* COAP_SERVER_SUPPORT */
1747 coap_ticks(&now);
1748#if COAP_ASYNC_SUPPORT
1749 /* Check to see if we need to send off any Async requests as delay might
1750 have been updated */
1751 coap_check_async(ctx, now);
1752 coap_ticks(&now);
1753#endif /* COAP_ASYNC_SUPPORT */
1754
1755 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1756}
1757#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION*/
1758
1759COAP_API int
1761 int ret;
1762
1763 coap_lock_lock(context, return 0);
1764 ret = coap_io_pending_lkd(context);
1765 coap_lock_unlock(context);
1766 return ret;
1767}
1768
1769/*
1770 * return 1 I/O pending
1771 * 0 No I/O pending
1772 */
1773int
1775 coap_session_t *s, *rtmp;
1776#if COAP_SERVER_SUPPORT
1777 coap_endpoint_t *ep;
1778#endif /* COAP_SERVER_SUPPORT */
1779
1780 if (!context)
1781 return 0;
1782 coap_lock_check_locked(context);
1783 if (coap_io_process_lkd(context, COAP_IO_NO_WAIT) < 0)
1784 return 0;
1785
1786 if (context->sendqueue)
1787 return 1;
1788#if COAP_SERVER_SUPPORT
1789 LL_FOREACH(context->endpoint, ep) {
1790 SESSIONS_ITER(ep->sessions, s, rtmp) {
1791 if (s->delayqueue)
1792 return 1;
1793 if (s->lg_xmit)
1794 return 1;
1795 if (s->lg_srcv)
1796 return 1;
1797 }
1798 }
1799#endif /* COAP_SERVER_SUPPORT */
1800#if COAP_CLIENT_SUPPORT
1801 SESSIONS_ITER(context->sessions, s, rtmp) {
1802 if (s->delayqueue)
1803 return 1;
1804 if (s->lg_xmit)
1805 return 1;
1806 if (s->lg_crcv)
1807 return 1;
1808 }
1809#endif /* COAP_CLIENT_SUPPORT */
1810 return 0;
1811}
1812
1813#ifdef _WIN32
1814const char *
1815coap_socket_format_errno(int error) {
1816 static char szError[256];
1817 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1818 NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL,
1819 SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError),
1820 NULL) == 0)
1821 strcpy(szError, "Unknown error");
1822 return szError;
1823}
1824
1825const char *
1827 return coap_socket_format_errno(WSAGetLastError());
1828}
1829#else /* _WIN32 */
1830const char *
1832 return strerror(error);
1833}
1834const char *
1836 return coap_socket_format_errno(errno);
1837}
1838#endif /* _WIN32 */
1839
1840#undef SIN6
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.
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:1831
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:1835
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
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ 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().
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition coap_notls.c:206
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:201
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:215
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
#define coap_lock_unlock(c)
#define coap_lock_lock(c, failed)
#define coap_lock_check_locked(c)
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:2317
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:1774
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:2252
int coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1526
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:1544
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:1262
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:1193
COAP_API int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1516
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:1760
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:1244
#define COAP_IO_NO_WAIT
Definition coap_net.h:620
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:1183
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:1531
#define COAP_IO_WAIT
Definition coap_net.h:619
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
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:4253
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition coap_net.c:269
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:277
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition coap_net.c:1812
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:196
@ 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
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition coap_pdu.h:266
@ COAP_PROTO_DTLS
Definition coap_pdu.h:315
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 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
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]
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