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