libcoap 4.3.5-develop-7cdc58d
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-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
16
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_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# 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# 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
114int
115coap_socket_bind_udp(coap_socket_t *sock,
116 const coap_address_t *listen_addr,
117 coap_address_t *bound_addr) {
118 int on = 1;
119#if COAP_IPV6_SUPPORT
120 int off = 0;
121#endif /* COAP_IPV6_SUPPORT */
122#ifdef _WIN32
123 u_long u_on = 1;
124#endif
125
126 sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
127
128 if (sock->fd == COAP_INVALID_SOCKET) {
129 coap_log_warn("coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
130 goto error;
131 }
132#ifdef _WIN32
133 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
134#else
135 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
136#endif
137 {
138 coap_log_warn("coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
139 }
140
141 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
142 coap_log_warn("coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
144
145 switch (listen_addr->addr.sa.sa_family) {
146#if COAP_IPV4_SUPPORT
147 case AF_INET:
148 if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on),
149 sizeof(on)) == COAP_SOCKET_ERROR)
150 coap_log_alert("coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
152 break;
153#endif /* COAP_IPV4_SUPPORT */
154#if COAP_IPV6_SUPPORT
155 case AF_INET6:
156 /* Configure the socket as dual-stacked */
157 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
158 sizeof(off)) == COAP_SOCKET_ERROR)
159 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
161#if !defined(ESPIDF_VERSION)
162 if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on),
163 sizeof(on)) == COAP_SOCKET_ERROR)
164 coap_log_alert("coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
166#endif /* !defined(ESPIDF_VERSION) */
167#endif /* COAP_IPV6_SUPPORT */
168 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 break;
172#if COAP_AF_UNIX_SUPPORT
173 case AF_UNIX:
174 break;
175#endif /* COAP_AF_UNIX_SUPPORT */
176#if COAP_AF_LLC_SUPPORT
177 case AF_LLC:
178 break;
179#endif /* COAP_AF_LLC_SUPPORT */
180 default:
181 coap_log_alert("coap_socket_bind_udp: unsupported sa_family\n");
182 break;
183 }
184
185 if (bind(sock->fd, &listen_addr->addr.sa,
187 listen_addr->addr.sa.sa_family == AF_INET ?
188 (socklen_t)sizeof(struct sockaddr_in) :
189#endif /* COAP_IPV4_SUPPORT */
190 (socklen_t)listen_addr->size) == COAP_SOCKET_ERROR) {
191 coap_log_warn("coap_socket_bind_udp: bind: %s\n",
193 goto error;
194 }
195
196 bound_addr->size = (socklen_t)sizeof(*bound_addr);
197 if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
198 coap_log_warn("coap_socket_bind_udp: getsockname: %s\n",
200 goto error;
201 }
202 return 1;
203
204error:
206 return 0;
207}
208#endif /* COAP_SERVER_SUPPORT */
209
210#if COAP_CLIENT_SUPPORT
211int
212coap_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 coap_address_t *remote_addr) {
218 int on = 1;
219#if COAP_IPV6_SUPPORT
220 int off = 0;
221#endif /* COAP_IPV6_SUPPORT */
222#ifdef _WIN32
223 u_long u_on = 1;
224#endif
225 coap_address_t connect_addr;
226 int is_mcast = coap_is_mcast(server);
227 coap_address_copy(&connect_addr, server);
228
230 sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
231
232 if (sock->fd == COAP_INVALID_SOCKET) {
233 coap_log_warn("coap_socket_connect_udp: socket: %s\n",
235 goto error;
236 }
237
238#ifdef _WIN32
239 if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR)
240#else
241 if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR)
242#endif
243 {
244 /* Ignore Zephyr unexpected Success response */
245 if (errno != 0) {
246 int keep_errno = errno;
247
248 coap_log_warn("coap_socket_connect_udp: ioctl FIONBIO: %s (%d)\n",
249 coap_socket_strerror(), keep_errno);
250 }
251 }
252
253 switch (connect_addr.addr.sa.sa_family) {
254#if COAP_IPV4_SUPPORT
255 case AF_INET:
256 if (connect_addr.addr.sin.sin_port == 0)
257 connect_addr.addr.sin.sin_port = htons(default_port);
258#if IP_RECVERR && defined(HAVE_STRUCT_CMSGHDR) && defined(HAVE_LINUX_ERRQUEUE_H)
259 if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVERR, OPTVAL_T(&on),
260 sizeof(on)) == COAP_SOCKET_ERROR)
261 coap_log_alert("coap_socket_connect_udp: setsockopt IP_RECVERR: %s\n",
263#endif /* IP_RECVERR && HAVE_STRUCT_CMSGHDR && HAVE_LINUX_ERRQUEUE_H */
264 break;
265#endif /* COAP_IPV4_SUPPORT */
266#if COAP_IPV6_SUPPORT
267 case AF_INET6:
268 if (connect_addr.addr.sin6.sin6_port == 0)
269 connect_addr.addr.sin6.sin6_port = htons(default_port);
270 /* Configure the socket as dual-stacked */
271 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off),
272 sizeof(off)) == COAP_SOCKET_ERROR)
273 if (errno != ENOSYS) {
274 coap_log_warn("coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
276 }
277#if IPV6_RECVERR && defined(HAVE_STRUCT_CMSGHDR) && defined(HAVE_LINUX_ERRQUEUE_H)
278 if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVERR, OPTVAL_T(&on),
279 sizeof(on)) == COAP_SOCKET_ERROR)
280 coap_log_alert("coap_socket_connect_udp: setsockopt IPV6_RECVERR: %s\n",
282#endif /* IPV6_RECVERR && HAVE_STRUCT_CMSGHDR && HAVE_LINUX_ERRQUEUE_H */
283#endif /* COAP_IPV6_SUPPORT */
284 break;
285#if COAP_AF_UNIX_SUPPORT
286 case AF_UNIX:
287 break;
288#endif /* COAP_AF_UNIX_SUPPORT */
289#if COAP_AF_LLC_SUPPORT
290 case AF_LLC:
291 break;
292#endif /* COAP_AF_LLC_SUPPORT */
293 default:
294 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
295 connect_addr.addr.sa.sa_family);
296 goto error;;
297 }
298
299 if (local_if && local_if->addr.sa.sa_family) {
300 if (local_if->addr.sa.sa_family != connect_addr.addr.sa.sa_family) {
301 coap_log_warn("coap_socket_connect_udp: local address family != "
302 "remote address family\n");
303 goto error;
304 }
305 if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
306 coap_log_warn("coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
308 if (bind(sock->fd, &local_if->addr.sa,
310 local_if->addr.sa.sa_family == AF_INET ?
311 (socklen_t)sizeof(struct sockaddr_in) :
312#endif /* COAP_IPV4_SUPPORT */
313 (socklen_t)local_if->size) == COAP_SOCKET_ERROR) {
314 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
316 goto error;
317 }
318#if COAP_AF_UNIX_SUPPORT
319 } else if (connect_addr.addr.sa.sa_family == AF_UNIX) {
320 /* Need to bind to a local address for clarity over endpoints */
321 coap_log_warn("coap_socket_connect_udp: local address required\n");
322 goto error;
323#endif /* COAP_AF_UNIX_SUPPORT */
324 }
325
326 /* special treatment for sockets that are used for multicast communication */
327 if (is_mcast) {
328 if (!(local_if && local_if->addr.sa.sa_family)) {
329 /* Bind to a (unused) port to simplify logging */
330 coap_address_t bind_addr;
331
332 coap_address_init(&bind_addr);
333 bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family;
334 if (bind(sock->fd, &bind_addr.addr.sa,
336 bind_addr.addr.sa.sa_family == AF_INET ?
337 (socklen_t)sizeof(struct sockaddr_in) :
338#endif /* COAP_IPV4_SUPPORT */
339 (socklen_t)bind_addr.size) == COAP_SOCKET_ERROR) {
340 coap_log_warn("coap_socket_connect_udp: bind: %s\n",
342 goto error;
343 }
344 }
345 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
346 coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n",
348 }
349 coap_address_copy(remote_addr, &connect_addr);
350 coap_address_copy(&sock->mcast_addr, &connect_addr);
352 if (coap_is_bcast(server) &&
353 setsockopt(sock->fd, SOL_SOCKET, SO_BROADCAST, OPTVAL_T(&on),
354 sizeof(on)) == COAP_SOCKET_ERROR)
355 coap_log_warn("coap_socket_connect_udp: setsockopt SO_BROADCAST: %s\n",
357 return 1;
358 }
359
360 switch (connect_addr.addr.sa.sa_family) {
361#if COAP_AF_LLC_SUPPORT
362 /* Only SOCK_STREAM type AF_LLC sockets can be connect()ed. */
363 case AF_LLC:
364 break;
365#endif /* COAP_AF_LLC_SUPPORT */
366#if COAP_AF_UNIX_SUPPORT
367 case AF_UNIX:
368#endif /* COAP_AF_UNIX_SUPPORT */
369 default:
370 if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
371#if COAP_AF_UNIX_SUPPORT
372 if (connect_addr.addr.sa.sa_family == AF_UNIX) {
373 coap_log_warn("coap_socket_connect_udp: connect: %s: %s\n",
374 connect_addr.addr.cun.sun_path, coap_socket_strerror());
375 } else
376#endif /* COAP_AF_UNIX_SUPPORT */
377 {
378 coap_log_warn("coap_socket_connect_udp: connect: %s (%d)\n",
379 coap_socket_strerror(), connect_addr.addr.sa.sa_family);
380 }
381 goto error;
382 }
383
384 if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
385 coap_log_warn("coap_socket_connect_udp: getpeername: %s\n",
387 }
388 break;
389 }
390
391 if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
392 coap_log_warn("coap_socket_connect_udp: getsockname: %s\n",
394 }
395
396#if COAP_AF_LLC_SUPPORT
397 /* AF_LLC sockets send to the local address without an explicit destination. */
398 if (coap_is_af_llc(&connect_addr))
400#endif /* COAP_AF_LLC_SUPPORT */
401
403 return 1;
404
405error:
407 return 0;
408}
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__)
418 struct in6_addr ipi6_addr; /* src/dst IPv6 address */
419 unsigned int ipi6_ifindex; /* send/recv interface index */
420};
421
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#define COAP_SOL_IP SOL_IP
439#endif /* ! _WIN32 */
440
441#if defined(_WIN32)
442#include <mswsock.h>
443#if defined(__MINGW32__)
444static __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__ */
455static __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
484static uint32_t cid_track_counter;
485
486static void
487coap_test_cid_tuple_change(coap_session_t *session) {
488 if (session->type == COAP_SESSION_TYPE_CLIENT &&
489 session->negotiated_cid &&
491 session->proto == COAP_PROTO_DTLS && session->context->testing_cids) {
492 if ((++cid_track_counter) % session->context->testing_cids == 0) {
493 coap_address_t local_if = session->addr_info.local;
494 uint16_t port = coap_address_get_port(&local_if);
495
496 port++;
497 coap_address_set_port(&local_if, port);
498
499 coap_socket_dgrm_close(&session->sock);
500 session->sock.session = session;
501 if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
502 port,
503 &session->addr_info.local,
504 &session->addr_info.remote)) {
505 coap_log_err("Tuple change for CID failed\n");
506 return;
507#ifdef COAP_EPOLL_SUPPORT
508 } else {
509 coap_epoll_ctl_add(&session->sock,
510 EPOLLIN |
511 ((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
512 EPOLLOUT : 0),
513 __func__);
514#endif /* COAP_EPOLL_SUPPORT */
515 }
517 }
518 }
519}
520#endif /* COAP_CLIENT_SUPPORT */
521
522#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
523static ssize_t
524coap_get_icmp_data(coap_socket_t *sock, uint8_t *data, size_t length) {
525 coap_fd_t fd = sock->fd;
526 char control_buf[1024];
527 struct iovec iov;
528 struct msghdr msg;
529 struct cmsghdr *cmsg;
530 int kerrno = errno;
531 int ret;
532
533 if (length < sizeof(coap_icmp_info_t)) {
534 return -1;
535 }
536 iov.iov_base = data + sizeof(coap_icmp_info_t);
537 iov.iov_len = length - sizeof(coap_icmp_info_t);;
538
539 memset(&msg, 0, sizeof(msg));
540 msg.msg_name = NULL;
541 msg.msg_namelen = 0;
542 msg.msg_iov = &iov;
543 msg.msg_iovlen = 1;
544 msg.msg_control = control_buf;
545 msg.msg_controllen = sizeof(control_buf);
546
547 /* Poll for errors using MSG_ERRQUEUE */
548 ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
549 errno = kerrno;
550 if (ret < 0) {
551 return -1;
552 }
553
554 /* Parse control messages, looking for ICMP error messages */
555 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
556#if COAP_IPV4_SUPPORT && IP_RECVERR
557 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) {
558 struct sock_extended_err *err = (struct sock_extended_err *)CMSG_DATA(cmsg);
559 coap_icmp_info_t *info = (coap_icmp_info_t *)data;
560
561 if (err->ee_origin == SO_EE_ORIGIN_ICMP) {
562 info->length = (uint32_t)ret;
563 info->cmsg_level = cmsg->cmsg_level;
564 info->ee_origin = err->ee_origin;
565 info->ee_type = err->ee_type;
566 info->ee_code = err->ee_code;
567#if COAP_SERVER_SUPPORT
568 coap_log_debug("* %s: ICMP Error Type: %d, Code: %d\n",
569 sock->endpoint ? coap_endpoint_str(sock->endpoint) :
571 err->ee_type, err->ee_code);
572#else /* ! COAP_SERVER_SUPPORT */
573 coap_log_debug("* %s: ICMP Error Type: %d, Code: %d\n",
575 err->ee_type, err->ee_code);
576#endif /* ! COAP_SERVER_SUPPORT */
577 return ret;
578 }
579 }
580#endif /* COAP_IPV4_SUPPORT && IP_RECVERR */
581#if COAP_IPV6_SUPPORT && IPV6_RECVERR
582 if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR) {
583 struct sock_extended_err *err = (struct sock_extended_err *)CMSG_DATA(cmsg);
584 coap_icmp_info_t *info = (coap_icmp_info_t *)data;
585
586 if (err->ee_origin == SO_EE_ORIGIN_ICMP6 || err->ee_origin == SO_EE_ORIGIN_ICMP) {
587 info->length = (uint32_t)ret;
588 info->cmsg_level = cmsg->cmsg_level;
589 info->ee_origin = err->ee_origin;
590 info->ee_type = err->ee_type;
591 info->ee_code = err->ee_code;
592#if COAP_SERVER_SUPPORT
593 coap_log_debug("* %s: ICMP%s Error Type: %d, Code: %d\n",
594 sock->endpoint ? coap_endpoint_str(sock->endpoint) :
596 err->ee_origin == SO_EE_ORIGIN_ICMP6 ? "6" : "",
597 err->ee_type, err->ee_code);
598#else /* ! COAP_SERVER_SUPPORT */
599 coap_log_debug("* %s: ICMP%s Error Type: %d, Code: %d\n",
601 err->ee_origin == SO_EE_ORIGIN_ICMP6 ? "6" : "",
602 err->ee_type, err->ee_code);
603#endif /* ! COAP_SERVER_SUPPORT */
604 return ret;
605 }
606 }
607#endif /* COAP_IPV6_SUPPORT && IPV6_RECVERR */
608 coap_log_debug("MSG_ERRQUEUE: Level %d, Type: %d\n", cmsg->cmsg_level, cmsg->cmsg_type);
609 }
610 return -1;
611}
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 */
619ssize_t
621 const uint8_t *data, size_t datalen) {
622 ssize_t bytes_written = 0;
623 int r;
624
625#if COAP_CLIENT_SUPPORT
626 coap_test_cid_tuple_change(session);
627#endif /* COAP_CLIENT_SUPPORT */
628
629 if ((r = coap_debug_send_packet()) != 1) {
630 if (r)
631 bytes_written = -1;
632 else
633 bytes_written = (ssize_t)datalen;
634 } else if (sock->flags & COAP_SOCKET_CONNECTED &&
635 !(sock->flags & COAP_SOCKET_WANT_SENDTO)) {
636#ifdef _WIN32
637 bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
638#else
639 bytes_written = send(sock->fd, data, datalen, 0);
640#endif
641 } else {
642#if defined(_WIN32)
643 DWORD dwNumberOfBytesSent = 0;
644#endif /* _WIN32 */
645#ifdef HAVE_STRUCT_CMSGHDR
646 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
647 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
648 struct msghdr mhdr;
649 struct iovec iov[1];
650 const void *addr = &session->addr_info.remote.addr;
651
652 assert(session);
653
654 memcpy(&iov[0].iov_base, &data, sizeof(iov[0].iov_base));
655 iov[0].iov_len = (iov_len_t)datalen;
656
657 memset(buf, 0, sizeof(buf));
658
659 memset(&mhdr, 0, sizeof(struct msghdr));
660 memcpy(&mhdr.msg_name, &addr, sizeof(mhdr.msg_name));
661 mhdr.msg_namelen = session->addr_info.remote.addr.sa.sa_family == AF_INET ?
662 (socklen_t)sizeof(struct sockaddr_in) :
663 session->addr_info.remote.size;
664
665 mhdr.msg_iov = iov;
666 mhdr.msg_iovlen = 1;
667
668 if (!coap_address_isany(&session->addr_info.local) &&
669 !coap_is_mcast(&session->addr_info.local)) {
670 switch (session->addr_info.local.addr.sa.sa_family) {
671#if COAP_IPV6_SUPPORT
672 case AF_INET6: {
673 struct cmsghdr *cmsg;
674
675#if COAP_IPV4_SUPPORT
676 if (IN6_IS_ADDR_V4MAPPED(&session->addr_info.local.addr.sin6.sin6_addr)) {
677#if defined(IP_PKTINFO)
678 struct in_pktinfo *pktinfo;
679 mhdr.msg_control = buf;
680 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
681
682 cmsg = CMSG_FIRSTHDR(&mhdr);
683 cmsg->cmsg_level = COAP_SOL_IP;
684 cmsg->cmsg_type = IP_PKTINFO;
685 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
686
687 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
688
689 pktinfo->ipi_ifindex = session->ifindex;
690 memcpy(&pktinfo->ipi_spec_dst,
691 session->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
692 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 } else {
707#endif /* COAP_IPV4_SUPPORT */
708 struct in6_pktinfo *pktinfo;
709 mhdr.msg_control = buf;
710 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
711
712 cmsg = CMSG_FIRSTHDR(&mhdr);
713 cmsg->cmsg_level = IPPROTO_IPV6;
714 cmsg->cmsg_type = IPV6_PKTINFO;
715 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
716
717 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
718
719 if (coap_is_mcast(&session->addr_info.remote)) {
720 pktinfo->ipi6_ifindex = session->addr_info.remote.addr.sin6.sin6_scope_id;
721 } else {
722 pktinfo->ipi6_ifindex = session->ifindex;
723 }
724 memcpy(&pktinfo->ipi6_addr,
725 &session->addr_info.local.addr.sin6.sin6_addr,
726 sizeof(pktinfo->ipi6_addr));
727#if COAP_IPV4_SUPPORT
728 }
729#endif /* COAP_IPV4_SUPPORT */
730 break;
731 }
732#endif /* COAP_IPV6_SUPPORT */
733#if COAP_IPV4_SUPPORT
734 case AF_INET: {
735#if defined(IP_PKTINFO)
736 struct cmsghdr *cmsg;
737 struct in_pktinfo *pktinfo;
738
739 mhdr.msg_control = buf;
740 mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
741
742 cmsg = CMSG_FIRSTHDR(&mhdr);
743 cmsg->cmsg_level = COAP_SOL_IP;
744 cmsg->cmsg_type = IP_PKTINFO;
745 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
746
747 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
748
749 pktinfo->ipi_ifindex = session->ifindex;
750 memcpy(&pktinfo->ipi_spec_dst,
751 &session->addr_info.local.addr.sin.sin_addr,
752 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 break;
768 }
769#endif /* COAP_IPV4_SUPPORT */
770#if COAP_AF_UNIX_SUPPORT
771 case AF_UNIX:
772 break;
773#endif /* COAP_AF_UNIX_SUPPORT */
774#if COAP_AF_LLC_SUPPORT
775 case AF_LLC:
776 break;
777#endif /* COAP_AF_LLC_SUPPORT */
778 default:
779 /* error */
780 coap_log_warn("protocol not supported\n");
781 return -1;
782 }
783 }
784#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#ifdef HAVE_STRUCT_CMSGHDR
797 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#endif /* !_WIN32 */
804 }
805
806 if (bytes_written < 0)
807 coap_log_warn("coap_socket_send: %s\n", coap_socket_strerror());
808
809 return bytes_written;
810}
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 */
820ssize_t
822 ssize_t len = -1;
823#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
824 ssize_t ret;
825#endif /* HAVE_LINUX_ERRQUEUE_H && HAVE_STRUCT_CMSGHDR */
826
827 assert(sock);
828 assert(packet);
829
830 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
831 return -1;
832 } else {
833 /* clear has-data flag */
835 }
836
837 if (sock->flags & COAP_SOCKET_CONNECTED) {
838#ifdef _WIN32
839 len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
840#else
841 len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
842#endif
843 if (len < 0) {
844#ifdef _WIN32
845 coap_win_error_to_errno();
846#endif /* _WIN32 */
847
848#if defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_STRUCT_CMSGHDR)
849 ret = coap_get_icmp_data(sock, packet->payload, COAP_RXBUFFER_SIZE);
850 if (ret >= 4) {
851 /* Information about the ICMP diagnostic packet is in packet->payload */
852 return -2;
853 }
854#endif /* HAVE_LINUX_ERRQUEUE_H && HAVE_STRUCT_CMSGHDR */
855 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
856 /* client-side ICMP destination unreachable, ignore it */
857 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
858 sock->session ?
859 coap_session_str(sock->session) : "",
861 goto error;
862 }
863 if (errno != EAGAIN) {
864 coap_log_warn("** %s: coap_socket_recv: %s\n",
865 sock->session ?
866 coap_session_str(sock->session) : "",
868 }
869 goto error;
870 } else if (len > 0) {
871 packet->length = (size_t)len;
872 }
873 } else {
874#if defined(_WIN32)
875 DWORD dwNumberOfBytesRecvd = 0;
876 int r;
877#endif /* _WIN32 */
878#ifdef HAVE_STRUCT_CMSGHDR
879 /* a buffer large enough to hold all packet info types, ipv6 is the largest */
880 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
881 struct cmsghdr *cmsg;
882 struct msghdr mhdr;
883 struct iovec iov[1];
884
885#if defined(__MINGW32__)
886 iov[0].iov_base = (char *) packet->payload;
887#else /* ! __MINGW32__ */
888 iov[0].iov_base = packet->payload;
889#endif /* defined(__MINGW32__) */
890 iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
891
892 memset(&mhdr, 0, sizeof(struct msghdr));
893
894 mhdr.msg_name = (struct sockaddr *)&packet->addr_info.remote.addr;
895 mhdr.msg_namelen = sizeof(packet->addr_info.remote.addr);
896
897 mhdr.msg_iov = iov;
898 mhdr.msg_iovlen = 1;
899
900 mhdr.msg_control = buf;
901 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 cmsg = (struct cmsghdr *)buf;
905 cmsg->cmsg_len = CMSG_LEN(sizeof(buf));
906 cmsg->cmsg_level = -1;
907 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 len = recvmsg(sock->fd, &mhdr, 0);
927#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 if (len < 0) {
936#ifdef _WIN32
937 coap_win_error_to_errno();
938#endif /* _WIN32 */
939 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
940 /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
941 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
942 sock->session ?
943 coap_session_str(sock->session) : "",
945 return 0;
946 }
947 if (errno != EAGAIN) {
948 coap_log_warn("coap_socket_recv: %s\n", coap_socket_strerror());
949 }
950 goto error;
951 } else {
952#ifdef HAVE_STRUCT_CMSGHDR
953 int dst_found = 0;
954
955 packet->addr_info.remote.size = mhdr.msg_namelen;
956 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 for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
961
962#if COAP_IPV6_SUPPORT
963 /* get the local interface for IPv6 */
964 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
965 union {
966 uint8_t *c;
967 struct in6_pktinfo *p;
968 } u;
969 u.c = CMSG_DATA(cmsg);
970 packet->ifindex = (int)(u.p->ipi6_ifindex);
971 memcpy(&packet->addr_info.local.addr.sin6.sin6_addr,
972 &u.p->ipi6_addr, sizeof(struct in6_addr));
973 dst_found = 1;
974 break;
975 }
976#endif /* COAP_IPV6_SUPPORT */
977
978#if COAP_IPV4_SUPPORT
979 /* local interface for IPv4 */
980#if defined(IP_PKTINFO)
981 if (cmsg->cmsg_level == COAP_SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
982 union {
983 uint8_t *c;
984 struct in_pktinfo *p;
985 } u;
986 u.c = CMSG_DATA(cmsg);
987 packet->ifindex = u.p->ipi_ifindex;
988#if COAP_IPV6_SUPPORT
989 if (packet->addr_info.local.addr.sa.sa_family == AF_INET6) {
990 memset(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr, 0, 10);
991 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
992 packet->addr_info.local.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
993 memcpy(packet->addr_info.local.addr.sin6.sin6_addr.s6_addr + 12,
994 &u.p->ipi_addr, sizeof(struct in_addr));
995 } else
996#endif /* COAP_IPV6_SUPPORT */
997 {
998 memcpy(&packet->addr_info.local.addr.sin.sin_addr,
999 &u.p->ipi_addr, sizeof(struct in_addr));
1000 }
1001 dst_found = 1;
1002 break;
1003 }
1004#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#endif /* COAP_IPV4_SUPPORT */
1015 if (!dst_found) {
1016 /* cmsg_level / cmsg_type combination we do not understand
1017 (ignore preset case for bad recvmsg() not updating cmsg) */
1018 if (cmsg->cmsg_level != -1 && cmsg->cmsg_type != -1) {
1019 coap_log_debug("cmsg_level = %d and cmsg_type = %d not supported - fix\n",
1020 cmsg->cmsg_level, cmsg->cmsg_type);
1021 }
1022 }
1023 }
1024 if (!dst_found) {
1025 /* Not expected, but cmsg_level and cmsg_type don't match above and
1026 may need a new case */
1027 packet->ifindex = (int)sock->fd;
1028 if (getsockname(sock->fd, &packet->addr_info.local.addr.sa,
1029 &packet->addr_info.local.size) < 0) {
1030 coap_log_debug("Cannot determine local port\n");
1031 }
1032 }
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 }
1043 }
1044
1045 if (len >= 0)
1046 return len;
1047error:
1048 return -1;
1049}
1050
1051void
1053 if (sock->fd != COAP_INVALID_SOCKET && !(sock->flags & COAP_SOCKET_SLAVE)) {
1054#ifdef COAP_EPOLL_SUPPORT
1055#if COAP_SERVER_SUPPORT
1056 coap_context_t *context = sock->session ? sock->session->context :
1057 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 if (context != NULL) {
1062 int ret;
1063 struct epoll_event event;
1064
1065 /* Kernels prior to 2.6.9 expect non NULL event parameter */
1066 ret = epoll_ctl(context->epfd, EPOLL_CTL_DEL, sock->fd, &event);
1067 if (ret == -1 && errno != ENOENT) {
1068 coap_log_err("%s: epoll_ctl DEL failed: %d: %s (%d)\n",
1069 "coap_socket_close",
1070 sock->fd,
1071 coap_socket_strerror(), errno);
1072 }
1073 }
1074#endif /* COAP_EPOLL_SUPPORT */
1075#if COAP_SERVER_SUPPORT
1076#if COAP_AF_UNIX_SUPPORT
1077 if (sock->endpoint &&
1078 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 unlink(sock->endpoint->bind_addr.addr.cun.sun_path);
1084#endif /* ! _WIN32 */
1085 }
1086#endif /* COAP_AF_UNIX_SUPPORT */
1087 sock->endpoint = NULL;
1088#endif /* COAP_SERVER_SUPPORT */
1089#if COAP_CLIENT_SUPPORT
1090#if COAP_AF_UNIX_SUPPORT
1091 if (sock->session && sock->session->type == COAP_SESSION_TYPE_CLIENT &&
1092 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 unlink(sock->session->addr_info.local.addr.cun.sun_path);
1098#endif /* ! _WIN32 */
1099 }
1100#endif /* COAP_AF_UNIX_SUPPORT */
1101#endif /* COAP_CLIENT_SUPPORT */
1102 sock->session = NULL;
1103 coap_closesocket(sock->fd);
1104 sock->fd = COAP_INVALID_SOCKET;
1105 sock->flags = COAP_SOCKET_EMPTY;
1106 }
1107}
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
1117static inline void
1118dummy(void) {
1119}
1120
1121#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.
int coap_is_af_llc(const coap_address_t *a)
Checks if given address a denotes an AF_LLC address.
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 SOL_IP
#define iov_len_t
#define COAP_SOL_IP
#define COAP_IPV4_SUPPORT
const char * coap_socket_strerror(void)
Definition coap_io.c:966
#define coap_closesocket
Definition coap_io.h:50
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:31
#define COAP_SOCKET_ERROR
Definition coap_io.h:51
int coap_fd_t
Definition coap_io.h:49
#define COAP_INVALID_SOCKET
Definition coap_io.h:52
#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_SENDTO
socket requires a destination address for sending
#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.
#define NULL
Definition coap_option.h:30
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.
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_endpoint_str(const coap_endpoint_t *endpoint)
Get endpoint description.
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
@ COAP_PROTO_DTLS
Definition coap_pdu.h:237
@ COAP_SESSION_TYPE_CLIENT
client-side
@ COAP_SESSION_STATE_ESTABLISHED
coap_address_t remote
remote address and port
Definition coap_io.h:58
coap_address_t local
local address and port
Definition coap_io.h:59
Multi-purpose address abstraction.
union coap_address_t::@240002377300042076074216002206221156022102076005 addr
socklen_t size
size of addr
struct sockaddr_in sin
struct coap_sockaddr_un cun
struct sockaddr_in6 sin6
struct sockaddr sa
The CoAP stack's global state is stored in a coap_context_t object.
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
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_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