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