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