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