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