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