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