libcoap 4.3.5-develop-490e4e0
Loading...
Searching...
No Matches
coap_strm_riot.c
Go to the documentation of this file.
1/* coap_strm_riot.c -- Default Stream (TCP) 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
33int
35 return !COAP_DISABLE_TCP;
36}
37
38#if ! COAP_DISABLE_TCP
39
40/*
41 * strm
42 * return +ve Number of bytes written.
43 * 0 No data written.
44 * -1 Error (error in errno).
45 */
46ssize_t
47coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
48 ssize_t ret;
49
51 ret = sock_tcp_write(&sock->tcp, data, data_len);
52 if (ret < 0) {
53 errno = -ret;
54 ret = -1;
55 if (errno==EAGAIN ||
56#if EAGAIN != EWOULDBLOCK
57 errno == EWOULDBLOCK ||
58#endif
59 errno == EINTR) {
61 return 0;
62 }
63 if (errno == EPIPE || errno == ECONNRESET) {
64 coap_log_info("coap_socket_write: send: %s\n",
66 } else {
67 coap_log_warn("coap_socket_write: send: %s\n",
69 }
70 return -1;
71 }
72 if (ret < (ssize_t)data_len) {
74 }
75 return ret;
76}
77
78/*
79 * strm
80 * return >=0 Number of bytes read.
81 * -1 Error (error in errno).
82 */
83ssize_t
84coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
85 ssize_t ret;
86
87 ret = sock_tcp_read(&sock->tcp, data, data_len, SOCK_NO_TIMEOUT);
88 if (ret == 0) {
89 /* graceful shutdown */
90 sock->flags &= ~COAP_SOCKET_CAN_READ;
91 errno = ECONNRESET;
92 return -1;
93 } else if (ret < 0) {
94 errno = -ret;
95 ret = -1;
96 sock->flags &= ~COAP_SOCKET_CAN_READ;
97 if (errno==EAGAIN ||
98#if EAGAIN != EWOULDBLOCK
99 errno == EWOULDBLOCK ||
100#endif
101 errno == EINTR) {
102 return 0;
103 }
104 if (errno != ECONNRESET) {
105 coap_log_warn("coap_socket_read: recv: %s\n",
107 }
108 return -1;
109 }
110 if (ret < (ssize_t)data_len)
111 sock->flags &= ~COAP_SOCKET_CAN_READ;
112 return ret;
113}
114
115#ifdef MODULE_LWIP_TCP
116static void
117tcp_recv_session_cb(sock_tcp_t *sock, sock_async_flags_t flags, void *arg) {
118 coap_session_t *session = (coap_session_t *)arg;
119
120 (void)sock;
121 if (!(flags & (SOCK_ASYNC_MSG_RECV | SOCK_ASYNC_MSG_SENT)))
122 return;
123
124 if (flags & SOCK_ASYNC_MSG_RECV)
125 session->sock.flags |= COAP_SOCKET_CAN_READ;
126 if (session->context->selecting_thread) {
127 thread_flags_set(session->context->selecting_thread,
128 COAP_SELECT_THREAD_FLAG);
129 }
130}
131#endif /* MODULE_LWIP_TCP */
132
133#if COAP_CLIENT_SUPPORT
134
135int
137 const coap_address_t *local_if,
138 const coap_address_t *server,
139 int default_port,
140 coap_address_t *local_addr,
141 coap_address_t *remote_addr) {
142 sock_tcp_ep_t local;
143 sock_tcp_ep_t remote;
144 coap_address_t connect_addr;
145 int ret;
146
147 coap_address_copy(&connect_addr, server);
148
150
151 if (local_if && local_if->riot.family) {
152 if (local_if->riot.family != connect_addr.riot.family) {
153 coap_log_warn("coap_socket_connect_tcp1: local address family != "
154 "remote address family\n");
155 goto error;
156 }
157 }
158
159 local.netif = SOCK_ADDR_ANY_NETIF;
160 remote.netif = SOCK_ADDR_ANY_NETIF;
161 switch (connect_addr.riot.family) {
162#if COAP_IPV4_SUPPORT
163 case AF_INET:
164 local.family = AF_INET;
165 local.port = 0;
166 if (local_if) {
167 memcpy(local.addr.ipv4, &local_if->riot.addr.ipv4, sizeof(local.addr.ipv4));
168 local.port = local_if->riot.port;
169 } else {
170 memset(local.addr.ipv4, 0, sizeof(local.addr.ipv4));
171 }
172 remote.family = AF_INET;
173 memcpy(remote.addr.ipv4, &server->riot.addr.ipv4, sizeof(remote.addr.ipv4));
174 if (connect_addr.riot.port == 0)
175 connect_addr.riot.port = default_port;
176 remote.port = connect_addr.riot.port;
177 break;
178#endif /* COAP_IPV4_SUPPORT */
179#if COAP_IPV6_SUPPORT
180 case AF_INET6:
181 local.family = AF_INET6;
182 local.port = 0;
183 if (local_if) {
184 memcpy(local.addr.ipv6, &local_if->riot.addr.ipv6, sizeof(local.addr.ipv6));
185 local.port = local_if->riot.port;
186 } else {
187 memset(local.addr.ipv6, 0, sizeof(local.addr.ipv6));
188 }
189 remote.family = AF_INET6;
190 memcpy(remote.addr.ipv6, &server->riot.addr.ipv6, sizeof(remote.addr.ipv6));
191 if (connect_addr.riot.port == 0)
192 connect_addr.riot.port = default_port;
193 remote.port = connect_addr.riot.port;
194 break;
195#endif /* COAP_IPV6_SUPPORT */
196 default:
197 coap_log_alert("coap_socket_connect_tcp1: unsupported sa_family %d\n",
198 connect_addr.riot.family);
199 goto error;
200 }
201
202 ret = sock_tcp_connect(&sock->tcp, &remote, 0, 0);
203 if (ret < 0) {
204 errno = -ret;
205 ret = -1;
206 coap_log_warn("coap_socket_connect_tcp1: sock_tcp_create: %s (%d)\n",
207 coap_socket_strerror(), connect_addr.riot.family);
208 goto error;
209 }
210 ret = sock_tcp_get_local(&sock->tcp, &local);
211 if (ret != 0) {
212 errno = -ret;
213 ret = -1;
214 coap_log_warn("coap_socket_connect_tcp1: sock_tcp_get_local: %s\n",
216 }
217 memcpy(&local_addr->riot, &local, sizeof(local_addr->riot));
218
219 ret = sock_tcp_get_remote(&sock->tcp, &remote);
220 if (ret != 0) {
221 errno = -ret;
222 ret = -1;
223 coap_log_warn("coap_socket_connect_tcp: sock_tcp_get_remote: %s\n",
225 }
226 memcpy(&remote_addr->riot, &remote, sizeof(remote_addr->riot));
227
228#ifdef MODULE_LWIP_TCP
229 sock_tcp_set_cb(&sock->tcp, tcp_recv_session_cb, sock->session);
230#endif /* MODULE_LWIP_TCP */
231
233 return 1;
234
235error:
236 coap_socket_close(sock);
237 return 0;
238}
239
240int
242 coap_address_t *local_addr,
243 coap_address_t *remote_addr) {
244 (void)sock;
245 (void)local_addr;
246 (void)remote_addr;
247
248 return -1;
249}
250#endif /* COAP_CLIENT_SUPPORT */
251
252#if COAP_SERVER_SUPPORT
253
254#define SOCK_QUEUE_LEN (1U)
255
256static sock_tcp_t sock_queue[SOCK_QUEUE_LEN];
257static sock_tcp_queue_t queue;
258
259int
261 const coap_address_t *listen_addr,
262 coap_address_t *bound_addr) {
263 ssize_t ret;
264
265 (void)sock;
266
267 ret = sock_tcp_listen(&queue, &listen_addr->riot, sock_queue, SOCK_QUEUE_LEN, 0);
268 if (ret < 0) {
269 errno = -ret;
270 return 0;
271 }
272
273 coap_address_copy(bound_addr, listen_addr);
274
275 return 1;
276}
277
278int
280 coap_socket_t *new_client,
281 coap_address_t *local_addr,
282 coap_address_t *remote_addr,
283 void *extra) {
284 sock_tcp_t *sock = NULL;
285 ssize_t ret;
286 sock_tcp_ep_t scratch;
287
288 (void)extra;
289 server->flags &= ~COAP_SOCKET_CAN_ACCEPT;
290 ret = sock_tcp_accept(&queue, &sock, SOCK_NO_TIMEOUT);
291 if (ret < 0) {
292 errno = -ret;
293 return 0;
294 }
295 if (sock == NULL || ret < 0) {
296 coap_log_warn("coap_socket_accept_tcp: accept: %s\n",
298 return 0;
299 }
300 new_client->tcp = *sock;
301
302 ret = sock_tcp_get_remote(&new_client->tcp, &scratch);
303 if (ret < 0) {
304 errno = -ret;
305 return 0;
306 }
307 memcpy(&remote_addr->riot, &scratch, sizeof(remote_addr->riot));
308 ret = sock_tcp_get_local(&new_client->tcp, &scratch);
309 if (ret < 0) {
310 errno = -ret;
311 return 0;
312 }
313 memcpy(&local_addr->riot, &scratch, sizeof(local_addr->riot));
314
315#ifdef MODULE_LWIP_TCP
316 sock_tcp_set_cb(&new_client->tcp, tcp_recv_session_cb, new_client->session);
317#endif /* MODULE_LWIP_TCP */
318 return 1;
319}
320#endif /* COAP_SERVER_SUPPORT */
321
322void
324 if (sock->flags != COAP_SOCKET_EMPTY) {
325 sock_tcp_disconnect(&sock->tcp);
326 }
327 sock->flags = COAP_SOCKET_EMPTY;
328}
329
330#endif /* ! COAP_DISABLE_TCP */
331
332#else /* ! RIOT_VERSION */
333
334#ifdef __clang__
335/* Make compilers happy that do not like empty modules. As this function is
336 * never used, we ignore -Wunused-function at the end of compiling this file
337 */
338#pragma GCC diagnostic ignored "-Wunused-function"
339#endif
340static inline void
341dummy(void) {
342}
343
344#endif /* ! RIOT_VERSION */
void coap_address_copy(coap_address_t *dst, const coap_address_t *src)
const char * coap_socket_strerror(void)
Definition coap_io.c:814
#define COAP_SOCKET_MULTICAST
socket is used for multicast communication
#define COAP_SOCKET_CAN_WRITE
non blocking socket can now write without blocking
#define COAP_SOCKET_WANT_WRITE
non blocking socket is waiting for writing
#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.
static void dummy(void)
#define coap_log_alert(...)
Definition coap_debug.h:90
#define coap_log_info(...)
Definition coap_debug.h:114
#define coap_log_warn(...)
Definition coap_debug.h:108
int coap_socket_bind_tcp(coap_socket_t *sock, const coap_address_t *listen_addr, coap_address_t *bound_addr)
Create a new TCP socket and then listen for new incoming TCP sessions.
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
Function interface for data stream receiving off a socket.
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
Function interface for data stream sending off a socket.
int coap_socket_connect_tcp1(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 TCP socket and initiate the connection.
int coap_socket_accept_tcp(coap_socket_t *server, coap_socket_t *new_client, coap_address_t *local_addr, coap_address_t *remote_addr, void *extra)
Accept a new incoming TCP session.
void coap_socket_strm_close(coap_socket_t *sock)
Function interface to close off a stream socket.
int coap_socket_connect_tcp2(coap_socket_t *sock, coap_address_t *local_addr, coap_address_t *remote_addr)
Complete the TCP Connection.
int coap_tcp_is_supported(void)
Check whether TCP is available.
Multi-purpose address abstraction.
union coap_address_t::@0 addr
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_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