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