libcoap  4.3.0
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-2019 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 
11 #include "coap3/coap_internal.h"
12 
13 #ifdef HAVE_STDIO_H
14 # include <stdio.h>
15 #endif
16 
17 #ifdef HAVE_SYS_SELECT_H
18 # include <sys/select.h>
19 #endif
20 #ifdef HAVE_SYS_SOCKET_H
21 # include <sys/socket.h>
22 # define OPTVAL_T(t) (t)
23 # define OPTVAL_GT(t) (t)
24 #endif
25 #ifdef HAVE_SYS_IOCTL_H
26  #include <sys/ioctl.h>
27 #endif
28 #ifdef HAVE_NETINET_IN_H
29 # include <netinet/in.h>
30 #endif
31 #ifdef HAVE_WS2TCPIP_H
32 #include <ws2tcpip.h>
33 # define OPTVAL_T(t) (const char*)(t)
34 # define OPTVAL_GT(t) (char*)(t)
35 # undef CMSG_DATA
36 # define CMSG_DATA WSA_CMSG_DATA
37 #endif
38 #ifdef HAVE_SYS_UIO_H
39 # include <sys/uio.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <errno.h>
45 #ifdef COAP_EPOLL_SUPPORT
46 #include <sys/epoll.h>
47 #include <sys/timerfd.h>
48 #ifdef HAVE_LIMITS_H
49 #include <limits.h>
50 #endif
51 #endif /* COAP_EPOLL_SUPPORT */
52 
53 #ifdef WITH_CONTIKI
54 # include "uip.h"
55 #endif
56 
57 #if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
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 KTINFO 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 #ifdef WITH_CONTIKI
78 static int ep_initialized = 0;
79 
82  static coap_endpoint_t ep;
83 
84  if (ep_initialized) {
85  return NULL;
86  } else {
87  ep_initialized = 1;
88  return &ep;
89  }
90 }
91 
92 void
94  ep_initialized = 0;
95 }
96 
97 int
99  const coap_address_t *listen_addr,
100  coap_address_t *bound_addr) {
101  sock->conn = udp_new(NULL, 0, NULL);
102 
103  if (!sock->conn) {
104  coap_log(LOG_WARNING, "coap_socket_bind_udp");
105  return 0;
106  }
107 
108  coap_address_init(bound_addr);
109  uip_ipaddr_copy(&bound_addr->addr, &listen_addr->addr);
110  bound_addr->port = listen_addr->port;
111  udp_bind((struct uip_udp_conn *)sock->conn, bound_addr->port);
112  return 1;
113 }
114 
115 int
117  const coap_address_t *local_if,
118  const coap_address_t *server,
119  int default_port,
120  coap_address_t *local_addr,
121  coap_address_t *remote_addr) {
122  return 0;
123 }
124 
125 ssize_t
126 coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
127  return -1;
128 }
129 
130 ssize_t
131 coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
132  return -1;
133 }
134 
135 void coap_socket_close(coap_socket_t *sock) {
136  if (sock->conn)
137  uip_udp_remove((struct uip_udp_conn *)sock->conn);
138  sock->flags = COAP_SOCKET_EMPTY;
139 }
140 
141 #else
142 
146 }
147 
148 void
151 }
152 
153 int
155  const coap_address_t *listen_addr,
156  coap_address_t *bound_addr) {
157 #ifndef RIOT_VERSION
158  int on = 1, off = 0;
159 #endif /* RIOT_VERSION */
160 #ifdef _WIN32
161  u_long u_on = 1;
162 #endif
163 
164  sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
165 
166  if (sock->fd == COAP_INVALID_SOCKET) {
168  "coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
169  goto error;
170  }
171 #ifndef RIOT_VERSION
172 #ifdef _WIN32
173  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
174 #else
175  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
176 #endif
178  "coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
179  }
180 
181 #ifndef RIOT_VERSION
182  if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
184  "coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
186 #endif /* RIOT_VERSION */
187 
188  switch (listen_addr->addr.sa.sa_family) {
189  case AF_INET:
190  if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
192  "coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
194  break;
195  case AF_INET6:
196  /* Configure the socket as dual-stacked */
197  if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
199  "coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
201 #if !defined(ESPIDF_VERSION)
202  if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
204  "coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
206 #endif /* !defined(ESPIDF_VERSION) */
207  setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
208  /* ignore error, because likely cause is that IPv4 is disabled at the os
209  level */
210  break;
211  default:
212  coap_log(LOG_ALERT, "coap_socket_bind_udp: unsupported sa_family\n");
213  break;
214  }
215 #endif /* RIOT_VERSION */
216 
217  if (bind(sock->fd, &listen_addr->addr.sa,
218  listen_addr->addr.sa.sa_family == AF_INET ?
219  (socklen_t)sizeof(struct sockaddr_in) :
220  (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
221  coap_log(LOG_WARNING, "coap_socket_bind_udp: bind: %s\n",
223  goto error;
224  }
225 
226  bound_addr->size = (socklen_t)sizeof(*bound_addr);
227  if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
229  "coap_socket_bind_udp: getsockname: %s\n",
231  goto error;
232  }
233 
234  return 1;
235 
236 error:
237  coap_socket_close(sock);
238  return 0;
239 }
240 
241 int
243  const coap_address_t *local_if,
244  const coap_address_t *server,
245  int default_port,
246  coap_address_t *local_addr,
247  coap_address_t *remote_addr) {
248 #ifndef RIOT_VERSION
249  int on = 1;
250  int off = 0;
251 #endif /* RIOT_VERSION */
252 #ifdef _WIN32
253  u_long u_on = 1;
254 #endif
255  coap_address_t connect_addr;
256  int is_mcast = coap_is_mcast(server);
257  coap_address_copy(&connect_addr, server);
258 
260  sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
261 
262  if (sock->fd == COAP_INVALID_SOCKET) {
263  coap_log(LOG_WARNING, "coap_socket_connect_udp: socket: %s\n",
265  goto error;
266  }
267 
268 #ifndef RIOT_VERSION
269 #ifdef _WIN32
270  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
271 #else
272  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
273 #endif
274  coap_log(LOG_WARNING, "coap_socket_connect_udp: ioctl FIONBIO: %s\n",
276  }
277 #endif /* RIOT_VERSION */
278 
279  switch (connect_addr.addr.sa.sa_family) {
280  case AF_INET:
281  if (connect_addr.addr.sin.sin_port == 0)
282  connect_addr.addr.sin.sin_port = htons(default_port);
283  break;
284  case AF_INET6:
285  if (connect_addr.addr.sin6.sin6_port == 0)
286  connect_addr.addr.sin6.sin6_port = htons(default_port);
287 #ifndef RIOT_VERSION
288  /* Configure the socket as dual-stacked */
289  if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
291  "coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
293 #endif /* RIOT_VERSION */
294  break;
295  default:
296  coap_log(LOG_ALERT, "coap_socket_connect_udp: unsupported sa_family\n");
297  break;
298  }
299 
300  if (local_if && local_if->addr.sa.sa_family) {
301 #ifndef RIOT_VERSION
302  if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
304  "coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
306 #endif /* RIOT_VERSION */
307  if (bind(sock->fd, &local_if->addr.sa,
308  local_if->addr.sa.sa_family == AF_INET ?
309  (socklen_t)sizeof(struct sockaddr_in) :
310  (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
311  coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n",
313  goto error;
314  }
315  }
316 
317  /* special treatment for sockets that are used for multicast communication */
318  if (is_mcast) {
319  if (!(local_if && local_if->addr.sa.sa_family)) {
320  /* Bind to a (unused) port to simplify logging */
321  coap_address_t bind_addr;
322 
323  coap_address_init(&bind_addr);
324  bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
325  if (bind(sock->fd, &bind_addr.addr.sa,
326  bind_addr.addr.sa.sa_family == AF_INET ?
327  (socklen_t)sizeof(struct sockaddr_in) :
328  (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
329  coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n",
331  goto error;
332  }
333  }
334  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
336  "coap_socket_connect_udp: getsockname for multicast socket: %s\n",
338  }
339  coap_address_copy(remote_addr, &connect_addr);
340  sock->flags |= COAP_SOCKET_MULTICAST;
341  return 1;
342  }
343 
344  if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
345  coap_log(LOG_WARNING, "coap_socket_connect_udp: connect: %s\n",
347  goto error;
348  }
349 
350  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
351  coap_log(LOG_WARNING, "coap_socket_connect_udp: getsockname: %s\n",
353  }
354 
355  if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
356  coap_log(LOG_WARNING, "coap_socket_connect_udp: getpeername: %s\n",
358  }
359 
360  sock->flags |= COAP_SOCKET_CONNECTED;
361  return 1;
362 
363 error:
364  coap_socket_close(sock);
365  return 0;
366 }
367 
369  if (sock->fd != COAP_INVALID_SOCKET) {
370 #ifdef COAP_EPOLL_SUPPORT
371  coap_context_t *context = sock->session ? sock->session->context :
372  sock->endpoint ? sock->endpoint->context : NULL;
373  if (context != NULL) {
374  int ret;
375  struct epoll_event event;
376 
377  /* Kernels prior to 2.6.9 expect non NULL event parameter */
378  ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
379  if (ret == -1) {
381  "%s: epoll_ctl DEL failed: %s (%d)\n",
382  "coap_socket_close",
383  coap_socket_strerror(), errno);
384  }
385  }
386  sock->endpoint = NULL;
387  sock->session = NULL;
388 #endif /* COAP_EPOLL_SUPPORT */
389  coap_closesocket(sock->fd);
390  sock->fd = COAP_INVALID_SOCKET;
391  }
392  sock->flags = COAP_SOCKET_EMPTY;
393 }
394 
395 #ifdef COAP_EPOLL_SUPPORT
396 void
398  uint32_t events,
399  const char *func
400 ) {
401  int ret;
402  struct epoll_event event;
403  coap_context_t *context;
404 
405  if (sock == NULL)
406  return;
407 
408  context = sock->session ? sock->session->context :
409  sock->endpoint ? sock->endpoint->context : NULL;
410  if (context == NULL)
411  return;
412 
413  event.events = events;
414  event.data.ptr = sock;
415 
416  ret = epoll_ctl(context->epfd, EPOLL_CTL_MOD, sock->fd, &event);
417  if (ret == -1) {
419  "%s: epoll_ctl MOD failed: %s (%d)\n",
420  func,
421  coap_socket_strerror(), errno);
422  }
423 }
424 #endif /* COAP_EPOLL_SUPPORT */
425 
426 ssize_t
427 coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
428  ssize_t r;
429 
431 #ifdef _WIN32
432  r = send(sock->fd, (const char *)data, (int)data_len, 0);
433 #else
434  r = send(sock->fd, data, data_len, 0);
435 #endif
436  if (r == COAP_SOCKET_ERROR) {
437 #ifdef _WIN32
438  if (WSAGetLastError() == WSAEWOULDBLOCK) {
439 #elif EAGAIN != EWOULDBLOCK
440  if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
441 #else
442  if (errno==EAGAIN || errno == EINTR) {
443 #endif
444  sock->flags |= COAP_SOCKET_WANT_WRITE;
445 #ifdef COAP_EPOLL_SUPPORT
446  coap_epoll_ctl_mod(sock,
447  EPOLLOUT |
448  ((sock->flags & COAP_SOCKET_WANT_READ) ?
449  EPOLLIN : 0),
450  __func__);
451 #endif /* COAP_EPOLL_SUPPORT */
452  return 0;
453  }
454  if (errno == EPIPE || errno == ECONNRESET) {
455  coap_log(LOG_INFO, "coap_socket_write: send: %s\n",
457  }
458  else {
459  coap_log(LOG_WARNING, "coap_socket_write: send: %s\n",
461  }
462  return -1;
463  }
464  if (r < (ssize_t)data_len) {
465  sock->flags |= COAP_SOCKET_WANT_WRITE;
466 #ifdef COAP_EPOLL_SUPPORT
467  coap_epoll_ctl_mod(sock,
468  EPOLLOUT |
469  ((sock->flags & COAP_SOCKET_WANT_READ) ?
470  EPOLLIN : 0),
471  __func__);
472 #endif /* COAP_EPOLL_SUPPORT */
473  }
474  return r;
475 }
476 
477 ssize_t
478 coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
479  ssize_t r;
480 #ifdef _WIN32
481  int error;
482 #endif
483 
484 #ifdef _WIN32
485  r = recv(sock->fd, (char *)data, (int)data_len, 0);
486 #else
487  r = recv(sock->fd, data, data_len, 0);
488 #endif
489  if (r == 0) {
490  /* graceful shutdown */
491  sock->flags &= ~COAP_SOCKET_CAN_READ;
492  return -1;
493  } else if (r == COAP_SOCKET_ERROR) {
494  sock->flags &= ~COAP_SOCKET_CAN_READ;
495 #ifdef _WIN32
496  error = WSAGetLastError();
497  if (error == WSAEWOULDBLOCK) {
498 #elif EAGAIN != EWOULDBLOCK
499  if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
500 #else
501  if (errno==EAGAIN || errno == EINTR) {
502 #endif
503  return 0;
504  }
505 #ifdef _WIN32
506  if (error != WSAECONNRESET)
507 #else
508  if (errno != ECONNRESET)
509 #endif
510  coap_log(LOG_WARNING, "coap_socket_read: recv: %s\n",
512  return -1;
513  }
514  if (r < (ssize_t)data_len)
515  sock->flags &= ~COAP_SOCKET_CAN_READ;
516  return r;
517 }
518 
519 #endif /* WITH_CONTIKI */
520 
521 #if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
522 /* define struct in6_pktinfo and struct in_pktinfo if not available
523  FIXME: check with configure
524 */
525 struct in6_pktinfo {
526  struct in6_addr ipi6_addr; /* src/dst IPv6 address */
527  unsigned int ipi6_ifindex; /* send/recv interface index */
528 };
529 
530 struct in_pktinfo {
532  struct in_addr ipi_spec_dst;
533  struct in_addr ipi_addr;
534 };
535 #endif
536 
537 #if !defined(WITH_CONTIKI) && !defined(SOL_IP)
538 /* Solaris expects level IPPROTO_IP for ancillary data. */
539 #define SOL_IP IPPROTO_IP
540 #endif
541 
542 #if defined(_WIN32)
543 #include <mswsock.h>
544 static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
545 /* Map struct WSABUF fields to their posix counterpart */
546 #define msghdr _WSAMSG
547 #define msg_name name
548 #define msg_namelen namelen
549 #define msg_iov lpBuffers
550 #define msg_iovlen dwBufferCount
551 #define msg_control Control.buf
552 #define msg_controllen Control.len
553 #define iovec _WSABUF
554 #define iov_base buf
555 #define iov_len len
556 #define iov_len_t u_long
557 #undef CMSG_DATA
558 #define CMSG_DATA WSA_CMSG_DATA
559 #define ipi_spec_dst ipi_addr
560 #pragma warning( disable : 4116 )
561 #else
562 #define iov_len_t size_t
563 #endif
564 
565 #if defined(_CYGWIN_ENV)
566 #define ipi_spec_dst ipi_addr
567 #endif
568 
569 #ifndef RIOT_VERSION
570 ssize_t
571 coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen) {
572  ssize_t bytes_written = 0;
573 
574  if (!coap_debug_send_packet()) {
575  bytes_written = (ssize_t)datalen;
576 #ifndef WITH_CONTIKI
577  } else if (sock->flags & COAP_SOCKET_CONNECTED) {
578 #ifdef _WIN32
579  bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
580 #else
581  bytes_written = send(sock->fd, data, datalen, 0);
582 #endif
583 #endif
584  } else {
585 #ifdef _WIN32
586  DWORD dwNumberOfBytesSent = 0;
587  int r;
588 #endif
589 #ifdef HAVE_STRUCT_CMSGHDR
590  /* a buffer large enough to hold all packet info types, ipv6 is the largest */
591  char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
592  struct msghdr mhdr;
593  struct iovec iov[1];
594  const void *addr = &session->addr_info.remote.addr;
595 
596  assert(session);
597 
598  memcpy (&iov[0].iov_base, &data, sizeof (iov[0].iov_base));
599  iov[0].iov_len = (iov_len_t)datalen;
600 
601  memset(buf, 0, sizeof (buf));
602 
603  memset(&mhdr, 0, sizeof(struct msghdr));
604  memcpy (&mhdr.msg_name, &addr, sizeof (mhdr.msg_name));
605  mhdr.msg_namelen = session->addr_info.remote.size;
606 
607  mhdr.msg_iov = iov;
608  mhdr.msg_iovlen = 1;
609 
610  if (!coap_address_isany(&session->addr_info.local) &&
611  !coap_is_mcast(&session->addr_info.local))
612  switch (session->addr_info.local.addr.sa.sa_family) {
613  case AF_INET6:
614  {
615  struct cmsghdr *cmsg;
616 
617  if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
618 #if defined(IP_PKTINFO)
619  struct in_pktinfo *pktinfo;
620  mhdr.msg_control = buf;
621  mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
622 
623  cmsg = CMSG_FIRSTHDR(&mhdr);
624  cmsg->cmsg_level = SOL_IP;
625  cmsg->cmsg_type = IP_PKTINFO;
626  cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
627 
628  pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
629 
630  pktinfo->ipi_ifindex = session->ifindex;
631  memcpy(&pktinfo->ipi_spec_dst,
632  session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
633  sizeof(pktinfo->ipi_spec_dst));
634 #elif defined(IP_SENDSRCADDR)
635  mhdr.msg_control = buf;
636  mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
637 
638  cmsg = CMSG_FIRSTHDR(&mhdr);
639  cmsg->cmsg_level = IPPROTO_IP;
640  cmsg->cmsg_type = IP_SENDSRCADDR;
641  cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
642 
643  memcpy(CMSG_DATA(cmsg),
644  session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
645  sizeof(struct in_addr));
646 #endif /* IP_PKTINFO */
647  } else {
648  struct in6_pktinfo *pktinfo;
649  mhdr.msg_control = buf;
650  mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
651 
652  cmsg = CMSG_FIRSTHDR(&mhdr);
653  cmsg->cmsg_level = IPPROTO_IPV6;
654  cmsg->cmsg_type = IPV6_PKTINFO;
655  cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
656 
657  pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
658 
659  pktinfo->ipi6_ifindex = session->ifindex;
660  memcpy(&pktinfo->ipi6_addr,
661  &session->addr_info.local.addr.sin6.sin6_addr,
662  sizeof(pktinfo->ipi6_addr));
663  }
664  break;
665  }
666  case AF_INET:
667  {
668 #if defined(IP_PKTINFO)
669  struct cmsghdr *cmsg;
670  struct in_pktinfo *pktinfo;
671 
672  mhdr.msg_control = buf;
673  mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
674 
675  cmsg = CMSG_FIRSTHDR(&mhdr);
676  cmsg->cmsg_level = SOL_IP;
677  cmsg->cmsg_type = IP_PKTINFO;
678  cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
679 
680  pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
681 
682  pktinfo->ipi_ifindex = session->ifindex;
683  memcpy(&pktinfo->ipi_spec_dst,
684  &session->addr_info.local.addr.sin.sin_addr,
685  sizeof(pktinfo->ipi_spec_dst));
686 #elif defined(IP_SENDSRCADDR)
687  struct cmsghdr *cmsg;
688  mhdr.msg_control = buf;
689  mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
690 
691  cmsg = CMSG_FIRSTHDR(&mhdr);
692  cmsg->cmsg_level = IPPROTO_IP;
693  cmsg->cmsg_type = IP_SENDSRCADDR;
694  cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
695 
696  memcpy(CMSG_DATA(cmsg),
697  &session->addr_info.local.addr.sin.sin_addr,
698  sizeof(struct in_addr));
699 #endif /* IP_PKTINFO */
700  break;
701  }
702  default:
703  /* error */
704  coap_log(LOG_WARNING, "protocol not supported\n");
705  bytes_written = -1;
706  }
707 #endif /* HAVE_STRUCT_CMSGHDR */
708 
709 #ifdef _WIN32
710  r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/, NULL /*lpCompletionRoutine*/);
711  if (r == 0)
712  bytes_written = (ssize_t)dwNumberOfBytesSent;
713  else
714  bytes_written = -1;
715 #else
716 #ifdef HAVE_STRUCT_CMSGHDR
717  bytes_written = sendmsg(sock->fd, &mhdr, 0);
718 #elif !defined(CONTIKI) /* ! HAVE_STRUCT_CMSGHDR */
719  bytes_written = sendto(sock->fd, data, datalen, 0,
720  &session->addr_info.remote.addr.sa,
721  session->addr_info.remote.size);
722 #endif /* ! HAVE_STRUCT_CMSGHDR */
723 #endif
724 #if defined(WITH_CONTIKI)
725  /* FIXME: untested */
726  /* FIXME: is there a way to check if send was successful? */
727  (void)datalen;
728  (void)data;
729  uip_udp_packet_sendto((struct uip_udp_conn *)sock->conn, data, datalen,
730  &session->addr_info.remote.addr, session->addr_info.remote.port);
731  bytes_written = datalen;
732 #endif /* WITH_CONTIKI */
733  }
734 
735  if (bytes_written < 0)
736  coap_log(LOG_CRIT, "coap_network_send: %s\n", coap_socket_strerror());
737 
738  return bytes_written;
739 }
740 #endif /* RIOT_VERSION */
741 
742 #define SIN6(A) ((struct sockaddr_in6 *)(A))
743 
744 void
745 coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
746  *address = packet->payload;
747  *length = packet->length;
748 }
749 
750 #ifndef RIOT_VERSION
751 ssize_t
753  ssize_t len = -1;
754 
755  assert(sock);
756  assert(packet);
757 
758  if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
759  return -1;
760  } else {
761  /* clear has-data flag */
762  sock->flags &= ~COAP_SOCKET_CAN_READ;
763  }
764 
765 #if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
766  if (sock->flags & COAP_SOCKET_CONNECTED) {
767 #ifdef _WIN32
768  len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
769 #else
770  len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
771 #endif
772  if (len < 0) {
773 #ifdef _WIN32
774  if (WSAGetLastError() == WSAECONNRESET) {
775 #else
776  if (errno == ECONNREFUSED) {
777 #endif
778  /* client-side ICMP destination unreachable, ignore it */
779  coap_log(LOG_WARNING, "coap_network_read: unreachable\n");
780  return -2;
781  }
782  coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror());
783  goto error;
784  } else if (len > 0) {
785  packet->length = (size_t)len;
786  }
787  } else {
788 #endif /* !(WITH_CONTIKI || RIOT_VERSION) */
789 #if defined(_WIN32)
790  DWORD dwNumberOfBytesRecvd = 0;
791  int r;
792 #endif
793 #if !defined(WITH_CONTIKI)
794 #ifdef HAVE_STRUCT_CMSGHDR
795  /* a buffer large enough to hold all packet info types, ipv6 is the largest */
796  char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
797  struct cmsghdr *cmsg;
798  struct msghdr mhdr;
799  struct iovec iov[1];
800 
801  iov[0].iov_base = packet->payload;
802  iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
803 
804  memset(&mhdr, 0, sizeof(struct msghdr));
805 
806  mhdr.msg_name = (struct sockaddr*)&packet->addr_info.remote.addr;
807  mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
808 
809  mhdr.msg_iov = iov;
810  mhdr.msg_iovlen = 1;
811 
812  mhdr.msg_control = buf;
813  mhdr.msg_controllen = sizeof(buf);
814  /* set a big first length incase recvmsg() does not implement updating
815  msg_control as well as preset the first cmsg with bad data */
816  cmsg = (struct cmsghdr *)buf;
817  cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
818  cmsg->cmsg_level = -1;
819  cmsg->cmsg_type = -1;
820 
821 #if defined(_WIN32)
822  if (!lpWSARecvMsg) {
823  GUID wsaid = WSAID_WSARECVMSG;
824  DWORD cbBytesReturned = 0;
825  if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
826  coap_log(LOG_WARNING, "coap_network_read: no WSARecvMsg\n");
827  return -1;
828  }
829  }
830  r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */, NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
831  if (r == 0)
832  len = (ssize_t)dwNumberOfBytesRecvd;
833 #else
834  len = recvmsg(sock->fd, &mhdr, 0);
835 #endif
836 
837 #else /* ! HAVE_STRUCT_CMSGHDR */
838  len = recvfrom(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0,
839  &packet->addr_info.remote.addr.sa,
840  &packet->addr_info.remote.size);
841 #endif /* ! HAVE_STRUCT_CMSGHDR */
842 
843  if (len < 0) {
844 #ifdef _WIN32
845  if (WSAGetLastError() == WSAECONNRESET) {
846 #else
847  if (errno == ECONNREFUSED) {
848 #endif
849  /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
850  return 0;
851  }
852  coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror());
853  goto error;
854  } else {
855 #ifdef HAVE_STRUCT_CMSGHDR
856  int dst_found = 0;
857 
858  packet->addr_info.remote.size = mhdr.msg_namelen;
859  packet->length = (size_t)len;
860 
861  /* Walk through ancillary data records until the local interface
862  * is found where the data was received. */
863  for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
864 
865  /* get the local interface for IPv6 */
866  if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
867  union {
868  uint8_t *c;
869  struct in6_pktinfo *p;
870  } u;
871  u.c = CMSG_DATA(cmsg);
872  packet->ifindex = (int)(u.p->ipi6_ifindex);
873  memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
874  &u.p->ipi6_addr, sizeof(struct in6_addr));
875  dst_found = 1;
876  break;
877  }
878 
879  /* local interface for IPv4 */
880 #if defined(IP_PKTINFO)
881  if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
882  union {
883  uint8_t *c;
884  struct in_pktinfo *p;
885  } u;
886  u.c = CMSG_DATA(cmsg);
887  packet->ifindex = u.p->ipi_ifindex;
888  if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
889  memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
890  packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
891  packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
892  memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
893  &u.p->ipi_addr, sizeof(struct in_addr));
894  } else {
895  memcpy(&packet->addr_info.local.addr.sin.sin_addr,
896  &u.p->ipi_addr, sizeof(struct in_addr));
897  }
898  dst_found = 1;
899  break;
900  }
901 #elif defined(IP_RECVDSTADDR)
902  if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
903  packet->ifindex = sock->fd;
904  memcpy(&packet->addr_info.local.addr.sin.sin_addr,
905  CMSG_DATA(cmsg), sizeof(struct in_addr));
906  dst_found = 1;
907  break;
908  }
909 #endif /* IP_PKTINFO */
910  if (!dst_found) {
911  /* cmsg_level / cmsg_type combination we do not understand
912  (ignore preset case for bad recvmsg() not updating cmsg) */
913  if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
915  "cmsg_level = %d and cmsg_type = %d not supported - fix\n",
916  cmsg->cmsg_level, cmsg->cmsg_type);
917  }
918  }
919  }
920  if (!dst_found) {
921  /* Not expected, but cmsg_level and cmsg_type don't match above and
922  may need a new case */
923  packet->ifindex = (int)sock->fd;
924  if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
925  &packet->addr_info.local.size) < 0) {
926  coap_log(LOG_DEBUG, "Cannot determine local port\n");
927  }
928  }
929 #else /* ! HAVE_STRUCT_CMSGHDR */
930  packet->length = (size_t)len;
931  packet->ifindex = 0;
932  if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
933  &packet->addr_info.local.size) < 0) {
934  coap_log(LOG_DEBUG, "Cannot determine local port\n");
935  goto error;
936  }
937 #endif /* ! HAVE_STRUCT_CMSGHDR */
938  }
939 #endif /* !defined(WITH_CONTIKI) && !defined(RIOT_VERSION) */
940 #ifdef WITH_CONTIKI
941  /* FIXME: untested, make this work */
942 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
943 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
944 
945  if (uip_newdata()) {
946  uip_ipaddr_copy(&packet->addr_info.remote.addr, &UIP_IP_BUF->srcipaddr);
947  packet->addr_info.remote.port = UIP_UDP_BUF->srcport;
948  uip_ipaddr_copy(&(packet)->addr_info.local.addr, &UIP_IP_BUF->destipaddr);
949  packet->addr_info.local.port = UIP_UDP_BUF->destport;
950 
951  len = uip_datalen();
952 
953  if (len > COAP_RXBUFFER_SIZE) {
954  /* FIXME: we might want to send back a response */
955  coap_log(LOG_WARNING, "discarded oversized packet\n");
956  return -1;
957  }
958 
959  ((char *)uip_appdata)[len] = 0;
960  if (LOG_DEBUG <= coap_get_log_level()) {
961 #ifndef INET6_ADDRSTRLEN
962 #define INET6_ADDRSTRLEN 40
963 #endif
964  unsigned char addr_str[INET6_ADDRSTRLEN + 8];
965 
966  if (coap_print_addr(&packet->addr_info.remote, addr_str,
967  INET6_ADDRSTRLEN + 8)) {
968  coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str);
969  }
970  }
971 
972  packet->length = len;
973  memcpy(&packet->payload, uip_appdata, len);
974  }
975 
976 #undef UIP_IP_BUF
977 #undef UIP_UDP_BUF
978 #endif /* WITH_CONTIKI */
979 #ifdef RIOT_VERSION
980  packet->src.size = sizeof(packet->src.addr);
981  len = recvfrom (sock->fd, packet->payload, COAP_RXBUFFER_SIZE,
982  0, &packet->src.addr.sa, &packet->src.size);
983  if (LOG_DEBUG <= coap_get_log_level()) {
984  unsigned char addr_str[INET6_ADDRSTRLEN + 8];
985 
986  if (coap_print_addr(&packet->src, addr_str, INET6_ADDRSTRLEN + 8)) {
987  coap_log(LOG_DEBUG, "received %zd bytes from %s\n", len, addr_str);
988  }
989  }
990 #endif /* RIOT_VERSION */
991 #if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
992  }
993 #endif /* !(WITH_CONTIKI || RIOT_VERSION) */
994 
995  if (len >= 0)
996  return len;
997 #if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
998 error:
999 #endif
1000  return -1;
1001 }
1002 #endif /* RIOT_VERSION */
1003 
1004 #if !defined(WITH_CONTIKI)
1005 
1006 unsigned int
1008 #ifndef COAP_EPOLL_SUPPORT
1009  (void)ctx;
1010  (void)now;
1012  "coap_io_prepare_epoll() requires libcoap compiled for using epoll\n");
1013  return 0;
1014 #else /* COAP_EPOLL_SUPPORT */
1015  coap_socket_t *sockets[1];
1016  unsigned int max_sockets = sizeof(sockets)/sizeof(sockets[0]);
1017  unsigned int num_sockets;
1018  unsigned int timeout;
1019 
1020  /* Use the common logic */
1021  timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now);
1022  /* Save when the next expected I/O is to take place */
1023  ctx->next_timeout = timeout ? now + timeout : 0;
1024  if (ctx->eptimerfd != -1) {
1025  struct itimerspec new_value;
1026  int ret;
1027 
1028  memset(&new_value, 0, sizeof(new_value));
1029  coap_ticks(&now);
1030  if (ctx->next_timeout != 0 && ctx->next_timeout > now) {
1031  coap_tick_t rem_timeout = ctx->next_timeout - now;
1032  /* Need to trigger an event on ctx->epfd in the future */
1033  new_value.it_value.tv_sec = rem_timeout / COAP_TICKS_PER_SECOND;
1034  new_value.it_value.tv_nsec = (rem_timeout % COAP_TICKS_PER_SECOND) *
1035  1000000;
1036  }
1037 #ifdef COAP_DEBUG_WAKEUP_TIMES
1038  coap_log(LOG_INFO, "****** Next wakeup time %ld.%09ld\n",
1039  new_value.it_value.tv_sec, new_value.it_value.tv_nsec);
1040 #endif /* COAP_DEBUG_WAKEUP_TIMES */
1041  /* reset, or specify a future time for eptimerfd to trigger */
1042  ret = timerfd_settime(ctx->eptimerfd, 0, &new_value, NULL);
1043  if (ret == -1) {
1044  coap_log(LOG_ERR,
1045  "%s: timerfd_settime failed: %s (%d)\n",
1046  "coap_io_prepare_epoll",
1047  coap_socket_strerror(), errno);
1048  }
1049  }
1050  return timeout;
1051 #endif /* COAP_EPOLL_SUPPORT */
1052 }
1053 
1054 /*
1055  * return 0 No i/o pending
1056  * +ve millisecs to next i/o activity
1057  */
1058 unsigned int
1060  coap_socket_t *sockets[],
1061  unsigned int max_sockets,
1062  unsigned int *num_sockets,
1063  coap_tick_t now)
1064 {
1065  coap_queue_t *nextpdu;
1066  coap_endpoint_t *ep;
1067  coap_session_t *s, *rtmp;
1068  coap_tick_t session_timeout;
1069  coap_tick_t timeout = 0;
1070  coap_tick_t s_timeout;
1071 #ifdef COAP_EPOLL_SUPPORT
1072  (void)sockets;
1073  (void)max_sockets;
1074 #endif /* COAP_EPOLL_SUPPORT */
1075 
1076  *num_sockets = 0;
1077 
1078  /* Check to see if we need to send off any Observe requests */
1079  coap_check_notify(ctx);
1080 
1081  if (ctx->session_timeout > 0)
1082  session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
1083  else
1085 
1086 #ifndef WITHOUT_ASYNC
1087  /* Check to see if we need to send off any Async requests */
1088  timeout = coap_check_async(ctx, now);
1089 #endif /* WITHOUT_ASYNC */
1090 
1091  LL_FOREACH(ctx->endpoint, ep) {
1092 #ifndef COAP_EPOLL_SUPPORT
1094  if (*num_sockets < max_sockets)
1095  sockets[(*num_sockets)++] = &ep->sock;
1096  }
1097 #endif /* ! COAP_EPOLL_SUPPORT */
1098  SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
1099  if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
1100  s->delayqueue == NULL &&
1101  (s->last_rx_tx + session_timeout <= now ||
1102  s->state == COAP_SESSION_STATE_NONE)) {
1103  coap_session_free(s);
1104  } else {
1105  if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && s->delayqueue == NULL) {
1106  s_timeout = (s->last_rx_tx + session_timeout) - now;
1107  if (timeout == 0 || s_timeout < timeout)
1108  timeout = s_timeout;
1109  }
1110  /* Check if any server large receives have timed out */
1111  if (s->lg_srcv) {
1112  s_timeout = coap_block_check_lg_srcv_timeouts(s, now);
1113  if (timeout == 0 || s_timeout < timeout)
1114  timeout = s_timeout;
1115  }
1116 #ifndef COAP_EPOLL_SUPPORT
1118  if (*num_sockets < max_sockets)
1119  sockets[(*num_sockets)++] = &s->sock;
1120  }
1121 #endif /* ! COAP_EPOLL_SUPPORT */
1122  }
1123  }
1124  }
1125  SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
1126  if (!COAP_DISABLE_TCP
1129  && ctx->ping_timeout > 0
1130  ) {
1131  if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
1132  if ((s->last_ping > 0 && s->last_pong < s->last_ping)
1134  {
1135  /* Make sure the session object is not deleted in the callback */
1139  continue;
1140  }
1141  s->last_rx_tx = now;
1142  s->last_ping = now;
1143  }
1144  s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
1145  if (timeout == 0 || s_timeout < timeout)
1146  timeout = s_timeout;
1147  }
1148 
1149  if (!COAP_DISABLE_TCP
1151  && COAP_PROTO_RELIABLE(s->proto)
1152  && s->state == COAP_SESSION_STATE_CSM
1153  && ctx->csm_timeout > 0
1154  ) {
1155  if (s->csm_tx == 0) {
1156  s->csm_tx = now;
1157  } else if (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND <= now) {
1158  /* Make sure the session object is not deleted in the callback */
1162  continue;
1163  }
1164  s_timeout = (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND) - now;
1165  if (timeout == 0 || s_timeout < timeout)
1166  timeout = s_timeout;
1167  }
1168 
1169  /* Check if any client large receives have timed out */
1170  if (s->lg_crcv) {
1171  s_timeout = coap_block_check_lg_crcv_timeouts(s, now);
1172  if (timeout == 0 || s_timeout < timeout)
1173  timeout = s_timeout;
1174  }
1175 
1176 #ifndef COAP_EPOLL_SUPPORT
1178  if (*num_sockets < max_sockets)
1179  sockets[(*num_sockets)++] = &s->sock;
1180  }
1181 #endif /* ! COAP_EPOLL_SUPPORT */
1182  }
1183 
1184  nextpdu = coap_peek_next(ctx);
1185 
1186  while (nextpdu && now >= ctx->sendqueue_basetime && nextpdu->t <= now - ctx->sendqueue_basetime) {
1187  coap_retransmit(ctx, coap_pop_next(ctx));
1188  nextpdu = coap_peek_next(ctx);
1189  }
1190 
1191  if (nextpdu && (timeout == 0 || nextpdu->t - ( now - ctx->sendqueue_basetime ) < timeout))
1192  timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
1193 
1194  if (ctx->dtls_context) {
1197  if (tls_timeout > 0) {
1198  if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
1199  tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
1200  coap_log(LOG_DEBUG, "** DTLS global timeout set to %dms\n",
1201  (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
1202  if (timeout == 0 || tls_timeout - now < timeout)
1203  timeout = tls_timeout - now;
1204  }
1205  } else {
1206  LL_FOREACH(ctx->endpoint, ep) {
1207  if (ep->proto == COAP_PROTO_DTLS) {
1208  SESSIONS_ITER(ep->sessions, s, rtmp) {
1209  if (s->state == COAP_SESSION_STATE_HANDSHAKE &&
1210  s->proto == COAP_PROTO_DTLS && s->tls) {
1211  coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1212  while (tls_timeout > 0 && tls_timeout <= now) {
1213  coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n",
1214  coap_session_str(s));
1215  /* Make sure the session object is not deleted in any callbacks */
1218  if (s->tls)
1219  tls_timeout = coap_dtls_get_timeout(s, now);
1220  else {
1221  tls_timeout = 0;
1222  timeout = 1;
1223  }
1225  }
1226  if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1227  timeout = tls_timeout - now;
1228  }
1229  }
1230  }
1231  }
1232  SESSIONS_ITER(ctx->sessions, s, rtmp) {
1233  if (s->state == COAP_SESSION_STATE_HANDSHAKE &&
1234  s->proto == COAP_PROTO_DTLS && s->tls) {
1235  coap_tick_t tls_timeout = coap_dtls_get_timeout(s, now);
1236  while (tls_timeout > 0 && tls_timeout <= now) {
1237  coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n", coap_session_str(s));
1238  /* Make sure the session object is not deleted in any callbacks */
1241  if (s->tls)
1242  tls_timeout = coap_dtls_get_timeout(s, now);
1243  else {
1244  tls_timeout = 0;
1245  timeout = 1;
1246  }
1248  }
1249  if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
1250  timeout = tls_timeout - now;
1251  }
1252  }
1253  }
1254  }
1255 
1256  return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
1257 }
1258 
1259 #ifndef RIOT_VERSION
1260 int
1261 coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1262  return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL);
1263 }
1264 
1265 int
1266 coap_io_process_with_fds(coap_context_t *ctx, uint32_t timeout_ms,
1267  int enfds, fd_set *ereadfds, fd_set *ewritefds,
1268  fd_set *eexceptfds) {
1269 #if COAP_CONSTRAINED_STACK
1270  static coap_mutex_t static_mutex = COAP_MUTEX_INITIALIZER;
1271 # ifndef COAP_EPOLL_SUPPORT
1272  static fd_set readfds, writefds, exceptfds;
1273  static coap_socket_t *sockets[64];
1274  unsigned int num_sockets = 0;
1275 # endif /* ! COAP_EPOLL_SUPPORT */
1276 #else /* ! COAP_CONSTRAINED_STACK */
1277 # ifndef COAP_EPOLL_SUPPORT
1278  fd_set readfds, writefds, exceptfds;
1279  coap_socket_t *sockets[64];
1280  unsigned int num_sockets = 0;
1281 # endif /* ! COAP_EPOLL_SUPPORT */
1282 #endif /* ! COAP_CONSTRAINED_STACK */
1283  coap_fd_t nfds = 0;
1284  coap_tick_t before, now;
1285  unsigned int timeout;
1286 #ifndef COAP_EPOLL_SUPPORT
1287  struct timeval tv;
1288  int result;
1289  unsigned int i;
1290 #endif /* ! COAP_EPOLL_SUPPORT */
1291 
1292 #if COAP_CONSTRAINED_STACK
1293  coap_mutex_lock(&static_mutex);
1294 #endif /* COAP_CONSTRAINED_STACK */
1295 
1296  coap_ticks(&before);
1297 
1298 #ifndef COAP_EPOLL_SUPPORT
1299  timeout = coap_io_prepare_io(ctx, sockets,
1300  (sizeof(sockets) / sizeof(sockets[0])),
1301  &num_sockets, before);
1302  if (timeout == 0 || timeout_ms < timeout)
1303  timeout = timeout_ms;
1304 
1305  if (ereadfds) {
1306  readfds = *ereadfds;
1307  nfds = enfds;
1308  }
1309  else {
1310  FD_ZERO(&readfds);
1311  }
1312  if (ewritefds) {
1313  writefds = *ewritefds;
1314  nfds = enfds;
1315  }
1316  else {
1317  FD_ZERO(&writefds);
1318  }
1319  if (eexceptfds) {
1320  exceptfds = *eexceptfds;
1321  nfds = enfds;
1322  }
1323  else {
1324  FD_ZERO(&exceptfds);
1325  }
1326  for (i = 0; i < num_sockets; i++) {
1327  if (sockets[i]->fd + 1 > nfds)
1328  nfds = sockets[i]->fd + 1;
1329  if (sockets[i]->flags & COAP_SOCKET_WANT_READ)
1330  FD_SET(sockets[i]->fd, &readfds);
1331  if (sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
1332  FD_SET(sockets[i]->fd, &writefds);
1333 #if !COAP_DISABLE_TCP
1334  if (sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
1335  FD_SET(sockets[i]->fd, &readfds);
1336  if (sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
1337  FD_SET(sockets[i]->fd, &writefds);
1338  FD_SET(sockets[i]->fd, &exceptfds);
1339  }
1340 #endif /* !COAP_DISABLE_TCP */
1341  }
1342 
1343  if (timeout_ms == COAP_IO_NO_WAIT) {
1344  tv.tv_usec = 0;
1345  tv.tv_sec = 0;
1346  timeout = 1;
1347  }
1348  else if (timeout > 0) {
1349  tv.tv_usec = (timeout % 1000) * 1000;
1350  tv.tv_sec = (long)(timeout / 1000);
1351  }
1352 
1353  result = select((int)nfds, &readfds, &writefds, &exceptfds, timeout > 0 ? &tv : NULL);
1354 
1355  if (result < 0) { /* error */
1356 #ifdef _WIN32
1357  if (WSAGetLastError() != WSAEINVAL) { /* May happen because of ICMP */
1358 #else
1359  if (errno != EINTR) {
1360 #endif
1362 #if COAP_CONSTRAINED_STACK
1363  coap_mutex_unlock(&static_mutex);
1364 #endif /* COAP_CONSTRAINED_STACK */
1365  return -1;
1366  }
1367  }
1368 
1369  if (result > 0) {
1370  for (i = 0; i < num_sockets; i++) {
1371  if ((sockets[i]->flags & COAP_SOCKET_WANT_READ) && FD_ISSET(sockets[i]->fd, &readfds))
1372  sockets[i]->flags |= COAP_SOCKET_CAN_READ;
1373 #if !COAP_DISABLE_TCP
1374  if ((sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) && FD_ISSET(sockets[i]->fd, &readfds))
1375  sockets[i]->flags |= COAP_SOCKET_CAN_ACCEPT;
1376  if ((sockets[i]->flags & COAP_SOCKET_WANT_WRITE) && FD_ISSET(sockets[i]->fd, &writefds))
1377  sockets[i]->flags |= COAP_SOCKET_CAN_WRITE;
1378  if ((sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) && (FD_ISSET(sockets[i]->fd, &writefds) || FD_ISSET(sockets[i]->fd, &exceptfds)))
1379  sockets[i]->flags |= COAP_SOCKET_CAN_CONNECT;
1380 #endif /* !COAP_DISABLE_TCP */
1381  }
1382  }
1383 
1384  coap_ticks(&now);
1385  coap_io_do_io(ctx, now);
1386  if (ereadfds) {
1387  *ereadfds = readfds;
1388  }
1389  if (ewritefds) {
1390  *ewritefds = writefds;
1391  }
1392  if (eexceptfds) {
1393  *eexceptfds = exceptfds;
1394  }
1395 
1396 #else /* COAP_EPOLL_SUPPORT */
1397  (void)ereadfds;
1398  (void)ewritefds;
1399  (void)eexceptfds;
1400  (void)enfds;
1401 
1402  timeout = coap_io_prepare_epoll(ctx, before);
1403 
1404  if (timeout == 0 || timeout_ms < timeout)
1405  timeout = timeout_ms;
1406 
1407  do {
1408  struct epoll_event events[COAP_MAX_EPOLL_EVENTS];
1409  int etimeout = timeout;
1410 
1411  /* Potentially adjust based on what the caller wants */
1412  if (timeout_ms == COAP_IO_NO_WAIT) {
1413  etimeout = 0;
1414  }
1415  else if (timeout == COAP_IO_WAIT) {
1416  /* coap_io_prepare_epoll() returned 0 and timeout_ms COAP_IO_WAIT (0) */
1417  etimeout = -1;
1418  }
1419  else if (etimeout < 0) {
1420  /* epoll_wait cannot wait longer than this as int timeout parameter */
1421  etimeout = INT_MAX;
1422  }
1423 
1424  nfds = epoll_wait(ctx->epfd, events, COAP_MAX_EPOLL_EVENTS, etimeout);
1425  if (nfds < 0) {
1426  if (errno != EINTR) {
1427  coap_log (LOG_ERR, "epoll_wait: unexpected error: %s (%d)\n",
1428  coap_socket_strerror(), nfds);
1429  }
1430  break;
1431  }
1432 
1433  coap_io_do_epoll(ctx, events, nfds);
1434 
1435  /*
1436  * reset to COAP_IO_NO_WAIT (which causes etimeout to become 0)
1437  * incase we have to do another iteration
1438  * (COAP_MAX_EPOLL_EVENTS insufficient)
1439  */
1440  timeout_ms = COAP_IO_NO_WAIT;
1441 
1442  /* Keep retrying until less than COAP_MAX_EPOLL_EVENTS are returned */
1443  } while (nfds == COAP_MAX_EPOLL_EVENTS);
1444 
1445 #endif /* COAP_EPOLL_SUPPORT */
1447  coap_ticks(&now);
1448 #ifndef WITHOUT_ASYNC
1449  /* Check to see if we need to send off any Async requests as delay might
1450  have been updated */
1451  coap_check_async(ctx, now);
1452  coap_ticks(&now);
1453 #endif /* WITHOUT_ASYNC */
1454 
1455 #if COAP_CONSTRAINED_STACK
1456  coap_mutex_unlock(&static_mutex);
1457 #endif /* COAP_CONSTRAINED_STACK */
1458 
1459  return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
1460 }
1461 #endif /* RIOT_VERSION */
1462 
1463 #else /* WITH_CONTIKI */
1464 int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
1465  coap_tick_t now;
1466 
1467  coap_ticks(&now);
1468  /* There is something to read on the endpoint */
1470  /* read in, and send off any responses */
1471  coap_io_do_io(ctx, now); /* read received data */
1472  return -1;
1473 }
1474 
1475 unsigned int
1476 coap_io_prepare(coap_context_t *ctx,
1477  coap_socket_t *sockets[],
1478  unsigned int max_sockets,
1479  unsigned int *num_sockets,
1480  coap_tick_t now)
1481 {
1482  *num_sockets = 0;
1483  return 0;
1484 }
1485 #endif /* WITH_CONTIKI */
1486 
1487 #ifdef _WIN32
1488 const char *coap_socket_format_errno(int error) {
1489  static char szError[256];
1490  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError), NULL) == 0)
1491  strcpy(szError, "Unknown error");
1492  return szError;
1493 }
1494 
1495 const char *coap_socket_strerror(void) {
1496  return coap_socket_format_errno(WSAGetLastError());
1497 }
1498 #else /* _WIN32 */
1499 const char *coap_socket_format_errno(int error) {
1500  return strerror(error);
1501 }
1502 const char *coap_socket_strerror(void) {
1503  return coap_socket_format_errno(errno);
1504 }
1505 #endif /* _WIN32 */
1506 
1507 ssize_t
1509  const uint8_t *data, size_t data_len) {
1510  return session->context->network_send(sock, session, data, data_len);
1511 }
1512 
1513 #undef SIN6
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
Definition: address.c:102
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
Definition: address.c:83
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
Definition: address.h:190
COAP_STATIC_INLINE void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
Definition: address.h:152
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:983
Pulls together all the internal only header files.
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)
Definition: coap_io.c:242
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
Definition: coap_io.c:478
void coap_socket_close(coap_socket_t *sock)
Definition: coap_io.c:368
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t data_len)
Definition: coap_io.c:1508
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:745
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Definition: coap_io.c:427
#define SOL_IP
Definition: coap_io.c:539
ssize_t coap_network_read(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition: coap_io.c:752
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Definition: coap_io.c:154
ssize_t coap_network_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:571
#define iov_len_t
Definition: coap_io.c:562
const char * coap_socket_strerror(void)
Definition: coap_io.c:1502
const char * coap_socket_format_errno(int error)
Definition: coap_io.c:1499
void coap_mfree_endpoint(coap_endpoint_t *ep)
Definition: coap_io.c:149
coap_endpoint_t * coap_malloc_endpoint(void)
Definition: coap_io.c:144
#define coap_closesocket
Definition: coap_io.h:43
#define COAP_MAX_EPOLL_EVENTS
Definition: coap_io.h:33
#define COAP_RXBUFFER_SIZE
Definition: coap_io.h:24
#define COAP_SOCKET_ERROR
Definition: coap_io.h:44
@ COAP_NACK_NOT_DELIVERABLE
Definition: coap_io.h:66
int coap_fd_t
Definition: coap_io.h:42
#define COAP_INVALID_SOCKET
Definition: coap_io.h:45
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#define COAP_SOCKET_WANT_ACCEPT
non blocking server socket is waiting for accept
#define COAP_SOCKET_CAN_WRITE
non blocking socket can now write without blocking
#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
#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
void coap_epoll_ctl_mod(coap_socket_t *sock, uint32_t events, const char *func)
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
#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
void coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
Definition: coap_notls.c:140
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
Definition: coap_notls.c:136
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
Definition: coap_notls.c:131
coap_mid_t coap_session_send_ping(coap_session_t *session)
Send a ping message for the session.
Definition: coap_session.c:381
#define INET6_ADDRSTRLEN
#define SESSIONS_ITER_SAFE(e, el, rtmp)
#define SESSIONS_ITER(e, el, rtmp)
#define COAP_DEFAULT_SESSION_TIMEOUT
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: net.c:1738
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:1007
void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents)
Process all the epoll events.
Definition: net.c:1799
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:1059
int coap_io_process(coap_context_t *ctx, uint32_t timeout_ms)
The main I/O processing function.
Definition: coap_io.c:1261
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:1266
#define COAP_IO_NO_WAIT
Definition: net.h:535
#define COAP_IO_WAIT
Definition: net.h:534
coap_tick_t coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now)
Definition: block.c:788
coap_tick_t coap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now)
Definition: block.c:734
void coap_expire_cache_entries(coap_context_t *ctx)
Expire coap_cache_entry_t entries.
Definition: coap_cache.c:256
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:122
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition: coap_time.h:137
coap_tick_t coap_check_async(coap_context_t *context, coap_tick_t now)
Checks if there are any pending Async requests - if so, send them off.
Definition: net.c:3199
coap_queue_t * coap_peek_next(coap_context_t *context)
Returns the next pdu to send without removing from sendqeue.
Definition: net.c:274
coap_queue_t * coap_pop_next(coap_context_t *context)
Returns the next pdu to send and removes it from the sendqeue.
Definition: net.c:282
coap_mid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
Handles retransmissions of confirmable messages.
Definition: net.c:1337
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
Definition: coap_notls.c:127
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:63
const char * coap_session_str(const coap_session_t *session)
Get session description.
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:173
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:152
@ LOG_ERR
Error.
Definition: coap_debug.h:55
@ LOG_CRIT
Critical.
Definition: coap_debug.h:54
@ LOG_INFO
Information.
Definition: coap_debug.h:58
@ LOG_ALERT
Alert.
Definition: coap_debug.h:53
@ LOG_WARNING
Warning.
Definition: coap_debug.h:56
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:59
@ LOG_EMERG
Emergency.
Definition: coap_debug.h:52
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition: pdu.h:234
@ COAP_PROTO_DTLS
Definition: pdu.h:283
void coap_session_free(coap_session_t *session)
Definition: coap_session.c:225
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:70
#define COAP_PROTO_RELIABLE(p)
Definition: coap_session.h:36
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:76
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
Definition: coap_session.c:456
@ COAP_SESSION_TYPE_SERVER
server-side
Definition: coap_session.h:44
@ COAP_SESSION_TYPE_CLIENT
client-side
Definition: coap_session.h:43
@ COAP_SESSION_STATE_HANDSHAKE
Definition: coap_session.h:55
@ COAP_SESSION_STATE_CSM
Definition: coap_session.h:56
@ COAP_SESSION_STATE_ESTABLISHED
Definition: coap_session.h:57
@ COAP_SESSION_STATE_NONE
Definition: coap_session.h:53
void coap_check_notify(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
Definition: resource.c:1062
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_ENDPOINT
Definition: mem.h:38
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
coap_address_t remote
remote address and port
Definition: coap_io.h:51
coap_address_t local
local address and port
Definition: coap_io.h:52
multi-purpose address abstraction
Definition: address.h:96
socklen_t size
size of addr
Definition: address.h:97
struct sockaddr_in sin
Definition: address.h:100
struct sockaddr_in6 sin6
Definition: address.h:101
struct sockaddr sa
Definition: address.h:99
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.
unsigned int csm_timeout
Timeout for waiting for a CSM from the remote side.
coap_session_t * sessions
client sessions
unsigned int ping_timeout
Minimum inactivity time before sending a ping message.
ssize_t(* network_send)(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
coap_endpoint_t * endpoint
the endpoints used for listening
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_socket_t sock
socket object for the interface, if any
coap_proto_t proto
protocol used on this interface
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char payload[COAP_RXBUFFER_SIZE]
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_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationaship with peer
coap_addr_tuple_t addr_info
key: remote/local address info
coap_proto_t proto
protocol used
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
coap_session_t * session
coap_endpoint_t * endpoint
coap_socket_flags_t flags
struct in6_addr ipi6_addr
Definition: coap_io.c:526
unsigned int ipi6_ifindex
Definition: coap_io.c:527
struct in_addr ipi_spec_dst
Definition: coap_io.c:532
struct in_addr ipi_addr
Definition: coap_io.c:533
int ipi_ifindex
Definition: coap_io.c:531