libcoap 4.3.5b
Loading...
Searching...
No Matches
coap_io.c
Go to the documentation of this file.
1/* coap_io.c -- Default network I/O functions for libcoap
2 *
3 * Copyright (C) 2012,2014,2016-2025 Olaf Bergmann <bergmann@tzi.org> and others
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
15
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 */
678 errno = ECONNRESET;
679 return -1;
680 } else if (r == COAP_SOCKET_ERROR) {
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)
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__ && ! RIOT_VERSION */
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 __thread LPFN_WSARECVMSG lpWSARecvMsg = NULL;
739#if(_WIN32_WINNT >= 0x0600)
740#define CMSG_FIRSTHDR WSA_CMSG_FIRSTHDR
741#define CMSG_NXTHDR WSA_CMSG_NXTHDR
742#define CMSG_LEN WSA_CMSG_LEN
743#define CMSG_SPACE WSA_CMSG_SPACE
744#if(_WIN32_WINNT < 0x0603 || _WIN32_WINNT == 0x0a00)
745#define cmsghdr _WSACMSGHDR
746#endif /* (_WIN32_WINNT<0x0603 || _WIN32_WINNT == 0x0a00) */
747#endif /* (_WIN32_WINNT>=0x0600) */
748#else /* ! __MINGW32__ */
749static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
750#endif /* ! __MINGW32__ */
751/* Map struct WSABUF fields to their posix counterpart */
752#define msghdr _WSAMSG
753#define msg_name name
754#define msg_namelen namelen
755#define msg_iov lpBuffers
756#define msg_iovlen dwBufferCount
757#define msg_control Control.buf
758#define msg_controllen Control.len
759#define iovec _WSABUF
760#define iov_base buf
761#define iov_len len
762#define iov_len_t u_long
763#undef CMSG_DATA
764#define CMSG_DATA WSA_CMSG_DATA
765#define ipi_spec_dst ipi_addr
766#if !defined(__MINGW32__)
767#pragma warning( disable : 4116 )
768#endif /* ! __MINGW32__ */
769#else
770#define iov_len_t size_t
771#endif
772
773#if defined(_CYGWIN_ENV) || defined(__QNXNTO__)
774#define ipi_spec_dst ipi_addr
775#endif
776
777#if !defined(RIOT_VERSION) && !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
778#if COAP_CLIENT_SUPPORT
779static uint32_t cid_track_counter;
780
781static void
782coap_test_cid_tuple_change(coap_session_t *session) {
783 if (session->type == COAP_SESSION_TYPE_CLIENT &&
784 session->negotiated_cid &&
786 session->proto == COAP_PROTO_DTLS && session->context->testing_cids) {
787 if ((++cid_track_counter) % session->context->testing_cids == 0) {
788 coap_address_t local_if = session->addr_info.local;
789 uint16_t port = coap_address_get_port(&local_if);
790
791 port++;
792 coap_address_set_port(&local_if, port);
793
794 coap_socket_close(&session->sock);
795 session->sock.session = session;
796 if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
797 port,
798 &session->addr_info.local,
799 &session->addr_info.remote)) {
800 coap_log_err("Tuple change for CID failed\n");
801 return;
802#ifdef COAP_EPOLL_SUPPORT
803 } else {
804 coap_epoll_ctl_add(&session->sock,
805 EPOLLIN |
806 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
807 EPOLLOUT : 0),
808 __func__);
809#endif /* COAP_EPOLL_SUPPORT */
810 }
812 }
813 }
814}
815#endif /* COAP_CLIENT_SUPPORT */
816
817/*
818 * dgram
819 * return +ve Number of bytes written.
820 * -1 Error error in errno).
821 */
822ssize_t
824 const uint8_t *data, size_t datalen) {
825 ssize_t bytes_written = 0;
826
827#if COAP_CLIENT_SUPPORT
828 coap_test_cid_tuple_change(session);
829#endif /* COAP_CLIENT_SUPPORT */
830
831 if (!coap_debug_send_packet()) {
832 bytes_written = (ssize_t)datalen;
833 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
834#ifdef _WIN32
835 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
836#else
837 bytes_written = send(sock->fd, data, datalen, 0);
838#endif
839 } else {
840#if defined(_WIN32)
841 DWORD dwNumberOfBytesSent = 0;
842 int r;
843#endif /* _WIN32 */
844#ifdef HAVE_STRUCT_CMSGHDR
845 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
846 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
847 struct msghdr mhdr;
848 struct iovec iov[1];
849 const void *addr = &session->addr_info.remote.addr;
850
851 assert(session);
852
853 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
854 iov[0].iov_len = (iov_len_t)datalen;
855
856 memset(buf, 0, sizeof(buf));
857
858 memset(&mhdr, 0, sizeof(struct msghdr));
859 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
860 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
861 (socklen_t)sizeof(struct sockaddr_in) :
862 session->addr_info.remote.size;
863
864 mhdr.msg_iov = iov;
865 mhdr.msg_iovlen = 1;
866
867 if (!coap_address_isany(&session->addr_info.local) &&
868 !coap_is_mcast(&session->addr_info.local)) {
869 switch (session->addr_info.local.addr.sa.sa_family) {
870#if COAP_IPV6_SUPPORT
871 case AF_INET6: {
872 struct cmsghdr *cmsg;
873
874#if COAP_IPV4_SUPPORT
875 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
876#if defined(IP_PKTINFO)
877 struct in_pktinfo *pktinfo;
878 mhdr.msg_control = buf;
879 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
880
881 cmsg = CMSG_FIRSTHDR(&mhdr);
882 cmsg->cmsg_level = COAP_SOL_IP;
883 cmsg->cmsg_type = IP_PKTINFO;
884 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
885
886 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
887
888 pktinfo->ipi_ifindex = session->ifindex;
889 memcpy(&pktinfo->ipi_spec_dst,
890 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
891 sizeof(pktinfo->ipi_spec_dst));
892#elif defined(IP_SENDSRCADDR)
893 mhdr.msg_control = buf;
894 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
895
896 cmsg = CMSG_FIRSTHDR(&mhdr);
897 cmsg->cmsg_level = IPPROTO_IP;
898 cmsg->cmsg_type = IP_SENDSRCADDR;
899 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
900
901 memcpy(CMSG_DATA(cmsg),
902 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
903 sizeof(struct in_addr));
904#endif /* IP_PKTINFO */
905 } else {
906#endif /* COAP_IPV4_SUPPORT */
907 struct in6_pktinfo *pktinfo;
908 mhdr.msg_control = buf;
909 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
910
911 cmsg = CMSG_FIRSTHDR(&mhdr);
912 cmsg->cmsg_level = IPPROTO_IPV6;
913 cmsg->cmsg_type = IPV6_PKTINFO;
914 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
915
916 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
917
918 pktinfo->ipi6_ifindex = session->ifindex;
919 memcpy(&pktinfo->ipi6_addr,
920 &session->addr_info.local.addr.sin6.sin6_addr,
921 sizeof(pktinfo->ipi6_addr));
922#if COAP_IPV4_SUPPORT
923 }
924#endif /* COAP_IPV4_SUPPORT */
925 break;
926 }
927#endif /* COAP_IPV6_SUPPORT */
928#if COAP_IPV4_SUPPORT
929 case AF_INET: {
930#if defined(IP_PKTINFO)
931 struct cmsghdr *cmsg;
932 struct in_pktinfo *pktinfo;
933
934 mhdr.msg_control = buf;
935 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
936
937 cmsg = CMSG_FIRSTHDR(&mhdr);
938 cmsg->cmsg_level = COAP_SOL_IP;
939 cmsg->cmsg_type = IP_PKTINFO;
940 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
941
942 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
943
944 pktinfo->ipi_ifindex = session->ifindex;
945 memcpy(&pktinfo->ipi_spec_dst,
946 &session->addr_info.local.addr.sin.sin_addr,
947 sizeof(pktinfo->ipi_spec_dst));
948#elif defined(IP_SENDSRCADDR)
949 struct cmsghdr *cmsg;
950 mhdr.msg_control = buf;
951 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
952
953 cmsg = CMSG_FIRSTHDR(&mhdr);
954 cmsg->cmsg_level = IPPROTO_IP;
955 cmsg->cmsg_type = IP_SENDSRCADDR;
956 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
957
958 memcpy(CMSG_DATA(cmsg),
959 &session->addr_info.local.addr.sin.sin_addr,
960 sizeof(struct in_addr));
961#endif /* IP_PKTINFO */
962 break;
963 }
964#endif /* COAP_IPV4_SUPPORT */
965#if COAP_AF_UNIX_SUPPORT
966 case AF_UNIX:
967 break;
968#endif /* COAP_AF_UNIX_SUPPORT */
969 default:
970 /* error */
971 coap_log_warn("protocol not supported\n");
972 return -1;
973 }
974 }
975#endif /* HAVE_STRUCT_CMSGHDR */
976
977#if defined(_WIN32)
978 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
979 NULL /*lpCompletionRoutine*/);
980 if (r == 0)
981 bytes_written = (ssize_t)dwNumberOfBytesSent;
982 else {
983 bytes_written = -1;
984 coap_win_error_to_errno();
985 }
986#else /* !_WIN32 */
987#ifdef HAVE_STRUCT_CMSGHDR
988 bytes_written = sendmsg(sock->fd, &mhdr, 0);
989#else /* ! HAVE_STRUCT_CMSGHDR */
990 bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
991 &session->addr_info.remote.addr.sa,
992 session->addr_info.remote.size);
993#endif /* ! HAVE_STRUCT_CMSGHDR */
994#endif /* !_WIN32 */
995 }
996
997 if (bytes_written < 0)
998 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
999
1000 return bytes_written;
1001}
1002#endif /* ! RIOT_VERSION && ! WITH_LWIP && ! WITH_CONTIKI */
1003
1004#define SIN6(A) ((struct sockaddr_in6 *)(A))
1005
1006void
1007coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
1008 *address = packet->payload;
1009 *length = packet->length;
1010}
1011
1012#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
1013/*
1014 * dgram
1015 * return +ve Number of bytes written.
1016 * -1 Error error in errno).
1017 * -2 ICMP error response
1018 */
1019ssize_t
1021 ssize_t len = -1;
1022
1023 assert(sock);
1024 assert(packet);
1025
1026 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
1027 return -1;
1028 } else {
1029 /* clear has-data flag */
1031 }
1032
1033 if (sock->flags & COAP_SOCKET_CONNECTED) {
1034#ifdef _WIN32
1035 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
1036#else
1037 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
1038#endif
1039 if (len < 0) {
1040#ifdef _WIN32
1041 coap_win_error_to_errno();
1042#endif /* _WIN32 */
1043 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1044 /* client-side ICMP destination unreachable, ignore it */
1045 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1046 sock->session ?
1047 coap_session_str(sock->session) : "",
1049 return -2;
1050 }
1051 if (errno != EAGAIN) {
1052 coap_log_warn("** %s: coap_socket_recv: %s\n",
1053 sock->session ?
1054 coap_session_str(sock->session) : "",
1056 }
1057 goto error;
1058 } else if (len > 0) {
1059 packet->length = (size_t)len;
1060 }
1061 } else {
1062#if defined(_WIN32)
1063 DWORD dwNumberOfBytesRecvd = 0;
1064 int r;
1065#endif /* _WIN32 */
1066#ifdef HAVE_STRUCT_CMSGHDR
1067 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
1068 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1069 struct cmsghdr *cmsg;
1070 struct msghdr mhdr;
1071 struct iovec iov[1];
1072
1073#if defined(__MINGW32__)
1074 iov[0].iov_base = (char *) packet->payload;
1075#else /* ! __MINGW32__ */
1076 iov[0].iov_base = packet->payload;
1077#endif /* defined(__MINGW32__) */
1078 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
1079
1080 memset(&mhdr, 0, sizeof(struct msghdr));
1081
1082 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
1083 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
1084
1085 mhdr.msg_iov = iov;
1086 mhdr.msg_iovlen = 1;
1087
1088 mhdr.msg_control = buf;
1089 mhdr.msg_controllen = sizeof(buf);
1090 /* set a big first length incase recvmsg() does not implement updating
1091 msg_control as well as preset the first cmsg with bad data */
1092 cmsg = (struct cmsghdr *)buf;
1093 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
1094 cmsg->cmsg_level = -1;
1095 cmsg->cmsg_type = -1;
1096
1097#if defined(_WIN32)
1098 if (!lpWSARecvMsg) {
1099 GUID wsaid = WSAID_WSARECVMSG;
1100 DWORD cbBytesReturned = 0;
1101 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
1102 sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
1103 coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
1104 return -1;
1105 }
1106 }
1107 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
1108 NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
1109 if (r == 0)
1110 len = (ssize_t)dwNumberOfBytesRecvd;
1111 else if (r == COAP_SOCKET_ERROR)
1112 coap_win_error_to_errno();
1113#else
1114 len = recvmsg(sock->fd, &mhdr, 0);
1115#endif
1116
1117#else /* ! HAVE_STRUCT_CMSGHDR */
1118 len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
1119 &packet->addr_info.remote.addr.sa,
1120 &packet->addr_info.remote.size);
1121#endif /* ! HAVE_STRUCT_CMSGHDR */
1122
1123 if (len < 0) {
1124#ifdef _WIN32
1125 coap_win_error_to_errno();
1126#endif /* _WIN32 */
1127 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
1128 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
1129 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
1130 sock->session ?
1131 coap_session_str(sock->session) : "",
1133 return 0;
1134 }
1135 if (errno != EAGAIN) {
1136 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
1137 }
1138 goto error;
1139 } else {
1140#ifdef HAVE_STRUCT_CMSGHDR
1141 int dst_found = 0;
1142
1143 packet->addr_info.remote.size = mhdr.msg_namelen;
1144 packet->length = (size_t)len;
1145
1146 /* Walk through ancillary data records until the local interface
1147 * is found where the data was received. */
1148 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
1149
1150#if COAP_IPV6_SUPPORT
1151 /* get the local interface for IPv6 */
1152 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
1153 union {
1154 uint8_t *c;
1155 struct in6_pktinfo *p;
1156 } u;
1157 u.c = CMSG_DATA(cmsg);
1158 packet->ifindex = (int)(u.p->ipi6_ifindex);
1159 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
1160 &u.p->ipi6_addr, sizeof(struct in6_addr));
1161 dst_found = 1;
1162 break;
1163 }
1164#endif /* COAP_IPV6_SUPPORT */
1165
1166#if COAP_IPV4_SUPPORT
1167 /* local interface for IPv4 */
1168#if defined(IP_PKTINFO)
1169 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
1170 union {
1171 uint8_t *c;
1172 struct in_pktinfo *p;
1173 } u;
1174 u.c = CMSG_DATA(cmsg);
1175 packet->ifindex = u.p->ipi_ifindex;
1176#if COAP_IPV6_SUPPORT
1177 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
1178 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
1179 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
1180 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
1181 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
1182 &u.p->ipi_addr, sizeof(struct in_addr));
1183 } else
1184#endif /* COAP_IPV6_SUPPORT */
1185 {
1186 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1187 &u.p->ipi_addr, sizeof(struct in_addr));
1188 }
1189 dst_found = 1;
1190 break;
1191 }
1192#endif /* IP_PKTINFO */
1193#if defined(IP_RECVDSTADDR)
1194 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
1195 packet->ifindex = (int)sock->fd;
1196 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1197 CMSG_DATA(cmsg), sizeof(struct in_addr));
1198 dst_found = 1;
1199 break;
1200 }
1201#endif /* IP_RECVDSTADDR */
1202#endif /* COAP_IPV4_SUPPORT */
1203 if (!dst_found) {
1204 /* cmsg_level / cmsg_type combination we do not understand
1205 (ignore preset case for bad recvmsg() not updating cmsg) */
1206 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1207 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1208 cmsg->cmsg_level, cmsg->cmsg_type);
1209 }
1210 }
1211 }
1212 if (!dst_found) {
1213 /* Not expected, but cmsg_level and cmsg_type don't match above and
1214 may need a new case */
1215 packet->ifindex = (int)sock->fd;
1216 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1217 &packet->addr_info.local.size) < 0) {
1218 coap_log_debug("Cannot determine local port\n");
1219 }
1220 }
1221#else /* ! HAVE_STRUCT_CMSGHDR */
1222 packet->length = (size_t)len;
1223 packet->ifindex = 0;
1224 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1225 &packet->addr_info.local.size) < 0) {
1226 coap_log_debug("Cannot determine local port\n");
1227 goto error;
1228 }
1229#endif /* ! HAVE_STRUCT_CMSGHDR */
1230 }
1231 }
1232
1233 if (len >= 0)
1234 return len;
1235error:
1236 return -1;
1237}
1238#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION */
1239
1240COAP_API unsigned int
1242 unsigned int ret;
1243
1244 coap_lock_lock(ctx, return 0);
1245 ret = coap_io_prepare_epoll_lkd(ctx, now);
1246 coap_lock_unlock(ctx);
1247 return ret;
1248}
1249
1250unsigned int
1252#ifndef COAP_EPOLL_SUPPORT
1253 (void)ctx;
1254 (void)now;
1255 coap_log_emerg("coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1256 return 0;
1257#else /* COAP_EPOLL_SUPPORT */
1258 coap_socket_t *sockets[1];
1259 unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1260 unsigned int num_sockets;
1261 unsigned int timeout;
1262
1264 /* Use the common logic */
1265 timeout = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, &num_sockets, now);
1266 /* Save when the next expected I/O is to take place */
1267 ctx->next_timeout = timeout ? now + timeout : 0;
1268 if (ctx->eptimerfd != -1) {
1269 struct itimerspec new_value;
1270 int ret;
1271
1272 memset(&new_value, 0, sizeof(new_value));
1273 coap_ticks(&now);
1274 if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1275 coap_tick_t rem_timeout = ctx->next_timeout - now;
1276 /* Need to trigger an event on ctx->eptimerfd in the future */
1277 new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1278 new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1279 1000000;
1280 }
1281#ifdef COAP_DEBUG_WAKEUP_TIMES
1282 coap_log_debug("****** Next wakeup time %3ld.%09ld\n",
1283 new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1284#endif /* COAP_DEBUG_WAKEUP_TIMES */
1285 /* reset, or specify a future time for eptimerfd to trigger */
1286 ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1287 if (ret == -1) {
1288 coap_log_err("%s: timerfd_settime failed: %s (%d)\n",
1289 "coap_io_prepare_epoll",
1290 coap_socket_strerror(), errno);
1291 }
1292 }
1293 return timeout;
1294#endif /* COAP_EPOLL_SUPPORT */
1295}
1296
1297/*
1298 * return 0 No i/o pending
1299 * +ve millisecs to next i/o activity
1300 */
1301COAP_API unsigned int
1303 coap_socket_t *sockets[],
1304 unsigned int max_sockets,
1305 unsigned int *num_sockets,
1306 coap_tick_t now) {
1307 unsigned int ret;
1308
1309 coap_lock_lock(ctx, return 0);
1310 ret = coap_io_prepare_io_lkd(ctx, sockets, max_sockets, num_sockets, now);
1311 coap_lock_unlock(ctx);
1312 return ret;
1313}
1314
1315/*
1316 * return 0 No i/o pending
1317 * +ve millisecs to next i/o activity
1318 */
1319unsigned int
1321 coap_socket_t *sockets[],
1322 unsigned int max_sockets,
1323 unsigned int *num_sockets,
1324 coap_tick_t now) {
1325 coap_queue_t *nextpdu;
1326 coap_session_t *s, *rtmp;
1327 coap_tick_t timeout = 0;
1328 coap_tick_t s_timeout;
1329#if COAP_SERVER_SUPPORT
1330 int check_dtls_timeouts = 0;
1331#endif /* COAP_SERVER_SUPPORT */
1332#if defined(COAP_EPOLL_SUPPORT) || defined(WITH_LWIP) || defined(RIOT_VERSION)
1333 (void)sockets;
1334 (void)max_sockets;
1335#endif /* COAP_EPOLL_SUPPORT || WITH_LWIP || RIOT_VERSION*/
1336
1338 *num_sockets = 0;
1339
1340#if COAP_SERVER_SUPPORT
1341 /* Check to see if we need to send off any Observe requests */
1343
1344#if COAP_ASYNC_SUPPORT
1345 /* Check to see if we need to send off any Async requests */
1346 timeout = coap_check_async(ctx, now);
1347#endif /* COAP_ASYNC_SUPPORT */
1348#endif /* COAP_SERVER_SUPPORT */
1349
1350 /* Check to see if we need to send off any retransmit request */
1351 nextpdu = coap_peek_next(ctx);
1352 while (nextpdu && now >= ctx->sendqueue_basetime &&
1353 nextpdu->t <= now - ctx->sendqueue_basetime) {
1354 coap_retransmit(ctx, coap_pop_next(ctx));
1355 nextpdu = coap_peek_next(ctx);
1356 }
1357 if (nextpdu && (timeout == 0 ||
1358 nextpdu->t - (now - ctx->sendqueue_basetime) < timeout))
1359 timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1360
1361 /* Check for DTLS timeouts */
1362 if (ctx->dtls_context) {
1365 if (tls_timeout > 0) {
1366 if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1367 tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1368 coap_log_debug("** DTLS global timeout set to %dms\n",
1369 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1370 if (timeout == 0 || tls_timeout - now < timeout)
1371 timeout = tls_timeout - now;
1372 }
1373#if COAP_SERVER_SUPPORT
1374 } else {
1375 check_dtls_timeouts = 1;
1376#endif /* COAP_SERVER_SUPPORT */
1377 }
1378 }
1379#if COAP_PROXY_SUPPORT
1380 if (coap_proxy_check_timeouts(ctx, now, &s_timeout)) {
1381 if (timeout == 0 || s_timeout < timeout)
1382 timeout = s_timeout;
1383 }
1384#endif /* COAP_PROXY_SUPPORT */
1385#if COAP_SERVER_SUPPORT
1386 coap_endpoint_t *ep;
1387 coap_tick_t session_timeout;
1388
1389 if (ctx->session_timeout > 0)
1390 session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1391 else
1393
1394 LL_FOREACH(ctx->endpoint, ep) {
1395#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1397 if (*num_sockets < max_sockets)
1398 sockets[(*num_sockets)++] = &ep->sock;
1399 }
1400#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1401 SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1402 /* Check whether any idle server sessions should be released */
1403 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1404 s->delayqueue == NULL &&
1405 (s->last_rx_tx + session_timeout <= now ||
1409 } else {
1410 if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1411 s->delayqueue == NULL) {
1412 s_timeout = (s->last_rx_tx + session_timeout) - now;
1413 if (timeout == 0 || s_timeout < timeout)
1414 timeout = s_timeout;
1415 }
1416 /* Make sure the session object is not deleted in any callbacks */
1418 /* Check any DTLS timeouts and expire if appropriate */
1419 if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE &&
1420 s->proto == COAP_PROTO_DTLS && s->tls) {
1421 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1422 while (tls_timeout > 0 && tls_timeout <= now) {
1423 coap_log_debug("** %s: DTLS retransmit timeout\n",
1424 coap_session_str(s));
1426 goto release_1;
1427
1428 if (s->tls)
1429 tls_timeout = coap_dtls_get_timeout(s, now);
1430 else {
1431 tls_timeout = 0;
1432 timeout = 1;
1433 }
1434 }
1435 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1436 timeout = tls_timeout - now;
1437 }
1438 /* Check if any server large receives are missing blocks */
1439 if (s->lg_srcv) {
1440 if (coap_block_check_lg_srcv_timeouts(s, now, &s_timeout)) {
1441 if (timeout == 0 || s_timeout < timeout)
1442 timeout = s_timeout;
1443 }
1444 }
1445 /* Check if any server large sending have timed out */
1446 if (s->lg_xmit) {
1447 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1448 if (timeout == 0 || s_timeout < timeout)
1449 timeout = s_timeout;
1450 }
1451 }
1452#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1454 if (*num_sockets < max_sockets)
1455 sockets[(*num_sockets)++] = &s->sock;
1456 }
1457#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1458#if COAP_Q_BLOCK_SUPPORT
1459 /*
1460 * Check if any server large transmits have hit MAX_PAYLOAD and need
1461 * restarting
1462 */
1463 if (s->lg_xmit) {
1464 s_timeout = coap_block_check_q_block2_xmit(s, now);
1465 if (timeout == 0 || s_timeout < timeout)
1466 timeout = s_timeout;
1467 }
1468#endif /* COAP_Q_BLOCK_SUPPORT */
1469release_1:
1471 }
1472 }
1473 }
1474#endif /* COAP_SERVER_SUPPORT */
1475#if COAP_CLIENT_SUPPORT
1476 SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1477 if (s->type == COAP_SESSION_TYPE_CLIENT &&
1479 ctx->ping_timeout > 0) {
1480 if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1481 /* Time to send a ping */
1483 /* Some issue - not safe to continue processing */
1484 continue;
1485 if (s->last_ping > 0 && s->last_pong < s->last_ping) {
1487 }
1488 s->last_rx_tx = now;
1489 s->last_ping = now;
1490 }
1491 s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1492 if (timeout == 0 || s_timeout < timeout)
1493 timeout = s_timeout;
1494 }
1495
1496#if !COAP_DISABLE_TCP
1498 s->state == COAP_SESSION_STATE_CSM && ctx->csm_timeout_ms > 0) {
1499 if (s->csm_tx == 0) {
1500 s->csm_tx = now;
1501 s_timeout = (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000;
1502 } else if (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000 <= now) {
1503 /* timed out */
1504 s_timeout = 0;
1505 } else {
1506 s_timeout = (s->csm_tx + (ctx->csm_timeout_ms * COAP_TICKS_PER_SECOND) / 1000) - now;
1507 }
1508 if ((timeout == 0 || s_timeout < timeout) && s_timeout != 0)
1509 timeout = s_timeout;
1510 }
1511#endif /* !COAP_DISABLE_TCP */
1512
1513 /* Make sure the session object is not deleted in any callbacks */
1515 /* Check any DTLS timeouts and expire if appropriate */
1517 s->proto == COAP_PROTO_DTLS && s->tls) {
1518 coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1519 while (tls_timeout > 0 && tls_timeout <= now) {
1520 coap_log_debug("** %s: DTLS retransmit timeout\n", coap_session_str(s));
1522 goto release_2;
1523
1524 if (s->tls)
1525 tls_timeout = coap_dtls_get_timeout(s, now);
1526 else {
1527 tls_timeout = 0;
1528 timeout = 1;
1529 }
1530 }
1531 if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1532 timeout = tls_timeout - now;
1533 }
1534
1535 /* Check if any client large receives are missing blocks */
1536 if (s->lg_crcv) {
1537 if (coap_block_check_lg_crcv_timeouts(s, now, &s_timeout)) {
1538 if (timeout == 0 || s_timeout < timeout)
1539 timeout = s_timeout;
1540 }
1541 }
1542 /* Check if any client large sending have timed out */
1543 if (s->lg_xmit) {
1544 if (coap_block_check_lg_xmit_timeouts(s, now, &s_timeout)) {
1545 if (timeout == 0 || s_timeout < timeout)
1546 timeout = s_timeout;
1547 }
1548 }
1549#if COAP_Q_BLOCK_SUPPORT
1550 /*
1551 * Check if any client large transmits have hit MAX_PAYLOAD and need
1552 * restarting
1553 */
1554 if (s->lg_xmit) {
1555 s_timeout = coap_block_check_q_block1_xmit(s, now);
1556 if (timeout == 0 || s_timeout < timeout)
1557 timeout = s_timeout;
1558 }
1559#endif /* COAP_Q_BLOCK_SUPPORT */
1560
1561#if !defined(COAP_EPOLL_SUPPORT) && !defined(WITH_LWIP) && !defined(RIOT_VERSION)
1562 assert(s->ref > 1);
1563 if (s->sock.flags & (COAP_SOCKET_WANT_READ |
1566 if (*num_sockets < max_sockets)
1567 sockets[(*num_sockets)++] = &s->sock;
1568 }
1569#endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */
1570release_2:
1572 }
1573#endif /* COAP_CLIENT_SUPPORT */
1574
1575 return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1576}
1577
1578#if !defined(WITH_LWIP) && !defined(CONTIKI) && !defined(RIOT_VERSION)
1579COAP_API int
1580coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1581 int ret;
1582
1583 coap_lock_lock(ctx, return 0);
1584 ret = coap_io_process_lkd(ctx, timeout_ms);
1585 coap_lock_unlock(ctx);
1586 return ret;
1587}
1588
1589int
1590coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms) {
1591 return coap_io_process_with_fds_lkd(ctx, timeout_ms, 0, NULL, NULL, NULL);
1592}
1593
1594COAP_API int
1596 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1597 fd_set *eexceptfds) {
1598 int ret;
1599
1600 coap_lock_lock(ctx, return 0);
1601 ret = coap_io_process_with_fds_lkd(ctx, timeout_ms, enfds, ereadfds, ewritefds,
1602 eexceptfds);
1603 coap_lock_unlock(ctx);
1604 return ret;
1605}
1606
1607int
1609 int enfds, fd_set *ereadfds, fd_set *ewritefds,
1610 fd_set *eexceptfds) {
1611 coap_fd_t nfds = 0;
1612 coap_tick_t before, now;
1613 unsigned int timeout;
1614#ifndef COAP_EPOLL_SUPPORT
1615 struct timeval tv;
1616 int result;
1617 unsigned int i;
1618#endif /* ! COAP_EPOLL_SUPPORT */
1619
1621 coap_ticks(&before);
1622
1623#ifndef COAP_EPOLL_SUPPORT
1624
1625 timeout = coap_io_prepare_io_lkd(ctx, ctx->sockets,
1626 (sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
1627 &ctx->num_sockets, before);
1628
1629 if (ereadfds) {
1630 ctx->readfds = *ereadfds;
1631 nfds = enfds;
1632 } else {
1633 FD_ZERO(&ctx->readfds);
1634 }
1635 if (ewritefds) {
1636 ctx->writefds = *ewritefds;
1637 nfds = enfds;
1638 } else {
1639 FD_ZERO(&ctx->writefds);
1640 }
1641 if (eexceptfds) {
1642 ctx->exceptfds = *eexceptfds;
1643 nfds = enfds;
1644 } else {
1645 FD_ZERO(&ctx->exceptfds);
1646 }
1647 for (i = 0; i < ctx->num_sockets; i++) {
1648 if (ctx->sockets[i]->fd + 1 > nfds)
1649 nfds = ctx->sockets[i]->fd + 1;
1650 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ)
1651 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1652 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1653 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1654#if !COAP_DISABLE_TCP
1655 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1656 FD_SET(ctx->sockets[i]->fd, &ctx->readfds);
1657 if (ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1658 FD_SET(ctx->sockets[i]->fd, &ctx->writefds);
1659 FD_SET(ctx->sockets[i]->fd, &ctx->exceptfds);
1660 }
1661#endif /* !COAP_DISABLE_TCP */
1662 }
1663
1664 if (timeout_ms == COAP_IO_NO_WAIT) {
1665 tv.tv_usec = 0;
1666 tv.tv_sec = 0;
1667 timeout = 1;
1668 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1669 ;
1670 } else {
1671 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1672 timeout = timeout_ms;
1673 tv.tv_usec = (timeout % 1000) * 1000;
1674 tv.tv_sec = (long)(timeout / 1000);
1675 }
1676
1677 /* Unlock so that other threads can lock/update ctx */
1678 coap_lock_unlock(ctx);
1679
1680 result = select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds,
1681 timeout > 0 ? &tv : NULL);
1682
1683 coap_lock_lock(ctx, return -1);
1684
1685 if (result < 0) { /* error */
1686#ifdef _WIN32
1687 coap_win_error_to_errno();
1688#endif
1689 if (errno != EINTR) {
1691 return -1;
1692 }
1693 }
1694 if (ereadfds) {
1695 *ereadfds = ctx->readfds;
1696 }
1697 if (ewritefds) {
1698 *ewritefds = ctx->writefds;
1699 }
1700 if (eexceptfds) {
1701 *eexceptfds = ctx->exceptfds;
1702 }
1703
1704 if (result > 0) {
1705#if COAP_THREAD_SAFE
1706 /* Need to refresh what is available to read / write etc. */
1707 tv.tv_usec = 0;
1708 tv.tv_sec = 0;
1709 select((int)nfds, &ctx->readfds, &ctx->writefds, &ctx->exceptfds, &tv);
1710#endif /* COAP_THREAD_SAFE */
1711 for (i = 0; i < ctx->num_sockets; i++) {
1712 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_READ) &&
1713 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1715#if !COAP_DISABLE_TCP
1716 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) &&
1717 FD_ISSET(ctx->sockets[i]->fd, &ctx->readfds))
1719 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_WRITE) &&
1720 FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds))
1722 if ((ctx->sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) &&
1723 (FD_ISSET(ctx->sockets[i]->fd, &ctx->writefds) ||
1724 FD_ISSET(ctx->sockets[i]->fd, &ctx->exceptfds)))
1726#endif /* !COAP_DISABLE_TCP */
1727 }
1728 }
1729
1730 coap_ticks(&now);
1731 coap_io_do_io_lkd(ctx, now);
1732
1733#else /* COAP_EPOLL_SUPPORT */
1734 (void)ereadfds;
1735 (void)ewritefds;
1736 (void)eexceptfds;
1737 (void)enfds;
1738
1739 timeout = coap_io_prepare_epoll_lkd(ctx, before);
1740
1741 do {
1742 struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1743 int etimeout;
1744
1745 /* Potentially adjust based on what the caller wants */
1746 if (timeout_ms == COAP_IO_NO_WAIT) {
1747 /* Need to return immediately from epoll_wait() */
1748 etimeout = 0;
1749 } else if (timeout == 0 && timeout_ms == COAP_IO_WAIT) {
1750 /*
1751 * Nothing found in coap_io_prepare_epoll_lkd() and COAP_IO_WAIT set,
1752 * so wait forever in epoll_wait().
1753 */
1754 etimeout = -1;
1755 } else {
1756 etimeout = timeout;
1757 if (timeout == 0 || (timeout_ms != COAP_IO_WAIT && timeout_ms < timeout))
1758 etimeout = timeout_ms;
1759 if (etimeout < 0) {
1760 /*
1761 * If timeout > INT_MAX, epoll_wait() cannot wait longer than this as
1762 * it has int timeout parameter
1763 */
1764 etimeout = INT_MAX;
1765 }
1766 }
1767
1768 /* Unlock so that other threads can lock/update ctx */
1769 coap_lock_unlock(ctx);
1770
1771 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1772 if (nfds < 0) {
1773 if (errno != EINTR) {
1774 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1775 coap_socket_strerror(), nfds);
1776 }
1777 coap_lock_lock(ctx, return -1);
1778 break;
1779 }
1780
1781#if COAP_THREAD_SAFE
1782 /* Need to refresh what is available to read / write etc. */
1783 nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, 0);
1784 if (nfds < 0) {
1785 if (errno != EINTR) {
1786 coap_log_err("epoll_wait: unexpected error: %s (%d)\n",
1787 coap_socket_strerror(), nfds);
1788 }
1789 coap_lock_lock(ctx, return -1);
1790 break;
1791 }
1792#endif /* COAP_THREAD_SAFE */
1793 coap_lock_lock(ctx, return -1);
1794
1795 coap_io_do_epoll_lkd(ctx, events, nfds);
1796
1797 /*
1798 * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1799 * incase we have to do another iteration
1800 * (COAP_MAX_EPOLL_EVENTS insufficient)
1801 */
1802 timeout_ms = COAP_IO_NO_WAIT;
1803
1804 /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1805 } while (nfds == COAP_MAX_EPOLL_EVENTS);
1806
1807#endif /* COAP_EPOLL_SUPPORT */
1808#if COAP_SERVER_SUPPORT
1810#endif /* COAP_SERVER_SUPPORT */
1811 coap_ticks(&now);
1812#if COAP_ASYNC_SUPPORT
1813 /* Check to see if we need to send off any Async requests as delay might
1814 have been updated */
1815 coap_check_async(ctx, now);
1816 coap_ticks(&now);
1817#endif /* COAP_ASYNC_SUPPORT */
1818
1819 return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1820}
1821#endif /* ! WITH_LWIP && ! WITH_CONTIKI && ! RIOT_VERSION*/
1822
1823COAP_API int
1825 int ret;
1826
1827 coap_lock_lock(context, return 0);
1828 ret = coap_io_pending_lkd(context);
1829 coap_lock_unlock(context);
1830 return ret;
1831}
1832
1833/*
1834 * return 1 I/O pending
1835 * 0 No I/O pending
1836 */
1837int
1839 coap_session_t *s, *rtmp;
1840#if COAP_SERVER_SUPPORT
1841 coap_endpoint_t *ep;
1842#endif /* COAP_SERVER_SUPPORT */
1843
1844 if (!context)
1845 return 0;
1846 coap_lock_check_locked(context);
1847 if (coap_io_process_lkd(context, COAP_IO_NO_WAIT) < 0)
1848 return 0;
1849
1850 if (context->sendqueue)
1851 return 1;
1852#if COAP_SERVER_SUPPORT
1853 LL_FOREACH(context->endpoint, ep) {
1854 SESSIONS_ITER(ep->sessions, s, rtmp) {
1855 if (s->delayqueue)
1856 return 1;
1857 if (s->lg_xmit)
1858 return 1;
1859 if (s->lg_srcv)
1860 return 1;
1861 }
1862 }
1863#endif /* COAP_SERVER_SUPPORT */
1864#if COAP_CLIENT_SUPPORT
1865 SESSIONS_ITER(context->sessions, s, rtmp) {
1866 if (s->delayqueue)
1867 return 1;
1868 if (s->lg_xmit)
1869 return 1;
1870 if (s->lg_crcv)
1871 return 1;
1872 }
1873#endif /* COAP_CLIENT_SUPPORT */
1874 return 0;
1875}
1876
1877#ifdef _WIN32
1878const char *
1879coap_socket_format_errno(int error) {
1880 static char szError[256];
1881 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1882 NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL,
1883 SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError),
1884 NULL) == 0)
1885 strcpy(szError, "Unknown error");
1886 return szError;
1887}
1888
1889const char *
1891 return coap_socket_format_errno(WSAGetLastError());
1892}
1893#else /* _WIN32 */
1894const char *
1896 return strerror(error);
1897}
1898const char *
1900 return coap_socket_format_errno(errno);
1901}
1902#endif /* _WIN32 */
1903
1904#undef SIN6
void coap_address_set_port(coap_address_t *addr, uint16_t port)
Set the port field of addr to port (in host byte order).
int coap_is_bcast(const coap_address_t *a)
Checks if given address a denotes a broadcast address.
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
uint16_t coap_address_get_port(const coap_address_t *addr)
Returns the port from addr in host byte order.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
#define COAP_IPV4_SUPPORT
const char * coap_socket_format_errno(int error)
Definition coap_io.c:1895
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
const char * coap_socket_strerror(void)
Definition coap_io.c:1899
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition coap_io.c:1020
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:823
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:1007
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:770
#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_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:228
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition coap_notls.c:223
int coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition coap_notls.c:237
#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:2382
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:1838
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:2317
int coap_io_process_lkd(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1590
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:1608
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:1320
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:1251
COAP_API int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition coap_io.c:1580
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:1824
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:1302
#define COAP_IO_NO_WAIT
Definition coap_net.h:631
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:1241
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:1595
#define COAP_IO_WAIT
Definition coap_net.h:630
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:4378
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:1909
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:218
@ 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:316
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::@015050156312105222052310207033242145215103030104 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]
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