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