libcoap 4.3.5-develop-f0533d3
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-2026 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 int r;
45
46 if ((r = coap_debug_send_packet()) != 1) {
47 if (r)
48 bytes_written = -1;
49 else
50 bytes_written = (ssize_t)datalen;
51 } else if (sock->flags & COAP_SOCKET_CONNECTED) {
52 bytes_written = sock_udp_send(&sock->udp, data, datalen, NULL);
53 } else {
54 bytes_written = sock_udp_send(&sock->udp, data, datalen, &session->addr_info.remote.riot);
55 }
56
57 if (bytes_written < 0) {
58 errno = -bytes_written;
59 bytes_written = -1;
60 coap_log_crit("coap_socket_send: %s\n", coap_socket_strerror());
61 }
62
63 return bytes_written;
64}
65
66/*
67 * dgram
68 * return +ve Number of bytes written.
69 * -1 Error error in errno).
70 * -2 ICMP error response
71 */
72ssize_t
74 ssize_t len = -1;
75
76 assert(sock);
77 assert(packet);
78
79 if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
80 return -1;
81 } else {
82 /* clear has-data flag */
83 sock->flags &= ~COAP_SOCKET_CAN_READ;
84 }
85
86 if (sock->flags & COAP_SOCKET_CONNECTED) {
87 len = sock_udp_recv(&sock->udp, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0, NULL);
88 if (len < 0) {
89 errno = -len;
90 len = -1;
91 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
92 /* client-side ICMP destination unreachable, ignore it */
93 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
94 sock->session ?
95 coap_session_str(sock->session) : "",
97 return -2;
98 }
99 if (errno != EAGAIN) {
100 coap_log_warn("** %s: coap_socket_recv: %s\n",
101 sock->session ?
102 coap_session_str(sock->session) : "",
104 }
105 goto error;
106 } else if (len > 0) {
107 packet->length = (size_t)len;
108 }
109 } else {
110 sock_udp_aux_rx_t aux;
111 sock_udp_ep_t remote;
112
113 aux.flags = SOCK_AUX_GET_LOCAL;
114 len = sock_udp_recv_aux(&sock->udp, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0,
115 &remote, &aux);
116 if (len < 0) {
117 errno = -len;
118 len = -1;
119 if (errno == ECONNREFUSED || errno == EHOSTUNREACH || errno == ECONNRESET) {
120 /* client-side ICMP destination unreachable, ignore it */
121 coap_log_warn("** %s: coap_socket_recv: ICMP: %s\n",
122 sock->session ?
123 coap_session_str(sock->session) : "",
125 return -2;
126 }
127 if (errno != EAGAIN) {
128 coap_log_warn("** %s: coap_socket_recv: %s\n",
129 sock->session ?
130 coap_session_str(sock->session) : "",
132 }
133 goto error;
134 } else if (len > 0) {
135 packet->length = (size_t)len;
136 memcpy(&packet->addr_info.local.riot, &aux.local, sizeof(packet->addr_info.local.riot));
137 memcpy(&packet->addr_info.remote.riot, &remote, sizeof(packet->addr_info.remote.riot));
138 }
139 }
140
141 if (len >= 0)
142 return len;
143error:
144 return -1;
145}
146
147#if COAP_SERVER_SUPPORT
148
149static void
150udp_recv_endpoint_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg) {
151 coap_endpoint_t *endpoint = (coap_endpoint_t *)arg;
152
153 (void)sock;
154 if (!(flags & (SOCK_ASYNC_MSG_RECV | SOCK_ASYNC_MSG_SENT)))
155 return;
156
157 if (flags & SOCK_ASYNC_MSG_RECV)
158 endpoint->sock.flags |= COAP_SOCKET_CAN_READ;
159 if (endpoint->context->selecting_thread) {
160 thread_flags_set(endpoint->context->selecting_thread,
161 COAP_SELECT_THREAD_FLAG);
162 }
163}
164
165int
166coap_socket_bind_udp(coap_socket_t *sock,
167 const coap_address_t *listen_addr,
168 coap_address_t *bound_addr) {
169 int ret;
170
171 ret = sock_udp_create(&sock->udp, &listen_addr->riot, NULL, SOCK_FLAGS_REUSE_EP);
172 if (ret < 0) {
173 errno = -ret;
174 ret = -1;
175 coap_log_warn("coap_socket_bind_udp: sock_udp_create: %s (%d)\n",
176 coap_socket_strerror(), listen_addr->riot.family);
177 goto error;
178 }
179 ret = sock_udp_get_local(&sock->udp, &bound_addr->riot);
180 if (ret != 0) {
181 errno = -ret;
182 ret = -1;
183 coap_log_warn("coap_socket_bind_udp: sock_udp_get_local: %s\n",
185 }
186 sock_udp_set_cb(&sock->udp, udp_recv_endpoint_cb, sock->endpoint);
187
188 return 1;
189
190error:
192 return 0;
193}
194#endif /* COAP_SERVER_SUPPORT */
195
196#if COAP_CLIENT_SUPPORT
197
198static void
199udp_recv_session_cb(sock_udp_t *sock, sock_async_flags_t flags, void *arg) {
200 coap_session_t *session = (coap_session_t *)arg;
201
202 (void)sock;
203 if (!(flags & (SOCK_ASYNC_MSG_RECV | SOCK_ASYNC_MSG_SENT)))
204 return;
205
206 if (flags & SOCK_ASYNC_MSG_RECV)
207 session->sock.flags |= COAP_SOCKET_CAN_READ;
208 if (session->context->selecting_thread) {
209 thread_flags_set(session->context->selecting_thread,
210 COAP_SELECT_THREAD_FLAG);
211 }
212}
213
214int
215coap_socket_connect_udp(coap_socket_t *sock,
216 const coap_address_t *local_if,
217 const coap_address_t *server,
218 int default_port,
219 coap_address_t *local_addr,
220 coap_address_t *remote_addr) {
221 sock_udp_ep_t local;
222 sock_udp_ep_t remote;
223 coap_address_t connect_addr;
224 int is_mcast = coap_is_mcast(server);
225 int ret;
226
227 coap_address_copy(&connect_addr, server);
228
230
231 if (local_if && local_if->riot.family) {
232 if (local_if->riot.family != connect_addr.riot.family) {
233 coap_log_warn("coap_socket_connect_udp: local address family != "
234 "remote address family\n");
235 goto error;
236 }
237 }
238
239 local.netif = SOCK_ADDR_ANY_NETIF;
240 remote.netif = SOCK_ADDR_ANY_NETIF;
241 switch (connect_addr.riot.family) {
242#if COAP_IPV4_SUPPORT
243 case AF_INET:
244 local.family = AF_INET;
245 local.port = 0;
246 if (local_if) {
247 memcpy(local.addr.ipv4, &local_if->riot.addr.ipv4, sizeof(local.addr.ipv4));
248 local.port = local_if->riot.port;
249 } else {
250 memset(local.addr.ipv4, 0, sizeof(local.addr.ipv4));
251 }
252 remote.family = AF_INET;
253 memcpy(remote.addr.ipv4, &server->riot.addr.ipv4, sizeof(remote.addr.ipv4));
254 if (connect_addr.riot.port == 0)
255 connect_addr.riot.port = default_port;
256 remote.port = connect_addr.riot.port;
257 break;
258#endif /* COAP_IPV4_SUPPORT */
259#if COAP_IPV6_SUPPORT
260 case AF_INET6:
261 local.family = AF_INET6;
262 local.port = 0;
263 if (local_if) {
264 memcpy(local.addr.ipv6, &local_if->riot.addr.ipv6, sizeof(local.addr.ipv6));
265 local.port = local_if->riot.port;
266 } else {
267 memset(local.addr.ipv6, 0, sizeof(local.addr.ipv6));
268 }
269 remote.family = AF_INET6;
270 memcpy(remote.addr.ipv6, &server->riot.addr.ipv6, sizeof(remote.addr.ipv6));
271 if (connect_addr.riot.port == 0)
272 connect_addr.riot.port = htons(default_port);
273 remote.port = connect_addr.riot.port;
274 break;
275#endif /* COAP_IPV6_SUPPORT */
276 default:
277 coap_log_alert("coap_socket_connect_udp: unsupported sa_family %d\n",
278 connect_addr.riot.family);
279 goto error;
280 }
281
282 ret = sock_udp_create(&sock->udp, &local, &remote, is_mcast ? 0 : SOCK_FLAGS_CONNECT_REMOTE);
283 if (ret < 0) {
284 errno = -ret;
285 ret = -1;
286 coap_log_warn("coap_socket_connect_udp: sock_udp_create: %s (%d)\n",
287 coap_socket_strerror(), connect_addr.riot.family);
288 goto error;
289 }
290 ret = sock_udp_get_local(&sock->udp, &local);
291 if (ret != 0) {
292 errno = -ret;
293 ret = -1;
294 coap_log_warn("coap_socket_connect_udp: sock_udp_get_local: %s\n",
296 }
297 memcpy(&local_addr->riot, &local, sizeof(local_addr->riot));
298
299 ret = sock_udp_get_remote(&sock->udp, &remote);
300 if (ret != 0) {
301 errno = -ret;
302 ret = -1;
303 coap_log_warn("coap_socket_connect_udp: sock_udp_get_remote: %s\n",
305 }
306 memcpy(&remote_addr->riot, &remote, sizeof(remote_addr->riot));
307
308 sock_udp_set_cb(&sock->udp, udp_recv_session_cb, sock->session);
309
310 /* special treatment for sockets that are used for multicast communication */
311 if (is_mcast) {
312 coap_address_copy(remote_addr, &connect_addr);
313 coap_address_copy(&sock->mcast_addr, &connect_addr);
315 return 1;
316 }
317
319 return 1;
320
321error:
323 return 0;
324}
325#endif /* COAP_CLIENT_SUPPORT */
326
327void
329 if (!(sock->flags & COAP_SOCKET_SLAVE)) {
330 if (sock->flags != COAP_SOCKET_EMPTY) {
331 sock_udp_close(&sock->udp);
332 }
333 sock->flags = COAP_SOCKET_EMPTY;
334 }
335}
336
337#else /* ! RIOT_VERSION */
338
339#ifdef __clang__
340/* Make compilers happy that do not like empty modules. As this function is
341 * never used, we ignore -Wunused-function at the end of compiling this file
342 */
343#pragma GCC diagnostic ignored "-Wunused-function"
344#endif
345static inline void
346dummy(void) {
347}
348
349#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)
struct coap_endpoint_t coap_endpoint_t
const char * coap_socket_strerror(void)
Definition coap_io.c:935
#define COAP_RXBUFFER_SIZE
Definition coap_io.h:31
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#define COAP_SOCKET_SLAVE
socket is a slave socket - do not close
#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
RIOT-specific definitions for libcoap.
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_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:58
coap_address_t local
local address and port
Definition coap_io.h:59
Multi-purpose address abstraction.
union coap_address_t::@0 addr
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_socket_flags_t flags
1 or more of COAP_SOCKET* flag values