libcoap 4.3.2rc2

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