libcoap 4.3.5-develop-490e4e0
Loading...
Searching...
No Matches
coap_dgrm_riot.c
Go to the documentation of this file.
1/* coap_dgrm_riot.c -- Default Datagram (UDP) network I/O functions for libcoap on RIOT
2 *
3 * Copyright (C) 2019-2025 Olaf Bergmann <bergmann@tzi.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
17
18#if defined(RIOT_VERSION)
19
20#include "net/gnrc.h"
21#include "net/gnrc/ipv6.h"
22#include "net/gnrc/netreg.h"
23#include "net/udp.h"
24#if COAP_DISABLE_TCP
25#include "net/tcp.h"
26#endif /* ! COAP_DISABLE_TCP */
27#include "net/sock/async.h"
28
29#include "coap3/coap_riot.h"
30
31#define COAP_SELECT_THREAD_FLAG (1U << 4)
32
33/*
34 * dgram
35 * return +ve Number of bytes written.
36 * -1 Error error in errno).
37 */
38ssize_t
40 coap_session_t *session,
41 const uint8_t *data,
42 size_t datalen) {
43 ssize_t bytes_written = 0;
44
46 bytes_written = (ssize_t)datalen;
47 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
48 bytes_written = sock_udp_send(&sock->udp, data, datalen, NULL);
49 } else {
50 bytes_written = sock_udp_send(&sock->udp, data, datalen, &session->addr_info.remote.riot);
51 }
52
53 if (bytes_written < 0) {
54 errno = -bytes_written;
55 bytes_written = -1;
56 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
57 }
58
59 return bytes_written;
60}
61
62/*
63 * dgram
64 * return +ve Number of bytes written.
65 * -1 Error error in errno).
66 * -2 ICMP error response
67 */
68ssize_t
70 ssize_t len = -1;
71
72 assert(sock);
73 assert(packet);
74
75 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
76 return -1;
77 } else {
78 /* clear has-data flag */
79 sock->flags &= ~COAP_SOCKET_CAN_READ;
80 }
81
82 if (sock->flags & COAP_SOCKET_CONNECTED) {
83 len = sock_udp_recv(&sock->udp, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0, NULL);
84 if (len < 0) {
85 errno = -len;
86 len = -1;
87 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
88 /* client-side ICMP destination unreachable, ignore it */
89 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
90 sock->session ?
91 coap_session_str(sock->session) : "",
93 return -2;
94 }
95 if (errno != EAGAIN) {
96 coap_log_warn("** %s: coap_socket_recv: %s\n",
97 sock->session ?
98 coap_session_str(sock->session) : "",
100 }
101 goto error;
102 } else if (len > 0) {
103 packet->length = (size_t)len;
104 }
105 } else {
106 sock_udp_aux_rx_t aux;
107 sock_udp_ep_t remote;
108
109 aux.flags = SOCK_AUX_GET_LOCAL;
110 len = sock_udp_recv_aux(&sock->udp, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0,
111 &remote, &aux);
112 if (len < 0) {
113 errno = -len;
114 len = -1;
115 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
116 /* client-side ICMP destination unreachable, ignore it */
117 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
118 sock->session ?
119 coap_session_str(sock->session) : "",
121 return -2;
122 }
123 if (errno != EAGAIN) {
124 coap_log_warn("** %s: coap_socket_recv: %s\n",
125 sock->session ?
126 coap_session_str(sock->session) : "",
128 }
129 goto error;
130 } else if (len > 0) {
131 packet->length = (size_t)len;
132 memcpy(&packet->addr_info.local.riot, &aux.local, sizeof(packet->addr_info.local.riot));
133 memcpy(&packet->addr_info.remote.riot, &remote, sizeof(packet->addr_info.remote.riot));
134 }
135 }
136
137 if (len >= 0)
138 return len;
139error:
140 return -1;
141}
142
143#if COAP_SERVER_SUPPORT
144
145static void
146udp_recv_endpoint_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg) {
147 coap_endpoint_t *endpoint = (coap_endpoint_t *)arg;
148
149 (void)sock;
150 if (!(flags & (SOCK_ASYNC_MSG_RECV | SOCK_ASYNC_MSG_SENT)))
151 return;
152
153 if (flags & SOCK_ASYNC_MSG_RECV)
154 endpoint->sock.flags |= COAP_SOCKET_CAN_READ;
155 if (endpoint->context->selecting_thread) {
156 thread_flags_set(endpoint->context->selecting_thread,
157 COAP_SELECT_THREAD_FLAG);
158 }
159}
160
161int
163 const coap_address_t *listen_addr,
164 coap_address_t *bound_addr) {
165 int ret;
166
167 ret = sock_udp_create(&sock->udp, &listen_addr->riot, NULL, SOCK_FLAGS_REUSE_EP);
168 if (ret < 0) {
169 errno = -ret;
170 ret = -1;
171 coap_log_warn("coap_socket_bind_udp: sock_udp_create: %s (%d)\n",
172 coap_socket_strerror(), listen_addr->riot.family);
173 goto error;
174 }
175 ret = sock_udp_get_local(&sock->udp, &bound_addr->riot);
176 if (ret != 0) {
177 errno = -ret;
178 ret = -1;
179 coap_log_warn("coap_socket_bind_udp: sock_udp_get_local: %s\n",
181 }
182 sock_udp_set_cb(&sock->udp, udp_recv_endpoint_cb, sock->endpoint);
183
184 return 1;
185
186error:
188 return 0;
189}
190#endif /* COAP_SERVER_SUPPORT */
191
192#if COAP_CLIENT_SUPPORT
193
194static void
195udp_recv_session_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg) {
196 coap_session_t *session = (coap_session_t *)arg;
197
198 (void)sock;
199 if (!(flags & (SOCK_ASYNC_MSG_RECV | SOCK_ASYNC_MSG_SENT)))
200 return;
201
202 if (flags & SOCK_ASYNC_MSG_RECV)
203 session->sock.flags |= COAP_SOCKET_CAN_READ;
204 if (session->context->selecting_thread) {
205 thread_flags_set(session->context->selecting_thread,
206 COAP_SELECT_THREAD_FLAG);
207 }
208}
209
210int
212 const coap_address_t *local_if,
213 const coap_address_t *server,
214 int default_port,
215 coap_address_t *local_addr,
216 coap_address_t *remote_addr) {
217 sock_udp_ep_t local;
218 sock_udp_ep_t remote;
219 coap_address_t connect_addr;
220 int is_mcast = coap_is_mcast(server);
221 int ret;
222
223 coap_address_copy(&connect_addr, server);
224
226
227 if (local_if && local_if->riot.family) {
228 if (local_if->riot.family != connect_addr.riot.family) {
229 coap_log_warn("coap_socket_connect_udp: local address family != "
230 "remote address family\n");
231 goto error;
232 }
233 }
234
235 local.netif = SOCK_ADDR_ANY_NETIF;
236 remote.netif = SOCK_ADDR_ANY_NETIF;
237 switch (connect_addr.riot.family) {
238#if COAP_IPV4_SUPPORT
239 case AF_INET:
240 local.family = AF_INET;
241 local.port = 0;
242 if (local_if) {
243 memcpy(local.addr.ipv4, &local_if->riot.addr.ipv4, sizeof(local.addr.ipv4));
244 local.port = local_if->riot.port;
245 } else {
246 memset(local.addr.ipv4, 0, sizeof(local.addr.ipv4));
247 }
248 remote.family = AF_INET;
249 memcpy(remote.addr.ipv4, &server->riot.addr.ipv4, sizeof(remote.addr.ipv4));
250 if (connect_addr.riot.port == 0)
251 connect_addr.riot.port = default_port;
252 remote.port = connect_addr.riot.port;
253 break;
254#endif /* COAP_IPV4_SUPPORT */
255#if COAP_IPV6_SUPPORT
256 case AF_INET6:
257 local.family = AF_INET6;
258 local.port = 0;
259 if (local_if) {
260 memcpy(local.addr.ipv6, &local_if->riot.addr.ipv6, sizeof(local.addr.ipv6));
261 local.port = local_if->riot.port;
262 } else {
263 memset(local.addr.ipv6, 0, sizeof(local.addr.ipv6));
264 }
265 remote.family = AF_INET6;
266 memcpy(remote.addr.ipv6, &server->riot.addr.ipv6, sizeof(remote.addr.ipv6));
267 if (connect_addr.riot.port == 0)
268 connect_addr.riot.port = htons(default_port);
269 remote.port = connect_addr.riot.port;
270 break;
271#endif /* COAP_IPV6_SUPPORT */
272 default:
273 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
274 connect_addr.riot.family);
275 goto error;
276 }
277
278 ret = sock_udp_create(&sock->udp, &local, &remote, is_mcast ? 0 : SOCK_FLAGS_CONNECT_REMOTE);
279 if (ret < 0) {
280 errno = -ret;
281 ret = -1;
282 coap_log_warn("coap_socket_connect_udp: sock_udp_create: %s (%d)\n",
283 coap_socket_strerror(), connect_addr.riot.family);
284 goto error;
285 }
286 ret = sock_udp_get_local(&sock->udp, &local);
287 if (ret != 0) {
288 errno = -ret;
289 ret = -1;
290 coap_log_warn("coap_socket_connect_udp: sock_udp_get_local: %s\n",
292 }
293 memcpy(&local_addr->riot, &local, sizeof(local_addr->riot));
294
295 ret = sock_udp_get_remote(&sock->udp, &remote);
296 if (ret != 0) {
297 errno = -ret;
298 ret = -1;
299 coap_log_warn("coap_socket_connect_udp: sock_udp_get_remote: %s\n",
301 }
302 memcpy(&remote_addr->riot, &remote, sizeof(remote_addr->riot));
303
304 sock_udp_set_cb(&sock->udp, udp_recv_session_cb, sock->session);
305
306 /* special treatment for sockets that are used for multicast communication */
307 if (is_mcast) {
308 coap_address_copy(remote_addr, &connect_addr);
309 coap_address_copy(&sock->mcast_addr, &connect_addr);
311 return 1;
312 }
313
315 return 1;
316
317error:
319 return 0;
320}
321#endif /* COAP_CLIENT_SUPPORT */
322
323void
325 if (sock->flags != COAP_SOCKET_EMPTY) {
326 sock_udp_close(&sock->udp);
327 }
328 sock->flags = COAP_SOCKET_EMPTY;
329}
330
331#else /* ! RIOT_VERSION */
332
333#ifdef __clang__
334/* Make compilers happy that do not like empty modules. As this function is
335 * never used, we ignore -Wunused-function at the end of compiling this file
336 */
337#pragma GCC diagnostic ignored "-Wunused-function"
338#endif
339static inline void
340dummy(void) {
341}
342
343#endif /* ! RIOT_VERSION */
int coap_is_mcast(const coap_address_t *a)
Checks if given address a denotes a multicast address.
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
static void dummy(void)
const char * coap_socket_strerror(void)
Definition coap_io.c:814
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:33
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#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.
RIOT-specific definitions for libcoap.
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_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_crit(...)
Definition coap_debug.h:96
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.
union coap_address_t::@0 addr
Abstraction of virtual endpoint that can be attached to coap_context_t.
coap_context_t * context
endpoint's context
coap_socket_t sock
socket object for the interface, if any
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
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_addr_tuple_t addr_info
remote/local address info
coap_context_t * context
session's context
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