libcoap 4.3.5-develop-490e4e0
Loading...
Searching...
No Matches
coap_dgrm_posix.c
Go to the documentation of this file.
1/*
2 * coap_dgrm_posix.c -- Datagram (UDP) functions for libcoap
3 *
4 * Copyright (C) 2019-2025 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
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# 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_WS2TCPIP_H
44#include <ws2tcpip.h>
45# define OPTVAL_T(t) (const char*)(t)
46# define OPTVAL_GT(t) (char*)(t)
47# undef CMSG_DATA
48# define CMSG_DATA WSA_CMSG_DATA
49#endif
50#ifdef HAVE_SYS_UIO_H
51# include <sys/uio.h>
52#endif
53#ifdef _WIN32
54#include <stdio.h>
55#endif /* _WIN32 */
56#ifdef COAP_EPOLL_SUPPORT
57#include <sys/epoll.h>
58#include <sys/timerfd.h>
59#ifdef HAVE_LIMITS_H
60#include <limits.h>
61#endif
62#endif /* COAP_EPOLL_SUPPORT */
63#else /* __ZEPHYR__ */
64#include <sys/ioctl.h>
65#include <sys/select.h>
66#define OPTVAL_T(t) (const void*)(t)
67#define OPTVAL_GT(t) (void*)(t)
68
69#ifndef IPV6_PKTINFO
70#ifdef IPV6_RECVPKTINFO
71#define IPV6_PKTINFO IPV6_RECVPKTINFO
72#else
73#define IPV6_PKTINFO IP_PKTINFO
74#endif
75#ifndef IN6_IS_ADDR_V4MAPPED
76#define IN6_IS_ADDR_V4MAPPED(a) \
77 ((((a)->s6_addr32[0]) == 0) && (((a)->s6_addr32[1]) == 0) && \
78 (((a)->s6_addr32[2]) == htonl(0xffff)))
79#endif
80#endif
81#endif /* __ZEPHYR__ */
82
83/* define generic PKTINFO for IPv4 */
84#if defined(IP_PKTINFO)
85# define GEN_IP_PKTINFO IP_PKTINFO
86#elif defined(IP_RECVDSTADDR)
87# define GEN_IP_PKTINFO IP_RECVDSTADDR
88#else
89# error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
90#endif /* IP_PKTINFO */
91
92/* define generic PKTINFO for IPv6 */
93#ifdef IPV6_RECVPKTINFO
94# define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
95#elif defined(IPV6_PKTINFO)
96# define GEN_IPV6_PKTINFO IPV6_PKTINFO
97#else
98# error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
99#endif /* IPV6_RECVPKTINFO */
100
101#if COAP_SERVER_SUPPORT
102int
104 const coap_address_t *listen_addr,
105 coap_address_t *bound_addr) {
106 int on = 1;
107#if COAP_IPV6_SUPPORT
108 int off = 0;
109#endif /* COAP_IPV6_SUPPORT */
110#ifdef _WIN32
111 u_long u_on = 1;
112#endif
113
114 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
115
116 if (sock->fd == COAP_INVALID_SOCKET) {
117 coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
118 goto error;
119 }
120#ifdef _WIN32
121 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
122#else
123 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
124#endif
125 {
126 coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
127 }
128
129 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
130 coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
132
133 switch (listen_addr->addr.sa.sa_family) {
134#if COAP_IPV4_SUPPORT
135 case AF_INET:
136 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
137 sizeof(on)) == COAP_SOCKET_ERROR)
138 coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
140 break;
141#endif /* COAP_IPV4_SUPPORT */
142#if COAP_IPV6_SUPPORT
143 case AF_INET6:
144 /* Configure the socket as dual-stacked */
145 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
146 sizeof(off)) == COAP_SOCKET_ERROR)
147 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
149#if !defined(ESPIDF_VERSION)
150 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
151 sizeof(on)) == COAP_SOCKET_ERROR)
152 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
154#endif /* !defined(ESPIDF_VERSION) */
155#endif /* COAP_IPV6_SUPPORT */
156 setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on));
157 /* ignore error, because likely cause is that IPv4 is disabled at the os
158 level */
159 break;
160#if COAP_AF_UNIX_SUPPORT
161 case AF_UNIX:
162 break;
163#endif /* COAP_AF_UNIX_SUPPORT */
164 default:
165 coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
166 break;
167 }
168
169 if (bind(sock->fd, &listen_addr->addr.sa,
171 listen_addr->addr.sa.sa_family == AF_INET ?
172 (socklen_t)sizeof(struct sockaddr_in) :
173#endif /* COAP_IPV4_SUPPORT */
174 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
175 coap_log_warn("coap_socket_bind_udp: bind: %s\n",
177 goto error;
178 }
179
180 bound_addr->size = (socklen_t)sizeof(*bound_addr);
181 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
182 coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
184 goto error;
185 }
186 return 1;
187
188error:
190 return 0;
191}
192#endif /* COAP_SERVER_SUPPORT */
193
194#if COAP_CLIENT_SUPPORT
195int
197 const coap_address_t *local_if,
198 const coap_address_t *server,
199 int default_port,
200 coap_address_t *local_addr,
201 coap_address_t *remote_addr) {
202 int on = 1;
203#if COAP_IPV6_SUPPORT
204 int off = 0;
205#endif /* COAP_IPV6_SUPPORT */
206#ifdef _WIN32
207 u_long u_on = 1;
208#endif
209 coap_address_t connect_addr;
210 int is_mcast = coap_is_mcast(server);
211 coap_address_copy(&connect_addr, server);
212
214 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
215
216 if (sock->fd == COAP_INVALID_SOCKET) {
217 coap_log_warn("coap_socket_connect_udp: socket: %s\n",
219 goto error;
220 }
221
222#ifdef _WIN32
223 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
224#else
225 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
226#endif
227 {
228 /* Ignore Zephyr unexpected Success response */
229 if (errno != 0) {
230 int keep_errno = errno;
231
232 coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s (%d)\n",
233 coap_socket_strerror(), keep_errno);
234 }
235 }
236
237 switch (connect_addr.addr.sa.sa_family) {
238#if COAP_IPV4_SUPPORT
239 case AF_INET:
240 if (connect_addr.addr.sin.sin_port == 0)
241 connect_addr.addr.sin.sin_port = htons(default_port);
242 break;
243#endif /* COAP_IPV4_SUPPORT */
244#if COAP_IPV6_SUPPORT
245 case AF_INET6:
246 if (connect_addr.addr.sin6.sin6_port == 0)
247 connect_addr.addr.sin6.sin6_port = htons(default_port);
248 /* Configure the socket as dual-stacked */
249 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
250 sizeof(off)) == COAP_SOCKET_ERROR)
251 if (errno != ENOSYS) {
252 coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
254 }
255#endif /* COAP_IPV6_SUPPORT */
256 break;
257#if COAP_AF_UNIX_SUPPORT
258 case AF_UNIX:
259 break;
260#endif /* COAP_AF_UNIX_SUPPORT */
261 default:
262 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
263 connect_addr.addr.sa.sa_family);
264 goto error;;
265 }
266
267 if (local_if && local_if->addr.sa.sa_family) {
268 if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
269 coap_log_warn("coap_socket_connect_udp: local address family != "
270 "remote address family\n");
271 goto error;
272 }
273 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
274 coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
276 if (bind(sock->fd, &local_if->addr.sa,
278 local_if->addr.sa.sa_family == AF_INET ?
279 (socklen_t)sizeof(struct sockaddr_in) :
280#endif /* COAP_IPV4_SUPPORT */
281 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
282 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
284 goto error;
285 }
286#if COAP_AF_UNIX_SUPPORT
287 } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
288 /* Need to bind to a local address for clarity over endpoints */
289 coap_log_warn("coap_socket_connect_udp: local address required\n");
290 goto error;
291#endif /* COAP_AF_UNIX_SUPPORT */
292 }
293
294 /* special treatment for sockets that are used for multicast communication */
295 if (is_mcast) {
296 if (!(local_if && local_if->addr.sa.sa_family)) {
297 /* Bind to a (unused) port to simplify logging */
298 coap_address_t bind_addr;
299
300 coap_address_init(&bind_addr);
301 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
302 if (bind(sock->fd, &bind_addr.addr.sa,
304 bind_addr.addr.sa.sa_family == AF_INET ?
305 (socklen_t)sizeof(struct sockaddr_in) :
306#endif /* COAP_IPV4_SUPPORT */
307 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
308 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
310 goto error;
311 }
312 }
313 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
314 coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
316 }
317 coap_address_copy(remote_addr, &connect_addr);
318 coap_address_copy(&sock->mcast_addr, &connect_addr);
320 if (coap_is_bcast(server) &&
321 setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
322 sizeof(on)) == COAP_SOCKET_ERROR)
323 coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
325 return 1;
326 }
327
328 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
329#if COAP_AF_UNIX_SUPPORT
330 if (connect_addr.addr.sa.sa_family == AF_UNIX) {
331 coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
332 connect_addr.addr.cun.sun_path, coap_socket_strerror());
333 } else
334#endif /* COAP_AF_UNIX_SUPPORT */
335 {
336 coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
337 coap_socket_strerror(), connect_addr.addr.sa.sa_family);
338 }
339 goto error;
340 }
341
342 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
343 coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
345 }
346
347 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
348 coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
350 }
351
353 return 1;
354
355error:
357 return 0;
358}
359#endif /* COAP_CLIENT_SUPPORT */
360
361#if !defined(__ZEPHYR__)
362#if 0 == ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_H) )
363/* define struct in6_pktinfo and struct in_pktinfo if not available
364 FIXME: check with configure
365*/
366#if !defined(__MINGW32__)
368 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
369 unsigned int ipi6_ifindex; /* send/recv interface index */
370};
371
374 struct in_addr ipi_spec_dst;
375 struct in_addr ipi_addr;
376};
377#endif /* ! __MINGW32__ */
378#endif
379#endif /* ! __ZEPHYR__ */
380
381#if !defined(SOL_IP)
382/* Solaris expects level IPPROTO_IP for ancillary data. */
383#define SOL_IP IPPROTO_IP
384#endif
385#ifdef _WIN32
386#define COAP_SOL_IP IPPROTO_IP
387#else /* ! _WIN32 */
388#define COAP_SOL_IP SOL_IP
389#endif /* ! _WIN32 */
390
391#if defined(_WIN32)
392#include <mswsock.h>
393#if defined(__MINGW32__)
394static __thread LPFN_WSARECVMSG lpWSARecvMsg = NULL;
395#if(_WIN32_WINNT >= 0x0600)
396#define CMSG_FIRSTHDR WSA_CMSG_FIRSTHDR
397#define CMSG_NXTHDR WSA_CMSG_NXTHDR
398#define CMSG_LEN WSA_CMSG_LEN
399#define CMSG_SPACE WSA_CMSG_SPACE
400#if(_WIN32_WINNT < 0x0603 || _WIN32_WINNT == 0x0a00)
401#define cmsghdr _WSACMSGHDR
402#endif /* (_WIN32_WINNT<0x0603 || _WIN32_WINNT == 0x0a00) */
403#endif /* (_WIN32_WINNT>=0x0600) */
404#else /* ! __MINGW32__ */
405static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
406#endif /* ! __MINGW32__ */
407/* Map struct WSABUF fields to their posix counterpart */
408#define msghdr _WSAMSG
409#define msg_name name
410#define msg_namelen namelen
411#define msg_iov lpBuffers
412#define msg_iovlen dwBufferCount
413#define msg_control Control.buf
414#define msg_controllen Control.len
415#define iovec _WSABUF
416#define iov_base buf
417#define iov_len len
418#define iov_len_t u_long
419#undef CMSG_DATA
420#define CMSG_DATA WSA_CMSG_DATA
421#define ipi_spec_dst ipi_addr
422#if !defined(__MINGW32__)
423#pragma warning( disable : 4116 )
424#endif /* ! __MINGW32__ */
425#else
426#define iov_len_t size_t
427#endif
428
429#if defined(_CYGWIN_ENV) || defined(__QNXNTO__)
430#define ipi_spec_dst ipi_addr
431#endif
432
433#if COAP_CLIENT_SUPPORT
434static uint32_t cid_track_counter;
435
436static void
437coap_test_cid_tuple_change(coap_session_t *session) {
438 if (session->type == COAP_SESSION_TYPE_CLIENT &&
439 session->negotiated_cid &&
441 session->proto == COAP_PROTO_DTLS && session->context->testing_cids) {
442 if ((++cid_track_counter) % session->context->testing_cids == 0) {
443 coap_address_t local_if = session->addr_info.local;
444 uint16_t port = coap_address_get_port(&local_if);
445
446 port++;
447 coap_address_set_port(&local_if, port);
448
449 coap_socket_dgrm_close(&session->sock);
450 session->sock.session = session;
451 if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
452 port,
453 &session->addr_info.local,
454 &session->addr_info.remote)) {
455 coap_log_err("Tuple change for CID failed\n");
456 return;
457#ifdef COAP_EPOLL_SUPPORT
458 } else {
459 coap_epoll_ctl_add(&session->sock,
460 EPOLLIN |
461 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
462 EPOLLOUT : 0),
463 __func__);
464#endif /* COAP_EPOLL_SUPPORT */
465 }
467 }
468 }
469}
470#endif /* COAP_CLIENT_SUPPORT */
471
472/*
473 * dgram
474 * return +ve Number of bytes written.
475 * -1 Error error in errno).
476 */
477ssize_t
479 const uint8_t *data, size_t datalen) {
480 ssize_t bytes_written = 0;
481
482#if COAP_CLIENT_SUPPORT
483 coap_test_cid_tuple_change(session);
484#endif /* COAP_CLIENT_SUPPORT */
485
486 if (!coap_debug_send_packet()) {
487 bytes_written = (ssize_t)datalen;
488 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
489#ifdef _WIN32
490 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
491#else
492 bytes_written = send(sock->fd, data, datalen, 0);
493#endif
494 } else {
495#if defined(_WIN32)
496 DWORD dwNumberOfBytesSent = 0;
497 int r;
498#endif /* _WIN32 */
499#ifdef HAVE_STRUCT_CMSGHDR
500 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
501 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
502 struct msghdr mhdr;
503 struct iovec iov[1];
504 const void *addr = &session->addr_info.remote.addr;
505
506 assert(session);
507
508 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
509 iov[0].iov_len = (iov_len_t)datalen;
510
511 memset(buf, 0, sizeof(buf));
512
513 memset(&mhdr, 0, sizeof(struct msghdr));
514 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
515 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
516 (socklen_t)sizeof(struct sockaddr_in) :
517 session->addr_info.remote.size;
518
519 mhdr.msg_iov = iov;
520 mhdr.msg_iovlen = 1;
521
522 if (!coap_address_isany(&session->addr_info.local) &&
523 !coap_is_mcast(&session->addr_info.local)) {
524 switch (session->addr_info.local.addr.sa.sa_family) {
525#if COAP_IPV6_SUPPORT
526 case AF_INET6: {
527 struct cmsghdr *cmsg;
528
529#if COAP_IPV4_SUPPORT
530 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
531#if defined(IP_PKTINFO)
532 struct in_pktinfo *pktinfo;
533 mhdr.msg_control = buf;
534 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
535
536 cmsg = CMSG_FIRSTHDR(&mhdr);
537 cmsg->cmsg_level = COAP_SOL_IP;
538 cmsg->cmsg_type = IP_PKTINFO;
539 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
540
541 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
542
543 pktinfo->ipi_ifindex = session->ifindex;
544 memcpy(&pktinfo->ipi_spec_dst,
545 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
546 sizeof(pktinfo->ipi_spec_dst));
547#elif defined(IP_SENDSRCADDR)
548 mhdr.msg_control = buf;
549 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
550
551 cmsg = CMSG_FIRSTHDR(&mhdr);
552 cmsg->cmsg_level = IPPROTO_IP;
553 cmsg->cmsg_type = IP_SENDSRCADDR;
554 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
555
556 memcpy(CMSG_DATA(cmsg),
557 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
558 sizeof(struct in_addr));
559#endif /* IP_PKTINFO */
560 } else {
561#endif /* COAP_IPV4_SUPPORT */
562 struct in6_pktinfo *pktinfo;
563 mhdr.msg_control = buf;
564 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
565
566 cmsg = CMSG_FIRSTHDR(&mhdr);
567 cmsg->cmsg_level = IPPROTO_IPV6;
568 cmsg->cmsg_type = IPV6_PKTINFO;
569 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
570
571 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
572
573 if (coap_is_mcast(&session->addr_info.remote)) {
574 pktinfo->ipi6_ifindex = session->addr_info.remote.addr.sin6.sin6_scope_id;
575 } else {
576 pktinfo->ipi6_ifindex = session->ifindex;
577 }
578 memcpy(&pktinfo->ipi6_addr,
579 &session->addr_info.local.addr.sin6.sin6_addr,
580 sizeof(pktinfo->ipi6_addr));
581#if COAP_IPV4_SUPPORT
582 }
583#endif /* COAP_IPV4_SUPPORT */
584 break;
585 }
586#endif /* COAP_IPV6_SUPPORT */
587#if COAP_IPV4_SUPPORT
588 case AF_INET: {
589#if defined(IP_PKTINFO)
590 struct cmsghdr *cmsg;
591 struct in_pktinfo *pktinfo;
592
593 mhdr.msg_control = buf;
594 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
595
596 cmsg = CMSG_FIRSTHDR(&mhdr);
597 cmsg->cmsg_level = COAP_SOL_IP;
598 cmsg->cmsg_type = IP_PKTINFO;
599 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
600
601 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
602
603 pktinfo->ipi_ifindex = session->ifindex;
604 memcpy(&pktinfo->ipi_spec_dst,
605 &session->addr_info.local.addr.sin.sin_addr,
606 sizeof(pktinfo->ipi_spec_dst));
607#elif defined(IP_SENDSRCADDR)
608 struct cmsghdr *cmsg;
609 mhdr.msg_control = buf;
610 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
611
612 cmsg = CMSG_FIRSTHDR(&mhdr);
613 cmsg->cmsg_level = IPPROTO_IP;
614 cmsg->cmsg_type = IP_SENDSRCADDR;
615 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
616
617 memcpy(CMSG_DATA(cmsg),
618 &session->addr_info.local.addr.sin.sin_addr,
619 sizeof(struct in_addr));
620#endif /* IP_PKTINFO */
621 break;
622 }
623#endif /* COAP_IPV4_SUPPORT */
624#if COAP_AF_UNIX_SUPPORT
625 case AF_UNIX:
626 break;
627#endif /* COAP_AF_UNIX_SUPPORT */
628 default:
629 /* error */
630 coap_log_warn("protocol not supported\n");
631 return -1;
632 }
633 }
634#endif /* HAVE_STRUCT_CMSGHDR */
635
636#if defined(_WIN32)
637 r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/,
638 NULL /*lpCompletionRoutine*/);
639 if (r == 0)
640 bytes_written = (ssize_t)dwNumberOfBytesSent;
641 else {
642 bytes_written = -1;
643 coap_win_error_to_errno();
644 }
645#else /* !_WIN32 */
646#ifdef HAVE_STRUCT_CMSGHDR
647 bytes_written = sendmsg(sock->fd, &mhdr, 0);
648#else /* ! HAVE_STRUCT_CMSGHDR */
649 bytes_written = sendto(sock->fd, (const void *)data, datalen, 0,
650 &session->addr_info.remote.addr.sa,
651 session->addr_info.remote.size);
652#endif /* ! HAVE_STRUCT_CMSGHDR */
653#endif /* !_WIN32 */
654 }
655
656 if (bytes_written < 0)
657 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
658
659 return bytes_written;
660}
661
662#define SIN6(A) ((struct sockaddr_in6 *)(A))
663
664/*
665 * dgram
666 * return +ve Number of bytes written.
667 * -1 Error error in errno).
668 * -2 ICMP error response
669 */
670ssize_t
672 ssize_t len = -1;
673
674 assert(sock);
675 assert(packet);
676
677 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
678 return -1;
679 } else {
680 /* clear has-data flag */
681 sock->flags &= ~COAP_SOCKET_CAN_READ;
682 }
683
684 if (sock->flags & COAP_SOCKET_CONNECTED) {
685#ifdef _WIN32
686 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
687#else
688 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
689#endif
690 if (len < 0) {
691#ifdef _WIN32
692 coap_win_error_to_errno();
693#endif /* _WIN32 */
694 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
695 /* client-side ICMP destination unreachable, ignore it */
696 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
697 sock->session ?
698 coap_session_str(sock->session) : "",
700 return -2;
701 }
702 if (errno != EAGAIN) {
703 coap_log_warn("** %s: coap_socket_recv: %s\n",
704 sock->session ?
705 coap_session_str(sock->session) : "",
707 }
708 goto error;
709 } else if (len > 0) {
710 packet->length = (size_t)len;
711 }
712 } else {
713#if defined(_WIN32)
714 DWORD dwNumberOfBytesRecvd = 0;
715 int r;
716#endif /* _WIN32 */
717#ifdef HAVE_STRUCT_CMSGHDR
718 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
719 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
720 struct cmsghdr *cmsg;
721 struct msghdr mhdr;
722 struct iovec iov[1];
723
724#if defined(__MINGW32__)
725 iov[0].iov_base = (char *) packet->payload;
726#else /* ! __MINGW32__ */
727 iov[0].iov_base = packet->payload;
728#endif /* defined(__MINGW32__) */
729 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
730
731 memset(&mhdr, 0, sizeof(struct msghdr));
732
733 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
734 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
735
736 mhdr.msg_iov = iov;
737 mhdr.msg_iovlen = 1;
738
739 mhdr.msg_control = buf;
740 mhdr.msg_controllen = sizeof(buf);
741 /* set a big first length incase recvmsg() does not implement updating
742 msg_control as well as preset the first cmsg with bad data */
743 cmsg = (struct cmsghdr *)buf;
744 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
745 cmsg->cmsg_level = -1;
746 cmsg->cmsg_type = -1;
747
748#if defined(_WIN32)
749 if (!lpWSARecvMsg) {
750 GUID wsaid = WSAID_WSARECVMSG;
751 DWORD cbBytesReturned = 0;
752 if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg,
753 sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
754 coap_log_warn("coap_socket_recv: no WSARecvMsg\n");
755 return -1;
756 }
757 }
758 r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */,
759 NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
760 if (r == 0)
761 len = (ssize_t)dwNumberOfBytesRecvd;
762 else if (r == COAP_SOCKET_ERROR)
763 coap_win_error_to_errno();
764#else
765 len = recvmsg(sock->fd, &mhdr, 0);
766#endif
767
768#else /* ! HAVE_STRUCT_CMSGHDR */
769 len = recvfrom(sock->fd, (void *)packet->payload, COAP_RXBUFFER_SIZE, 0,
770 &packet->addr_info.remote.addr.sa,
771 &packet->addr_info.remote.size);
772#endif /* ! HAVE_STRUCT_CMSGHDR */
773
774 if (len < 0) {
775#ifdef _WIN32
776 coap_win_error_to_errno();
777#endif /* _WIN32 */
778 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
779 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
780 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
781 sock->session ?
782 coap_session_str(sock->session) : "",
784 return 0;
785 }
786 if (errno != EAGAIN) {
787 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
788 }
789 goto error;
790 } else {
791#ifdef HAVE_STRUCT_CMSGHDR
792 int dst_found = 0;
793
794 packet->addr_info.remote.size = mhdr.msg_namelen;
795 packet->length = (size_t)len;
796
797 /* Walk through ancillary data records until the local interface
798 * is found where the data was received. */
799 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
800
801#if COAP_IPV6_SUPPORT
802 /* get the local interface for IPv6 */
803 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
804 union {
805 uint8_t *c;
806 struct in6_pktinfo *p;
807 } u;
808 u.c = CMSG_DATA(cmsg);
809 packet->ifindex = (int)(u.p->ipi6_ifindex);
810 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
811 &u.p->ipi6_addr, sizeof(struct in6_addr));
812 dst_found = 1;
813 break;
814 }
815#endif /* COAP_IPV6_SUPPORT */
816
817#if COAP_IPV4_SUPPORT
818 /* local interface for IPv4 */
819#if defined(IP_PKTINFO)
820 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
821 union {
822 uint8_t *c;
823 struct in_pktinfo *p;
824 } u;
825 u.c = CMSG_DATA(cmsg);
826 packet->ifindex = u.p->ipi_ifindex;
827#if COAP_IPV6_SUPPORT
828 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
829 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
830 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
831 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
832 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
833 &u.p->ipi_addr, sizeof(struct in_addr));
834 } else
835#endif /* COAP_IPV6_SUPPORT */
836 {
837 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
838 &u.p->ipi_addr, sizeof(struct in_addr));
839 }
840 dst_found = 1;
841 break;
842 }
843#endif /* IP_PKTINFO */
844#if defined(IP_RECVDSTADDR)
845 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
846 packet->ifindex = (int)sock->fd;
847 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
848 CMSG_DATA(cmsg), sizeof(struct in_addr));
849 dst_found = 1;
850 break;
851 }
852#endif /* IP_RECVDSTADDR */
853#endif /* COAP_IPV4_SUPPORT */
854 if (!dst_found) {
855 /* cmsg_level / cmsg_type combination we do not understand
856 (ignore preset case for bad recvmsg() not updating cmsg) */
857 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
858 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
859 cmsg->cmsg_level, cmsg->cmsg_type);
860 }
861 }
862 }
863 if (!dst_found) {
864 /* Not expected, but cmsg_level and cmsg_type don't match above and
865 may need a new case */
866 packet->ifindex = (int)sock->fd;
867 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
868 &packet->addr_info.local.size) < 0) {
869 coap_log_debug("Cannot determine local port\n");
870 }
871 }
872#else /* ! HAVE_STRUCT_CMSGHDR */
873 packet->length = (size_t)len;
874 packet->ifindex = 0;
875 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
876 &packet->addr_info.local.size) < 0) {
877 coap_log_debug("Cannot determine local port\n");
878 goto error;
879 }
880#endif /* ! HAVE_STRUCT_CMSGHDR */
881 }
882 }
883
884 if (len >= 0)
885 return len;
886error:
887 return -1;
888}
889
890void
892 if (sock->fd != COAP_INVALID_SOCKET && !(sock->flags & COAP_SOCKET_SLAVE)) {
893#ifdef COAP_EPOLL_SUPPORT
894#if COAP_SERVER_SUPPORT
895 coap_context_t *context = sock->session ? sock->session->context :
896 sock->endpoint ? sock->endpoint->context : NULL;
897#else /* COAP_SERVER_SUPPORT */
898 coap_context_t *context = sock->session ? sock->session->context : NULL;
899#endif /* COAP_SERVER_SUPPORT */
900 if (context != NULL) {
901 int ret;
902 struct epoll_event event;
903
904 /* Kernels prior to 2.6.9 expect non NULL event parameter */
905 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
906 if (ret == -1 && errno != ENOENT) {
907 coap_log_err("%s: epoll_ctl DEL failed: %d: %s (%d)\n",
908 "coap_socket_close",
909 sock->fd,
910 coap_socket_strerror(), errno);
911 }
912 }
913#endif /* COAP_EPOLL_SUPPORT */
914#if COAP_SERVER_SUPPORT
915#if COAP_AF_UNIX_SUPPORT
916 if (sock->endpoint &&
917 sock->endpoint->bind_addr.addr.sa.sa_family == AF_UNIX) {
918 /* Clean up Unix endpoint */
919#ifdef _WIN32
920 _unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
921#else /* ! _WIN32 */
922 unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
923#endif /* ! _WIN32 */
924 }
925#endif /* COAP_AF_UNIX_SUPPORT */
926 sock->endpoint = NULL;
927#endif /* COAP_SERVER_SUPPORT */
928#if COAP_CLIENT_SUPPORT
929#if COAP_AF_UNIX_SUPPORT
930 if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
931 sock->session->addr_info.local.addr.sa.sa_family == AF_UNIX) {
932 /* Clean up Unix endpoint */
933#ifdef _WIN32
934 _unlink(sock->session->addr_info.local.addr.cun.sun_path);
935#else /* ! _WIN32 */
936 unlink(sock->session->addr_info.local.addr.cun.sun_path);
937#endif /* ! _WIN32 */
938 }
939#endif /* COAP_AF_UNIX_SUPPORT */
940#endif /* COAP_CLIENT_SUPPORT */
941 sock->session = NULL;
942 coap_closesocket(sock->fd);
943 sock->fd = COAP_INVALID_SOCKET;
944 }
945 sock->flags = COAP_SOCKET_EMPTY;
946}
947
948#else /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */
949
950#ifdef __clang__
951/* Make compilers happy that do not like empty modules. As this function is
952 * never used, we ignore -Wunused-function at the end of compiling this file
953 */
954#pragma GCC diagnostic ignored "-Wunused-function"
955#endif
956static inline void
957dummy(void) {
958}
959
960#endif /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */
void coap_address_set_port(coap_address_t *addr, uint16_t port)
Set the port field of addr to port (in host byte order).
int coap_is_bcast(const coap_address_t *a)
Checks if given address a denotes a broadcast address.
void coap_address_init(coap_address_t *addr)
Resets the given coap_address_t object addr to its default values.
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
uint16_t coap_address_get_port(const coap_address_t *addr)
Returns the port from addr in host byte order.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
COAP_STATIC_INLINE int coap_address_isany(const coap_address_t *a)
Checks if given address object a denotes the wildcard address.
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
static void dummy(void)
#define iov_len_t
#define COAP_SOL_IP
#define COAP_IPV4_SUPPORT
const char * coap_socket_strerror(void)
Definition coap_io.c:814
#define coap_closesocket
Definition coap_io.h:52
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:33
#define COAP_SOCKET_ERROR
Definition coap_io.h:53
#define COAP_INVALID_SOCKET
Definition coap_io.h:54
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
void coap_epoll_ctl_add(coap_socket_t *sock, uint32_t events, const char *func)
Epoll specific function to add the state of events that epoll is to track for the appropriate file de...
#define COAP_SOCKET_NOT_EMPTY
the socket is not empty
#define COAP_SOCKET_BOUND
the socket is bound
#define COAP_SOCKET_SLAVE
socket is a slave socket - do not close
#define COAP_SOCKET_WANT_READ
non blocking socket is waiting for reading
#define COAP_SOCKET_WANT_CONNECT
non blocking client socket is waiting for connect
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
#define COAP_SOCKET_CONNECTED
the socket is connected
#define COAP_SOCKET_EMPTY
coap_socket_flags_t values
Library specific build wrapper for coap_internal.h.
int coap_socket_connect_udp(coap_socket_t *sock, const coap_address_t *local_if, const coap_address_t *server, int default_port, coap_address_t *local_addr, coap_address_t *remote_addr)
Create a new UDP socket and 'connect' it to the address tuple.
ssize_t coap_socket_recv(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for data transmission.
int coap_socket_bind_udp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Create a new UDP socket and then listen for new incoming UDP sessions to the specified IP address and...
void coap_socket_dgrm_close(coap_socket_t *sock)
Function interface to close off a datagram socket.
#define coap_log_debug(...)
Definition coap_debug.h:126
#define coap_log_alert(...)
Definition coap_debug.h:90
const char * coap_session_str(const coap_session_t *session)
Get session description.
#define coap_log_warn(...)
Definition coap_debug.h:108
#define coap_log_err(...)
Definition coap_debug.h:102
#define coap_log_crit(...)
Definition coap_debug.h:96
@ COAP_PROTO_DTLS
Definition coap_pdu.h:320
@ COAP_SESSION_TYPE_CLIENT
client-side
@ COAP_SESSION_STATE_ESTABLISHED
coap_address_t remote
remote address and port
Definition coap_io.h:60
coap_address_t local
local address and port
Definition coap_io.h:61
Multi-purpose address abstraction.
socklen_t size
size of addr
struct sockaddr_in sin
struct coap_sockaddr_un cun
struct sockaddr_in6 sin6
struct sockaddr sa
union coap_address_t::@0 addr
The CoAP stack's global state is stored in a coap_context_t object.
uint8_t testing_cids
Change client's source port every testing_cids.
coap_context_t * context
endpoint's context
coap_address_t bind_addr
local interface address
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
int ifindex
the interface index
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_socket_t sock
socket object for the session, if any
coap_session_state_t state
current state of relationship with peer
coap_addr_tuple_t addr_info
remote/local address info
coap_proto_t proto
protocol used
uint8_t negotiated_cid
Set for a client if CID negotiated.
coap_session_type_t type
client or server side socket
coap_context_t * context
session's context
int ifindex
interface index
char sun_path[COAP_UNIX_PATH_MAX]
coap_session_t * session
Used to determine session owner.
coap_endpoint_t * endpoint
Used by the epoll logic for a listening endpoint.
coap_address_t mcast_addr
remote address and port (multicast track)
coap_socket_flags_t flags
1 or more of COAP_SOCKET* flag values
struct in6_addr ipi6_addr
unsigned int ipi6_ifindex
struct in_addr ipi_spec_dst
struct in_addr ipi_addr