Coverage Report

Created: 2026-08-08 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcoap/src/coap_dgrm_posix.c
Line
Count
Source
1
/*
2
 * coap_dgrm_posix.c -- Datagram (UDP) functions for libcoap
3
 *
4
 * Copyright (C) 2019-2026 Olaf Bergmann <bergmann@tzi.org> and others
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * This file is part of the CoAP library libcoap. Please see README for terms
9
 * of use.
10
 */
11
12
/**
13
 * @file coap_dgrm_posix.c
14
 * @brief Posix CoAP Datagram (UDP) handling functions
15
 */
16
17
#include "coap3/coap_libcoap_build.h"
18
19
#if ! defined(WITH_LWIP) && ! defined(WITH_CONTIKI) && ! defined (RIOT_VERSION)
20
21
#ifdef HAVE_STDIO_H
22
#  include <stdio.h>
23
#endif
24
#ifdef HAVE_UNISTD_H
25
# include <unistd.h>
26
#endif
27
28
#ifndef __ZEPHYR__
29
#ifdef HAVE_SYS_SELECT_H
30
# include <sys/select.h>
31
#endif
32
#ifdef HAVE_SYS_SOCKET_H
33
# include <sys/socket.h>
34
26
# define OPTVAL_T(t)         (t)
35
# define OPTVAL_GT(t)        (t)
36
#endif
37
#ifdef HAVE_SYS_IOCTL_H
38
#include <sys/ioctl.h>
39
#endif
40
#ifdef HAVE_NETINET_IN_H
41
# include <netinet/in.h>
42
#endif
43
#ifdef HAVE_NETINET_IP_ICMP_H
44
# include <netinet/ip_icmp.h>
45
#endif
46
#ifdef HAVE_NETINET_ICMP6_H
47
# include <netinet/icmp6.h>
48
#endif
49
#ifdef HAVE_LINUX_ERRQUEUE_H
50
# include <linux/errqueue.h>
51
#endif
52
#ifdef HAVE_SYS_SELECT_H
53
# include <sys/select.h>
54
#endif
55
#ifdef HAVE_WS2TCPIP_H
56
#include <ws2tcpip.h>
57
# define OPTVAL_T(t)         (const char*)(t)
58
# define OPTVAL_GT(t)        (char*)(t)
59
# undef CMSG_DATA
60
# define CMSG_DATA WSA_CMSG_DATA
61
#endif
62
#ifdef HAVE_SYS_UIO_H
63
# include <sys/uio.h>
64
#endif
65
#ifdef _WIN32
66
#include <stdio.h>
67
#endif /* _WIN32 */
68
#ifdef COAP_EPOLL_SUPPORT
69
#include <sys/epoll.h>
70
#include <sys/timerfd.h>
71
#ifdef HAVE_LIMITS_H
72
#include <limits.h>
73
#endif
74
#endif /* COAP_EPOLL_SUPPORT */
75
#else /* __ZEPHYR__ */
76
#include <sys/ioctl.h>
77
#include <sys/select.h>
78
#define OPTVAL_T(t)         (const void*)(t)
79
#define OPTVAL_GT(t)        (void*)(t)
80
81
#ifndef IPV6_PKTINFO
82
#ifdef IPV6_RECVPKTINFO
83
#define IPV6_PKTINFO IPV6_RECVPKTINFO
84
#else
85
#define IPV6_PKTINFO IP_PKTINFO
86
#endif
87
#ifndef IN6_IS_ADDR_V4MAPPED
88
#define IN6_IS_ADDR_V4MAPPED(a) \
89
  ((((a)->s6_addr32[0]) == 0) && (((a)->s6_addr32[1]) == 0) && \
90
   (((a)->s6_addr32[2]) == htonl(0xffff)))
91
#endif
92
#endif
93
#endif /* __ZEPHYR__ */
94
95
/* define generic PKTINFO for IPv4 */
96
#if defined(IP_PKTINFO)
97
0
#  define GEN_IP_PKTINFO IP_PKTINFO
98
#elif defined(IP_RECVDSTADDR)
99
#  define GEN_IP_PKTINFO IP_RECVDSTADDR
100
#else
101
#  error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
102
#endif /* IP_PKTINFO */
103
104
/* define generic PKTINFO for IPv6 */
105
#ifdef IPV6_RECVPKTINFO
106
0
#  define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
107
#elif defined(IPV6_PKTINFO)
108
#  define GEN_IPV6_PKTINFO IPV6_PKTINFO
109
#else
110
#  error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
111
#endif /* IPV6_RECVPKTINFO */
112
113
#if COAP_SERVER_SUPPORT
114
int
115
coap_socket_bind_udp(coap_socket_t *sock,
116
                     const coap_address_t *listen_addr,
117
0
                     coap_address_t *bound_addr) {
118
0
  int on = 1;
119
0
#if COAP_IPV6_SUPPORT
120
0
  int off = 0;
121
0
#endif /* COAP_IPV6_SUPPORT */
122
#ifdef _WIN32
123
  u_long u_on = 1;
124
#endif
125
126
0
  sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
127
128
0
  if (sock->fd == COAP_INVALID_SOCKET) {
129
0
    coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
130
0
    goto error;
131
0
  }
132
#ifdef _WIN32
133
  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
134
#else
135
0
  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
136
0
#endif
137
0
  {
138
0
    coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
139
0
  }
140
141
0
  if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
142
0
    coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
143
0
                  coap_socket_strerror());
144
145
0
  switch (listen_addr->addr.sa.sa_family) {
146
0
#if COAP_IPV4_SUPPORT
147
0
  case AF_INET:
148
0
    if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
149
0
                   sizeof(on)) == COAP_SOCKET_ERROR)
150
0
      coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
151
0
                     coap_socket_strerror());
152
0
    break;
153
0
#endif /* COAP_IPV4_SUPPORT */
154
0
#if COAP_IPV6_SUPPORT
155
0
  case AF_INET6:
156
    /* Configure the socket as dual-stacked */
157
0
    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
158
0
                   sizeof(off)) == COAP_SOCKET_ERROR)
159
0
      coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
160
0
                     coap_socket_strerror());
161
0
#if !defined(ESPIDF_VERSION)
162
0
    if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
163
0
                   sizeof(on)) == COAP_SOCKET_ERROR)
164
0
      coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
165
0
                     coap_socket_strerror());
166
0
#endif /* !defined(ESPIDF_VERSION) */
167
0
#endif /* COAP_IPV6_SUPPORT */
168
0
    setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
169
    /* ignore error, because likely cause is that IPv4 is disabled at the os
170
       level */
171
0
    break;
172
0
#if COAP_AF_UNIX_SUPPORT
173
0
  case AF_UNIX:
174
0
    break;
175
0
#endif /* COAP_AF_UNIX_SUPPORT */
176
0
#if COAP_AF_LLC_SUPPORT
177
0
  case AF_LLC:
178
0
    break;
179
0
#endif /* COAP_AF_LLC_SUPPORT */
180
0
  default:
181
0
    coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
182
0
    break;
183
0
  }
184
185
0
  if (bind(sock->fd, &listen_addr->addr.sa,
186
0
#if COAP_IPV4_SUPPORT
187
0
           listen_addr->addr.sa.sa_family == AF_INET ?
188
0
           (socklen_t)sizeof(struct sockaddr_in) :
189
0
#endif /* COAP_IPV4_SUPPORT */
190
0
           (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
191
0
    coap_log_warn("coap_socket_bind_udp: bind: %s\n",
192
0
                  coap_socket_strerror());
193
0
    goto error;
194
0
  }
195
196
0
  bound_addr->size = (socklen_t)sizeof(*bound_addr);
197
0
  if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
198
0
    coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
199
0
                  coap_socket_strerror());
200
0
    goto error;
201
0
  }
202
0
  return 1;
203
204
0
error:
205
0
  coap_socket_dgrm_close(sock);
206
0
  return 0;
207
0
}
208
#endif /* COAP_SERVER_SUPPORT */
209
210
#if COAP_CLIENT_SUPPORT
211
int
212
coap_socket_connect_udp(coap_socket_t *sock,
213
                        const coap_address_t *local_if,
214
                        const coap_address_t *server,
215
                        int default_port,
216
                        coap_address_t *local_addr,
217
26
                        coap_address_t *remote_addr) {
218
26
  int on = 1;
219
26
#if COAP_IPV6_SUPPORT
220
26
  int off = 0;
221
26
#endif /* COAP_IPV6_SUPPORT */
222
#ifdef _WIN32
223
  u_long u_on = 1;
224
#endif
225
26
  coap_address_t connect_addr;
226
26
  int is_mcast = coap_is_mcast(server);
227
26
  coap_address_copy(&connect_addr, server);
228
229
26
  sock->flags &= ~(COAP_SOCKET_CONNECTED | COAP_SOCKET_MULTICAST);
230
26
  sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
231
232
26
  if (sock->fd == COAP_INVALID_SOCKET) {
233
0
    coap_log_warn("coap_socket_connect_udp: socket: %s\n",
234
0
                  coap_socket_strerror());
235
0
    goto error;
236
0
  }
237
238
#ifdef _WIN32
239
  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
240
#else
241
26
  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
242
0
#endif
243
0
  {
244
    /* Ignore Zephyr unexpected Success response */
245
0
    if (errno != 0) {
246
0
      int keep_errno = errno;
247
248
0
      coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s (%d)\n",
249
0
                    coap_socket_strerror(), keep_errno);
250
0
    }
251
0
  }
252
253
26
  switch (connect_addr.addr.sa.sa_family) {
254
0
#if COAP_IPV4_SUPPORT
255
26
  case AF_INET:
256
26
    if (connect_addr.addr.sin.sin_port == 0)
257
26
      connect_addr.addr.sin.sin_port = htons(default_port);
258
26
#if IP_RECVERR && defined(HAVE_STRUCT_CMSGHDR) && defined(HAVE_LINUX_ERRQUEUE_H)
259
26
    if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVERR, OPTVAL_T(&on),
260
26
                   sizeof(on)) == COAP_SOCKET_ERROR)
261
26
      coap_log_alert("coap_socket_connect_udp: setsockopt IP_RECVERR: %s\n",
262
26
                     coap_socket_strerror());
263
26
#endif /* IP_RECVERR && HAVE_STRUCT_CMSGHDR && HAVE_LINUX_ERRQUEUE_H */
264
26
    break;
265
0
#endif /* COAP_IPV4_SUPPORT */
266
0
#if COAP_IPV6_SUPPORT
267
0
  case AF_INET6:
268
0
    if (connect_addr.addr.sin6.sin6_port == 0)
269
0
      connect_addr.addr.sin6.sin6_port = htons(default_port);
270
    /* Configure the socket as dual-stacked */
271
0
    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
272
0
                   sizeof(off)) == COAP_SOCKET_ERROR)
273
0
      if (errno != ENOSYS) {
274
0
        coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
275
0
                      coap_socket_strerror());
276
0
      }
277
0
#if IPV6_RECVERR && defined(HAVE_STRUCT_CMSGHDR) && defined(HAVE_LINUX_ERRQUEUE_H)
278
0
    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVERR, OPTVAL_T(&on),
279
0
                   sizeof(on)) == COAP_SOCKET_ERROR)
280
0
      coap_log_alert("coap_socket_connect_udp: setsockopt IPV6_RECVERR: %s\n",
281
0
                     coap_socket_strerror());
282
0
#endif /* IPV6_RECVERR && HAVE_STRUCT_CMSGHDR && HAVE_LINUX_ERRQUEUE_H */
283
0
#endif /* COAP_IPV6_SUPPORT */
284
0
    break;
285
0
#if COAP_AF_UNIX_SUPPORT
286
0
  case AF_UNIX:
287
0
    break;
288
0
#endif /* COAP_AF_UNIX_SUPPORT */
289
0
#if COAP_AF_LLC_SUPPORT
290
0
  case AF_LLC:
291
0
    break;
292
0
#endif /* COAP_AF_LLC_SUPPORT */
293
0
  default:
294
0
    coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
295
0
                   connect_addr.addr.sa.sa_family);
296
0
    goto error;;
297
26
  }
298
299
26
  if (local_if && local_if->addr.sa.sa_family) {
300
0
    if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
301
0
      coap_log_warn("coap_socket_connect_udp: local address family != "
302
0
                    "remote address family\n");
303
0
      goto error;
304
0
    }
305
0
    if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
306
0
      coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
307
0
                    coap_socket_strerror());
308
0
    if (bind(sock->fd, &local_if->addr.sa,
309
0
#if COAP_IPV4_SUPPORT
310
0
             local_if->addr.sa.sa_family == AF_INET ?
311
0
             (socklen_t)sizeof(struct sockaddr_in) :
312
0
#endif /* COAP_IPV4_SUPPORT */
313
0
             (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
314
0
      coap_log_warn("coap_socket_connect_udp: bind: %s\n",
315
0
                    coap_socket_strerror());
316
0
      goto error;
317
0
    }
318
0
#if COAP_AF_UNIX_SUPPORT
319
26
  } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
320
    /* Need to bind to a local address for clarity over endpoints */
321
0
    coap_log_warn("coap_socket_connect_udp: local address required\n");
322
0
    goto error;
323
0
#endif /* COAP_AF_UNIX_SUPPORT */
324
0
  }
325
326
  /* special treatment for sockets that are used for multicast communication */
327
26
  if (is_mcast) {
328
0
    if (!(local_if && local_if->addr.sa.sa_family)) {
329
      /* Bind to a (unused) port to simplify logging */
330
0
      coap_address_t bind_addr;
331
332
0
      coap_address_init(&bind_addr);
333
0
      bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
334
0
      if (bind(sock->fd, &bind_addr.addr.sa,
335
0
#if COAP_IPV4_SUPPORT
336
0
               bind_addr.addr.sa.sa_family == AF_INET ?
337
0
               (socklen_t)sizeof(struct sockaddr_in) :
338
0
#endif /* COAP_IPV4_SUPPORT */
339
0
               (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
340
0
        coap_log_warn("coap_socket_connect_udp: bind: %s\n",
341
0
                      coap_socket_strerror());
342
0
        goto error;
343
0
      }
344
0
    }
345
0
    if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
346
0
      coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
347
0
                    coap_socket_strerror());
348
0
    }
349
0
    coap_address_copy(remote_addr, &connect_addr);
350
0
    coap_address_copy(&sock->mcast_addr, &connect_addr);
351
0
    sock->flags |= COAP_SOCKET_MULTICAST;
352
0
    if (coap_is_bcast(server) &&
353
0
        setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
354
0
                   sizeof(on)) == COAP_SOCKET_ERROR)
355
0
      coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
356
0
                    coap_socket_strerror());
357
0
    return 1;
358
0
  }
359
360
26
  switch (connect_addr.addr.sa.sa_family) {
361
0
#if COAP_AF_LLC_SUPPORT
362
  /* Only SOCK_STREAM type AF_LLC sockets can be connect()ed. */
363
0
  case AF_LLC:
364
0
    break;
365
0
#endif /* COAP_AF_LLC_SUPPORT */
366
0
#if COAP_AF_UNIX_SUPPORT
367
0
  case AF_UNIX:
368
0
#endif /* COAP_AF_UNIX_SUPPORT */
369
26
  default:
370
26
    if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
371
0
#if COAP_AF_UNIX_SUPPORT
372
0
      if (connect_addr.addr.sa.sa_family == AF_UNIX) {
373
0
        coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
374
0
                      connect_addr.addr.cun.sun_path, coap_socket_strerror());
375
0
      } else
376
0
#endif /* COAP_AF_UNIX_SUPPORT */
377
0
      {
378
0
        coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
379
0
                      coap_socket_strerror(), connect_addr.addr.sa.sa_family);
380
0
      }
381
0
      goto error;
382
0
    }
383
384
26
    if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
385
0
      coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
386
0
                    coap_socket_strerror());
387
0
    }
388
26
    break;
389
26
  }
390
391
26
  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
392
0
    coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
393
0
                  coap_socket_strerror());
394
0
  }
395
396
26
#if COAP_AF_LLC_SUPPORT
397
  /* AF_LLC sockets send to the local address without an explicit destination. */
398
26
  if (coap_is_af_llc(&connect_addr))
399
0
    sock->flags |= COAP_SOCKET_WANT_SENDTO;
400
26
#endif /* COAP_AF_LLC_SUPPORT */
401
402
26
  sock->flags |= COAP_SOCKET_CONNECTED;
403
26
  return 1;
404
405
0
error:
406
0
  coap_socket_dgrm_close(sock);
407
0
  return 0;
408
26
}
409
#endif /* COAP_CLIENT_SUPPORT */
410
411
#if !defined(__ZEPHYR__)
412
#if 0 == ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
413
/* define struct in6_pktinfo and struct in_pktinfo if not available
414
   FIXME: check with configure
415
*/
416
#if !defined(__MINGW32__)
417
struct in6_pktinfo {
418
  struct in6_addr ipi6_addr;        /* src/dst IPv6 address */
419
  unsigned int ipi6_ifindex;        /* send/recv interface index */
420
};
421
422
struct in_pktinfo {
423
  int ipi_ifindex;
424
  struct in_addr ipi_spec_dst;
425
  struct in_addr ipi_addr;
426
};
427
#endif /* ! __MINGW32__ */
428
#endif
429
#endif /* ! __ZEPHYR__ */
430
431
#if !defined(SOL_IP)
432
/* Solaris expects level IPPROTO_IP for ancillary data. */
433
#define SOL_IP IPPROTO_IP
434
#endif
435
#ifdef _WIN32
436
#define COAP_SOL_IP IPPROTO_IP
437
#else /* ! _WIN32 */
438
0
#define COAP_SOL_IP SOL_IP
439
#endif /* ! _WIN32 */
440
441
#if defined(_WIN32)
442
#include <mswsock.h>
443
#if defined(__MINGW32__)
444
static __thread LPFN_WSARECVMSG lpWSARecvMsg = NULL;
445
#if(_WIN32_WINNT >= 0x0600)
446
#define CMSG_FIRSTHDR WSA_CMSG_FIRSTHDR
447
#define CMSG_NXTHDR WSA_CMSG_NXTHDR
448
#define CMSG_LEN WSA_CMSG_LEN
449
#define CMSG_SPACE WSA_CMSG_SPACE
450
#if(_WIN32_WINNT < 0x0603 || _WIN32_WINNT == 0x0a00)
451
#define cmsghdr _WSACMSGHDR
452
#endif /* (_WIN32_WINNT<0x0603 || _WIN32_WINNT == 0x0a00) */
453
#endif /* (_WIN32_WINNT>=0x0600) */
454
#else /* ! __MINGW32__ */
455
static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
456
#endif /* ! __MINGW32__ */
457
/* Map struct WSABUF fields to their posix counterpart */
458
#define msghdr _WSAMSG
459
#define msg_name name
460
#define msg_namelen namelen
461
#define msg_iov lpBuffers
462
#define msg_iovlen dwBufferCount
463
#define msg_control Control.buf
464
#define msg_controllen Control.len
465
#define iovec _WSABUF
466
#define iov_base buf
467
#define iov_len len
468
#define iov_len_t u_long
469
#undef CMSG_DATA
470
#define CMSG_DATA WSA_CMSG_DATA
471
#define ipi_spec_dst ipi_addr
472
#if !defined(__MINGW32__)
473
#pragma warning( disable : 4116 )
474
#endif /* ! __MINGW32__ */
475
#else
476
#define iov_len_t size_t
477
#endif
478
479
#if defined(_CYGWIN_ENV) || defined(__QNXNTO__)
480
#define ipi_spec_dst ipi_addr
481
#endif
482
483
#if COAP_CLIENT_SUPPORT
484
static uint32_t cid_track_counter;
485
486
static void
487
187
coap_test_cid_tuple_change(coap_session_t *session) {
488
187
  if (session->type == COAP_SESSION_TYPE_CLIENT &&
489
187
      session->negotiated_cid &&
490
0
      session->state == COAP_SESSION_STATE_ESTABLISHED &&
491
0
      session->proto == COAP_PROTO_DTLS && session->context->testing_cids) {
492
0
    if ((++cid_track_counter) % session->context->testing_cids == 0) {
493
0
      coap_address_t local_if = session->addr_info.local;
494
0
      uint16_t port = coap_address_get_port(&local_if);
495
496
0
      port++;
497
0
      coap_address_set_port(&local_if, port);
498
499
0
      coap_socket_dgrm_close(&session->sock);
500
0
      session->sock.session = session;
501
0
      if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
502
0
                                   port,
503
0
                                   &session->addr_info.local,
504
0
                                   &session->addr_info.remote)) {
505
0
        coap_log_err("Tuple change for CID failed\n");
506
0
        return;
507
0
#ifdef COAP_EPOLL_SUPPORT
508
0
      } else {
509
0
        coap_epoll_ctl_add(&session->sock,
510
0
                           EPOLLIN |
511
0
                           ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
512
0
                            EPOLLOUT : 0),
513
0
                           __func__);
514
0
#endif /* COAP_EPOLL_SUPPORT */
515
0
      }
516
0
      session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ | COAP_SOCKET_BOUND;
517
0
    }
518
0
  }
519
187
}
520
#endif /* COAP_CLIENT_SUPPORT */
521
522
#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
523
static ssize_t
524
0
coap_get_icmp_data(coap_socket_t *sock, uint8_t *data, size_t length) {
525
0
  coap_fd_t fd = sock->fd;
526
0
  char control_buf[1024];
527
0
  struct iovec iov;
528
0
  struct msghdr msg;
529
0
  struct cmsghdr *cmsg;
530
0
  int kerrno = errno;
531
0
  int ret;
532
533
0
  if (length < sizeof(coap_icmp_info_t)) {
534
0
    return -1;
535
0
  }
536
0
  iov.iov_base = data + sizeof(coap_icmp_info_t);
537
0
  iov.iov_len = length - sizeof(coap_icmp_info_t);;
538
539
0
  memset(&msg, 0, sizeof(msg));
540
0
  msg.msg_name = NULL;
541
0
  msg.msg_namelen = 0;
542
0
  msg.msg_iov = &iov;
543
0
  msg.msg_iovlen = 1;
544
0
  msg.msg_control = control_buf;
545
0
  msg.msg_controllen = sizeof(control_buf);
546
547
  /* Poll for errors using MSG_ERRQUEUE */
548
0
  ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
549
0
  errno = kerrno;
550
0
  if (ret < 0) {
551
0
    return -1;
552
0
  }
553
554
  /* Parse control messages, looking for ICMP error messages */
555
0
  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
556
0
#if COAP_IPV4_SUPPORT && IP_RECVERR
557
0
    if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) {
558
0
      struct sock_extended_err *err = (struct sock_extended_err *)CMSG_DATA(cmsg);
559
0
      coap_icmp_info_t *info = (coap_icmp_info_t *)data;
560
561
0
      if (err->ee_origin == SO_EE_ORIGIN_ICMP) {
562
0
        info->length = (uint32_t)ret;
563
0
        info->cmsg_level = cmsg->cmsg_level;
564
0
        info->ee_origin = err->ee_origin;
565
0
        info->ee_type = err->ee_type;
566
0
        info->ee_code = err->ee_code;
567
0
#if COAP_SERVER_SUPPORT
568
0
        coap_log_debug("*  %s: ICMP Error Type: %d, Code: %d\n",
569
0
                       sock->endpoint ? coap_endpoint_str(sock->endpoint) :
570
0
                       coap_session_str(sock->session),
571
0
                       err->ee_type, err->ee_code);
572
#else /* ! COAP_SERVER_SUPPORT */
573
        coap_log_debug("*  %s: ICMP Error Type: %d, Code: %d\n",
574
                       coap_session_str(sock->session),
575
                       err->ee_type, err->ee_code);
576
#endif /* ! COAP_SERVER_SUPPORT */
577
0
        return ret;
578
0
      }
579
0
    }
580
0
#endif /* COAP_IPV4_SUPPORT && IP_RECVERR */
581
0
#if COAP_IPV6_SUPPORT && IPV6_RECVERR
582
0
    if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR) {
583
0
      struct sock_extended_err *err = (struct sock_extended_err *)CMSG_DATA(cmsg);
584
0
      coap_icmp_info_t *info = (coap_icmp_info_t *)data;
585
586
0
      if (err->ee_origin == SO_EE_ORIGIN_ICMP6 || err->ee_origin == SO_EE_ORIGIN_ICMP) {
587
0
        info->length = (uint32_t)ret;
588
0
        info->cmsg_level = cmsg->cmsg_level;
589
0
        info->ee_origin = err->ee_origin;
590
0
        info->ee_type = err->ee_type;
591
0
        info->ee_code = err->ee_code;
592
0
#if COAP_SERVER_SUPPORT
593
0
        coap_log_debug("*  %s: ICMP%s Error Type: %d, Code: %d\n",
594
0
                       sock->endpoint ? coap_endpoint_str(sock->endpoint) :
595
0
                       coap_session_str(sock->session),
596
0
                       err->ee_origin == SO_EE_ORIGIN_ICMP6 ? "6" : "",
597
0
                       err->ee_type, err->ee_code);
598
#else /* ! COAP_SERVER_SUPPORT */
599
        coap_log_debug("*  %s: ICMP%s Error Type: %d, Code: %d\n",
600
                       coap_session_str(sock->session),
601
                       err->ee_origin == SO_EE_ORIGIN_ICMP6 ? "6" : "",
602
                       err->ee_type, err->ee_code);
603
#endif /* ! COAP_SERVER_SUPPORT */
604
0
        return ret;
605
0
      }
606
0
    }
607
0
#endif /* COAP_IPV6_SUPPORT && IPV6_RECVERR */
608
0
    coap_log_debug("MSG_ERRQUEUE: Level %d, Type: %d\n", cmsg->cmsg_level, cmsg->cmsg_type);
609
0
  }
610
0
  return -1;
611
0
}
612
#endif /* HAVE_LINUX_ERRQUEUE_H && HAVE_STRUCT_CMSGHDR */
613
614
/*
615
 * dgram
616
 * return +ve Number of bytes written.
617
 *         -1 Error error in errno).
618
 */
619
ssize_t
620
coap_socket_send(coap_socket_t *sock, coap_session_t *session,
621
187
                 const uint8_t *data, size_t datalen) {
622
187
  ssize_t bytes_written = 0;
623
187
  int r;
624
625
187
#if COAP_CLIENT_SUPPORT
626
187
  coap_test_cid_tuple_change(session);
627
187
#endif /* COAP_CLIENT_SUPPORT */
628
629
187
  if ((r = coap_debug_send_packet()) != 1) {
630
187
    if (r)
631
92
      bytes_written = -1;
632
95
    else
633
95
      bytes_written = (ssize_t)datalen;
634
187
  } else if (sock->flags & COAP_SOCKET_CONNECTED &&
635
0
             !(sock->flags & COAP_SOCKET_WANT_SENDTO)) {
636
#ifdef _WIN32
637
    bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
638
#else
639
0
    bytes_written = send(sock->fd, data, datalen, 0);
640
0
#endif
641
0
  } else {
642
#if defined(_WIN32)
643
    DWORD dwNumberOfBytesSent = 0;
644
#endif /* _WIN32 */
645
0
#ifdef HAVE_STRUCT_CMSGHDR
646
    /* a buffer large enough to hold all packet info types, ipv6 is the largest */
647
0
    char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
648
0
    struct msghdr mhdr;
649
0
    struct iovec iov[1];
650
0
    const void *addr = &session->addr_info.remote.addr;
651
652
0
    assert(session);
653
654
0
    memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
655
0
    iov[0].iov_len = (iov_len_t)datalen;
656
657
0
    memset(buf, 0, sizeof(buf));
658
659
0
    memset(&mhdr, 0, sizeof(struct msghdr));
660
0
    memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
661
0
    mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
662
0
                       (socklen_t)sizeof(struct sockaddr_in) :
663
0
                       session->addr_info.remote.size;
664
665
0
    mhdr.msg_iov = iov;
666
0
    mhdr.msg_iovlen = 1;
667
668
0
    if (!coap_address_isany(&session->addr_info.local) &&
669
0
        !coap_is_mcast(&session->addr_info.local)) {
670
0
      switch (session->addr_info.local.addr.sa.sa_family) {
671
0
#if COAP_IPV6_SUPPORT
672
0
      case AF_INET6: {
673
0
        struct cmsghdr *cmsg;
674
675
0
#if COAP_IPV4_SUPPORT
676
0
        if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
677
0
#if defined(IP_PKTINFO)
678
0
          struct in_pktinfo *pktinfo;
679
0
          mhdr.msg_control = buf;
680
0
          mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
681
682
0
          cmsg = CMSG_FIRSTHDR(&mhdr);
683
0
          cmsg->cmsg_level = COAP_SOL_IP;
684
0
          cmsg->cmsg_type = IP_PKTINFO;
685
0
          cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
686
687
0
          pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
688
689
0
          pktinfo->ipi_ifindex = session->ifindex;
690
0
          memcpy(&pktinfo->ipi_spec_dst,
691
0
                 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
692
0
                 sizeof(pktinfo->ipi_spec_dst));
693
#elif defined(IP_SENDSRCADDR)
694
          mhdr.msg_control = buf;
695
          mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
696
697
          cmsg = CMSG_FIRSTHDR(&mhdr);
698
          cmsg->cmsg_level = IPPROTO_IP;
699
          cmsg->cmsg_type = IP_SENDSRCADDR;
700
          cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
701
702
          memcpy(CMSG_DATA(cmsg),
703
                 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
704
                 sizeof(struct in_addr));
705
#endif /* IP_PKTINFO */
706
0
        } else {
707
0
#endif /* COAP_IPV4_SUPPORT */
708
0
          struct in6_pktinfo *pktinfo;
709
0
          mhdr.msg_control = buf;
710
0
          mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
711
712
0
          cmsg = CMSG_FIRSTHDR(&mhdr);
713
0
          cmsg->cmsg_level = IPPROTO_IPV6;
714
0
          cmsg->cmsg_type = IPV6_PKTINFO;
715
0
          cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
716
717
0
          pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
718
719
0
          if (coap_is_mcast(&session->addr_info.remote)) {
720
0
            pktinfo->ipi6_ifindex = session->addr_info.remote.addr.sin6.sin6_scope_id;
721
0
          } else {
722
0
            pktinfo->ipi6_ifindex = session->ifindex;
723
0
          }
724
0
          memcpy(&pktinfo->ipi6_addr,
725
0
                 &session->addr_info.local.addr.sin6.sin6_addr,
726
0
                 sizeof(pktinfo->ipi6_addr));
727
0
#if COAP_IPV4_SUPPORT
728
0
        }
729
0
#endif /* COAP_IPV4_SUPPORT */
730
0
        break;
731
0
      }
732
0
#endif /* COAP_IPV6_SUPPORT */
733
0
#if COAP_IPV4_SUPPORT
734
0
      case AF_INET: {
735
0
#if defined(IP_PKTINFO)
736
0
        struct cmsghdr *cmsg;
737
0
        struct in_pktinfo *pktinfo;
738
739
0
        mhdr.msg_control = buf;
740
0
        mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
741
742
0
        cmsg = CMSG_FIRSTHDR(&mhdr);
743
0
        cmsg->cmsg_level = COAP_SOL_IP;
744
0
        cmsg->cmsg_type = IP_PKTINFO;
745
0
        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
746
747
0
        pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
748
749
0
        pktinfo->ipi_ifindex = session->ifindex;
750
0
        memcpy(&pktinfo->ipi_spec_dst,
751
0
               &session->addr_info.local.addr.sin.sin_addr,
752
0
               sizeof(pktinfo->ipi_spec_dst));
753
#elif defined(IP_SENDSRCADDR)
754
        struct cmsghdr *cmsg;
755
        mhdr.msg_control = buf;
756
        mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
757
758
        cmsg = CMSG_FIRSTHDR(&mhdr);
759
        cmsg->cmsg_level = IPPROTO_IP;
760
        cmsg->cmsg_type = IP_SENDSRCADDR;
761
        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
762
763
        memcpy(CMSG_DATA(cmsg),
764
               &session->addr_info.local.addr.sin.sin_addr,
765
               sizeof(struct in_addr));
766
#endif /* IP_PKTINFO */
767
0
        break;
768
0
      }
769
0
#endif /* COAP_IPV4_SUPPORT */
770
0
#if COAP_AF_UNIX_SUPPORT
771
0
      case AF_UNIX:
772
0
        break;
773
0
#endif /* COAP_AF_UNIX_SUPPORT */
774
0
#if COAP_AF_LLC_SUPPORT
775
0
      case AF_LLC:
776
0
        break;
777
0
#endif /* COAP_AF_LLC_SUPPORT */
778
0
      default:
779
        /* error */
780
0
        coap_log_warn("protocol not supported\n");
781
0
        return -1;
782
0
      }
783
0
    }
784
0
#endif /* HAVE_STRUCT_CMSGHDR */
785
786
#if defined(_WIN32)
787
    r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
788
                   NULL /*lpCompletionRoutine*/);
789
    if (r == 0)
790
      bytes_written = (ssize_t)dwNumberOfBytesSent;
791
    else {
792
      bytes_written = -1;
793
      coap_win_error_to_errno();
794
    }
795
#else /* !_WIN32 */
796
0
#ifdef HAVE_STRUCT_CMSGHDR
797
0
    bytes_written = sendmsg(sock->fd, &mhdr, 0);
798
#else /* ! HAVE_STRUCT_CMSGHDR */
799
    bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
800
                           &session->addr_info.remote.addr.sa,
801
                           session->addr_info.remote.size);
802
#endif /* ! HAVE_STRUCT_CMSGHDR */
803
0
#endif /* !_WIN32 */
804
0
  }
805
806
187
  if (bytes_written < 0)
807
187
    coap_log_warn("coap_socket_send: %s\n", coap_socket_strerror());
808
809
187
  return bytes_written;
810
187
}
811
812
#define SIN6(A) ((struct sockaddr_in6 *)(A))
813
814
/*
815
 * dgram
816
 * return +ve Number of bytes written.
817
 *         -1 Error error in errno).
818
 *         -2 ICMP error response
819
 */
820
ssize_t
821
0
coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet) {
822
0
  ssize_t len = -1;
823
0
#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
824
0
  ssize_t ret;
825
0
#endif /* HAVE_LINUX_ERRQUEUE_H && HAVE_STRUCT_CMSGHDR */
826
827
0
  assert(sock);
828
0
  assert(packet);
829
830
0
  if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
831
0
    return -1;
832
0
  } else {
833
    /* clear has-data flag */
834
0
    sock->flags &= ~COAP_SOCKET_CAN_READ;
835
0
  }
836
837
0
  if (sock->flags & COAP_SOCKET_CONNECTED) {
838
#ifdef _WIN32
839
    len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
840
#else
841
0
    len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
842
0
#endif
843
0
    if (len < 0) {
844
#ifdef _WIN32
845
      coap_win_error_to_errno();
846
#endif /* _WIN32 */
847
848
0
#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
849
0
      ret = coap_get_icmp_data(sock, packet->payload, COAP_RXBUFFER_SIZE);
850
0
      if (ret >= 4) {
851
        /* Information about the ICMP diagnostic packet is in packet->payload */
852
0
        return -2;
853
0
      }
854
0
#endif /* HAVE_LINUX_ERRQUEUE_H && HAVE_STRUCT_CMSGHDR */
855
0
      if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
856
        /* client-side ICMP destination unreachable, ignore it */
857
0
        coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
858
0
                      sock->session ?
859
0
                      coap_session_str(sock->session) : "",
860
0
                      coap_socket_strerror());
861
0
        goto error;
862
0
      }
863
0
      if (errno != EAGAIN) {
864
0
        coap_log_warn("** %s: coap_socket_recv: %s\n",
865
0
                      sock->session ?
866
0
                      coap_session_str(sock->session) : "",
867
0
                      coap_socket_strerror());
868
0
      }
869
0
      goto error;
870
0
    } else if (len > 0) {
871
0
      packet->length = (size_t)len;
872
0
    }
873
0
  } else {
874
#if defined(_WIN32)
875
    DWORD dwNumberOfBytesRecvd = 0;
876
    int r;
877
#endif /* _WIN32 */
878
0
#ifdef HAVE_STRUCT_CMSGHDR
879
    /* a buffer large enough to hold all packet info types, ipv6 is the largest */
880
0
    char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
881
0
    struct cmsghdr *cmsg;
882
0
    struct msghdr mhdr;
883
0
    struct iovec iov[1];
884
885
#if defined(__MINGW32__)
886
    iov[0].iov_base = (char *) packet->payload;
887
#else /* ! __MINGW32__ */
888
0
    iov[0].iov_base = packet->payload;
889
0
#endif /* defined(__MINGW32__) */
890
0
    iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
891
892
0
    memset(&mhdr, 0, sizeof(struct msghdr));
893
894
0
    mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
895
0
    mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
896
897
0
    mhdr.msg_iov = iov;
898
0
    mhdr.msg_iovlen = 1;
899
900
0
    mhdr.msg_control = buf;
901
0
    mhdr.msg_controllen = sizeof(buf);
902
    /* set a big first length incase recvmsg() does not implement updating
903
       msg_control as well as preset the first cmsg with bad data */
904
0
    cmsg = (struct cmsghdr *)buf;
905
0
    cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
906
0
    cmsg->cmsg_level = -1;
907
0
    cmsg->cmsg_type = -1;
908
909
#if defined(_WIN32)
910
    if (!lpWSARecvMsg) {
911
      GUID wsaid = WSAID_WSARECVMSG;
912
      DWORD cbBytesReturned = 0;
913
      if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
914
                   sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
915
        coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
916
        return -1;
917
      }
918
    }
919
    r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
920
                     NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
921
    if (r == 0)
922
      len = (ssize_t)dwNumberOfBytesRecvd;
923
    else if (r == COAP_SOCKET_ERROR)
924
      coap_win_error_to_errno();
925
#else
926
0
    len = recvmsg(sock->fd, &mhdr, 0);
927
0
#endif
928
929
#else /* ! HAVE_STRUCT_CMSGHDR */
930
    len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
931
                   &packet->addr_info.remote.addr.sa,
932
                   &packet->addr_info.remote.size);
933
#endif /* ! HAVE_STRUCT_CMSGHDR */
934
935
0
    if (len < 0) {
936
#ifdef _WIN32
937
      coap_win_error_to_errno();
938
#endif /* _WIN32 */
939
0
      if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
940
        /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
941
0
        coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
942
0
                      sock->session ?
943
0
                      coap_session_str(sock->session) : "",
944
0
                      coap_socket_strerror());
945
0
        return 0;
946
0
      }
947
0
      if (errno != EAGAIN) {
948
0
        coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
949
0
      }
950
0
      goto error;
951
0
    } else {
952
0
#ifdef HAVE_STRUCT_CMSGHDR
953
0
      int dst_found = 0;
954
955
0
      packet->addr_info.remote.size = mhdr.msg_namelen;
956
0
      packet->length = (size_t)len;
957
958
      /* Walk through ancillary data records until the local interface
959
       * is found where the data was received. */
960
0
      for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
961
962
0
#if COAP_IPV6_SUPPORT
963
        /* get the local interface for IPv6 */
964
0
        if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
965
0
          union {
966
0
            uint8_t *c;
967
0
            struct in6_pktinfo *p;
968
0
          } u;
969
0
          u.c = CMSG_DATA(cmsg);
970
0
          packet->ifindex = (int)(u.p->ipi6_ifindex);
971
0
          memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
972
0
                 &u.p->ipi6_addr, sizeof(struct in6_addr));
973
0
          dst_found = 1;
974
0
          break;
975
0
        }
976
0
#endif /* COAP_IPV6_SUPPORT */
977
978
0
#if COAP_IPV4_SUPPORT
979
        /* local interface for IPv4 */
980
0
#if defined(IP_PKTINFO)
981
0
        if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
982
0
          union {
983
0
            uint8_t *c;
984
0
            struct in_pktinfo *p;
985
0
          } u;
986
0
          u.c = CMSG_DATA(cmsg);
987
0
          packet->ifindex = u.p->ipi_ifindex;
988
0
#if COAP_IPV6_SUPPORT
989
0
          if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
990
0
            memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
991
0
            packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
992
0
            packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
993
0
            memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
994
0
                   &u.p->ipi_addr, sizeof(struct in_addr));
995
0
          } else
996
0
#endif /* COAP_IPV6_SUPPORT */
997
0
          {
998
0
            memcpy(&packet->addr_info.local.addr.sin.sin_addr,
999
0
                   &u.p->ipi_addr, sizeof(struct in_addr));
1000
0
          }
1001
0
          dst_found = 1;
1002
0
          break;
1003
0
        }
1004
0
#endif /* IP_PKTINFO */
1005
#if defined(IP_RECVDSTADDR)
1006
        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
1007
          packet->ifindex = (int)sock->fd;
1008
          memcpy(&packet->addr_info.local.addr.sin.sin_addr,
1009
                 CMSG_DATA(cmsg), sizeof(struct in_addr));
1010
          dst_found = 1;
1011
          break;
1012
        }
1013
#endif /* IP_RECVDSTADDR */
1014
0
#endif /* COAP_IPV4_SUPPORT */
1015
0
        if (!dst_found) {
1016
          /* cmsg_level / cmsg_type combination we do not understand
1017
             (ignore preset case for bad recvmsg() not updating cmsg) */
1018
0
          if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1019
0
            coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1020
0
                           cmsg->cmsg_level, cmsg->cmsg_type);
1021
0
          }
1022
0
        }
1023
0
      }
1024
0
      if (!dst_found) {
1025
        /* Not expected, but cmsg_level and cmsg_type don't match above and
1026
           may need a new case */
1027
0
        packet->ifindex = (int)sock->fd;
1028
0
        if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1029
0
                        &packet->addr_info.local.size) < 0) {
1030
0
          coap_log_debug("Cannot determine local port\n");
1031
0
        }
1032
0
      }
1033
#else /* ! HAVE_STRUCT_CMSGHDR */
1034
      packet->length = (size_t)len;
1035
      packet->ifindex = 0;
1036
      if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1037
                      &packet->addr_info.local.size) < 0) {
1038
        coap_log_debug("Cannot determine local port\n");
1039
        goto error;
1040
      }
1041
#endif /* ! HAVE_STRUCT_CMSGHDR */
1042
0
    }
1043
0
  }
1044
1045
0
  if (len >= 0)
1046
0
    return len;
1047
0
error:
1048
0
  return -1;
1049
0
}
1050
1051
void
1052
26
coap_socket_dgrm_close(coap_socket_t *sock) {
1053
26
  if (sock->fd != COAP_INVALID_SOCKET && !(sock->flags & COAP_SOCKET_SLAVE)) {
1054
26
#ifdef COAP_EPOLL_SUPPORT
1055
26
#if COAP_SERVER_SUPPORT
1056
26
    coap_context_t *context = sock->session ? sock->session->context :
1057
26
                              sock->endpoint ? sock->endpoint->context : NULL;
1058
#else /* ! COAP_SERVER_SUPPORT */
1059
    coap_context_t *context = sock->session ? sock->session->context : NULL;
1060
#endif /* ! COAP_SERVER_SUPPORT */
1061
26
    if (context != NULL) {
1062
26
      int ret;
1063
26
      struct epoll_event event;
1064
1065
      /* Kernels prior to 2.6.9 expect non NULL event parameter */
1066
26
      ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
1067
26
      if (ret == -1 && errno != ENOENT) {
1068
0
        coap_log_err("%s: epoll_ctl DEL failed: %d: %s (%d)\n",
1069
0
                     "coap_socket_close",
1070
0
                     sock->fd,
1071
0
                     coap_socket_strerror(), errno);
1072
0
      }
1073
26
    }
1074
26
#endif /* COAP_EPOLL_SUPPORT */
1075
26
#if COAP_SERVER_SUPPORT
1076
26
#if COAP_AF_UNIX_SUPPORT
1077
26
    if (sock->endpoint &&
1078
0
        sock->endpoint->bind_addr.addr.sa.sa_family == AF_UNIX) {
1079
      /* Clean up Unix endpoint */
1080
#ifdef _WIN32
1081
      _unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
1082
#else /* ! _WIN32 */
1083
0
      unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
1084
0
#endif /* ! _WIN32 */
1085
0
    }
1086
26
#endif /* COAP_AF_UNIX_SUPPORT */
1087
26
    sock->endpoint = NULL;
1088
26
#endif /* COAP_SERVER_SUPPORT */
1089
26
#if COAP_CLIENT_SUPPORT
1090
26
#if COAP_AF_UNIX_SUPPORT
1091
26
    if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
1092
26
        sock->session->addr_info.local.addr.sa.sa_family == AF_UNIX) {
1093
      /* Clean up Unix endpoint */
1094
#ifdef _WIN32
1095
      _unlink(sock->session->addr_info.local.addr.cun.sun_path);
1096
#else /* ! _WIN32 */
1097
0
      unlink(sock->session->addr_info.local.addr.cun.sun_path);
1098
0
#endif /* ! _WIN32 */
1099
0
    }
1100
26
#endif /* COAP_AF_UNIX_SUPPORT */
1101
26
#endif /* COAP_CLIENT_SUPPORT */
1102
26
    sock->session = NULL;
1103
26
    coap_closesocket(sock->fd);
1104
26
    sock->fd = COAP_INVALID_SOCKET;
1105
26
    sock->flags = COAP_SOCKET_EMPTY;
1106
26
  }
1107
26
}
1108
1109
#else /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */
1110
1111
#ifdef __clang__
1112
/* Make compilers happy that do not like empty modules. As this function is
1113
 * never used, we ignore -Wunused-function at the end of compiling this file
1114
 */
1115
#pragma GCC diagnostic ignored "-Wunused-function"
1116
#endif
1117
static inline void
1118
dummy(void) {
1119
}
1120
1121
#endif /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */