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