• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
83 static int
bind_to_device(int sockfd,const struct sockaddr_in * local_addr)84 bind_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
132 coap_endpoint_t *
coap_malloc_endpoint(void)133 coap_malloc_endpoint(void) {
134   return (coap_endpoint_t *)coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t));
135 }
136 
137 void
coap_mfree_endpoint(coap_endpoint_t * ep)138 coap_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 
145 int
coap_socket_bind_udp(coap_socket_t * sock,const coap_address_t * listen_addr,coap_address_t * bound_addr)146 coap_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 
250 error:
251   coap_socket_close(sock);
252   return 0;
253 }
254 
255 #if COAP_CLIENT_SUPPORT
256 int
257 coap_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 
478 error:
479   coap_socket_close(sock);
480   return 0;
481 }
482 #endif /* COAP_CLIENT_SUPPORT */
483 
484 void
485 coap_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
534 void
535 coap_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 
571 void
572 coap_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 
609 void
610 coap_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
647 static void
648 coap_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  */
717 ssize_t
718 coap_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  */
776 ssize_t
777 coap_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__)
821 struct in6_pktinfo {
822   struct in6_addr ipi6_addr;        /* src/dst IPv6 address */
823   unsigned int ipi6_ifindex;        /* send/recv interface index */
824 };
825 
826 struct 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__)
848 static __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  */
882 ssize_t
883 coap_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 
1062 void
1063 coap_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  */
1075 ssize_t
1076 coap_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;
1299 error:
1300   return -1;
1301 }
1302 #endif /* ! WITH_LWIP && ! WITH_CONTIKI */
1303 
1304 unsigned int
1305 coap_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  */
1354 unsigned int
1355 coap_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 */
1497 release_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 */
1599 release_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)
1608 int
1609 coap_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 
1613 int
1614 coap_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  */
1792 int
1793 coap_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
1832 const char *
1833 coap_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 
1843 const char *
1844 coap_socket_strerror(void) {
1845   return coap_socket_format_errno(WSAGetLastError());
1846 }
1847 #else /* _WIN32 */
1848 const char *
1849 coap_socket_format_errno(int error) {
1850   return strerror(error);
1851 }
1852 const char *
1853 coap_socket_strerror(void) {
1854   return coap_socket_format_errno(errno);
1855 }
1856 #endif /* _WIN32 */
1857 
1858 #undef SIN6
1859