1 /*
2 * coap_netif.c -- Netif functions for libcoap
3 *
4 * Copyright (C) 2023 Jon Shallow <supjps-libcoap@jpshallow.com>
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
12 /**
13 * @file coap_netif.c
14 * @brief CoAP Netif handling functions
15 */
16
17 #include "coap3/coap_internal.h"
18 #include "coap3/coap_session_internal.h"
19
20 /*
21 * return 1 netif still in use.
22 * 0 netif no longer available.
23 */
24 int
coap_netif_available(coap_session_t * session)25 coap_netif_available(coap_session_t *session) {
26 return session->sock.flags != COAP_SOCKET_EMPTY;
27 }
28
29 #if COAP_SERVER_SUPPORT
30 /*
31 * return 1 netif still in use.
32 * 0 netif no longer available.
33 */
34 int
coap_netif_available_ep(coap_endpoint_t * endpoint)35 coap_netif_available_ep(coap_endpoint_t *endpoint) {
36 return endpoint->sock.flags != COAP_SOCKET_EMPTY;
37 }
38
39 int
coap_netif_dgrm_listen(coap_endpoint_t * endpoint,const coap_address_t * listen_addr)40 coap_netif_dgrm_listen(coap_endpoint_t *endpoint,
41 const coap_address_t *listen_addr) {
42 if (!coap_socket_bind_udp(&endpoint->sock, listen_addr,
43 &endpoint->bind_addr)) {
44 return 0;
45 }
46 endpoint->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_BOUND | COAP_SOCKET_WANT_READ;
47 return 1;
48 }
49 #endif /* COAP_SERVER_SUPPORT */
50
51 #if COAP_CLIENT_SUPPORT
52 int
coap_netif_dgrm_connect(coap_session_t * session,const coap_address_t * local_if,const coap_address_t * server,int default_port)53 coap_netif_dgrm_connect(coap_session_t *session, const coap_address_t *local_if,
54 const coap_address_t *server, int default_port) {
55 if (!coap_socket_connect_udp(&session->sock, local_if, server,
56 default_port,
57 &session->addr_info.local,
58 &session->addr_info.remote)) {
59 return 0;
60 }
61 return 1;
62 }
63 #endif /* COAP_CLIENT_SUPPORT */
64
65 /*
66 * dgram
67 * return +ve Number of bytes written.
68 * -1 Error error in errno).
69 * -2 ICMP error response
70 */
71 ssize_t
coap_netif_dgrm_read(coap_session_t * session,coap_packet_t * packet)72 coap_netif_dgrm_read(coap_session_t *session, coap_packet_t *packet) {
73 ssize_t bytes_read;
74 int keep_errno;
75
76 bytes_read = coap_socket_recv(&session->sock, packet);
77 keep_errno = errno;
78 if (bytes_read == -1) {
79 coap_log_debug("* %s: netif: failed to read %zd bytes (%s) state %d\n",
80 coap_session_str(session), packet->length,
81 coap_socket_strerror(), session->state);
82 errno = keep_errno;
83 } else if (bytes_read > 0) {
84 coap_ticks(&session->last_rx_tx);
85 coap_log_debug("* %s: netif: recv %4zd bytes\n",
86 coap_session_str(session), bytes_read);
87 }
88 return bytes_read;
89 }
90
91 #if COAP_SERVER_SUPPORT
92 /*
93 * dgram
94 * return +ve Number of bytes written.
95 * -1 Error error in errno).
96 * -2 ICMP error response
97 */
98 ssize_t
coap_netif_dgrm_read_ep(coap_endpoint_t * endpoint,coap_packet_t * packet)99 coap_netif_dgrm_read_ep(coap_endpoint_t *endpoint, coap_packet_t *packet) {
100 ssize_t bytes_read;
101 int keep_errno;
102
103 bytes_read = coap_socket_recv(&endpoint->sock, packet);
104 keep_errno = errno;
105 if (bytes_read == -1) {
106 coap_log_debug("* %s: netif: failed to read %zd bytes (%s)\n",
107 coap_endpoint_str(endpoint), packet->length,
108 coap_socket_strerror());
109 errno = keep_errno;
110 } else if (bytes_read > 0) {
111 /* Let the caller do the logging as session available by then */
112 }
113 return bytes_read;
114 }
115 #endif /* COAP_SERVER_SUPPORT */
116
117 /*
118 * dgram
119 * return +ve Number of bytes written.
120 * -1 Error error in errno).
121 */
122 ssize_t
coap_netif_dgrm_write(coap_session_t * session,const uint8_t * data,size_t datalen)123 coap_netif_dgrm_write(coap_session_t *session, const uint8_t *data,
124 size_t datalen) {
125 ssize_t bytes_written;
126 int keep_errno;
127
128 coap_socket_t *sock = &session->sock;
129 #if COAP_SERVER_SUPPORT
130 if (sock->flags == COAP_SOCKET_EMPTY) {
131 assert(session->endpoint != NULL);
132 sock = &session->endpoint->sock;
133 }
134 #endif /* COAP_SERVER_SUPPORT */
135
136 bytes_written = coap_socket_send(sock, session, data, datalen);
137 keep_errno = errno;
138 if (bytes_written <= 0) {
139 coap_log_debug("* %s: netif: failed to send %zd bytes (%s) state %d\n",
140 coap_session_str(session), datalen,
141 coap_socket_strerror(), session->state);
142 errno = keep_errno;
143 } else {
144 coap_ticks(&session->last_rx_tx);
145 if (bytes_written == (ssize_t)datalen)
146 coap_log_debug("* %s: netif: sent %4zd bytes\n",
147 coap_session_str(session), bytes_written);
148 else
149 coap_log_debug("* %s: netif: sent %4zd of %4zd bytes\n",
150 coap_session_str(session), bytes_written, datalen);
151 }
152 return bytes_written;
153 }
154
155 #if !COAP_DISABLE_TCP
156 #if COAP_SERVER_SUPPORT
157 int
coap_netif_strm_listen(coap_endpoint_t * endpoint,const coap_address_t * listen_addr)158 coap_netif_strm_listen(coap_endpoint_t *endpoint,
159 const coap_address_t *listen_addr) {
160 if (!coap_socket_bind_tcp(&endpoint->sock, listen_addr,
161 &endpoint->bind_addr)) {
162 return 0;
163 }
164 endpoint->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_BOUND |
165 COAP_SOCKET_WANT_ACCEPT;
166 return 1;
167 }
168
169 int
coap_netif_strm_accept(coap_endpoint_t * endpoint,coap_session_t * session)170 coap_netif_strm_accept(coap_endpoint_t *endpoint, coap_session_t *session) {
171 if (!coap_socket_accept_tcp(&endpoint->sock, &session->sock,
172 &session->addr_info.local,
173 &session->addr_info.remote)) {
174 return 0;
175 }
176 session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_CONNECTED |
177 COAP_SOCKET_WANT_READ;
178 return 1;
179 }
180 #endif /* COAP_SERVER_SUPPORT */
181
182 #if COAP_CLIENT_SUPPORT
183 int
coap_netif_strm_connect1(coap_session_t * session,const coap_address_t * local_if,const coap_address_t * server,int default_port)184 coap_netif_strm_connect1(coap_session_t *session,
185 const coap_address_t *local_if,
186 const coap_address_t *server, int default_port) {
187 if (!coap_socket_connect_tcp1(&session->sock, local_if, server,
188 default_port,
189 &session->addr_info.local,
190 &session->addr_info.remote)) {
191 return 0;
192 }
193 return 1;
194 }
195
196 int
coap_netif_strm_connect2(coap_session_t * session)197 coap_netif_strm_connect2(coap_session_t *session) {
198 if (!coap_socket_connect_tcp2(&session->sock,
199 &session->addr_info.local,
200 &session->addr_info.remote)) {
201 return 0;
202 }
203 return 1;
204 }
205 #endif /* COAP_CLIENT_SUPPORT */
206
207 /*
208 * strm
209 * return >=0 Number of bytes read.
210 * -1 Error (error in errno).
211 */
212 ssize_t
coap_netif_strm_read(coap_session_t * session,uint8_t * data,size_t datalen)213 coap_netif_strm_read(coap_session_t *session, uint8_t *data, size_t datalen) {
214 ssize_t bytes_read = coap_socket_read(&session->sock, data, datalen);
215 int keep_errno = errno;
216
217 if (bytes_read >= 0) {
218 coap_log_debug("* %s: netif: recv %4zd bytes\n",
219 coap_session_str(session), bytes_read);
220 } else if (bytes_read == -1 && errno != EAGAIN) {
221 coap_log_debug("* %s: netif: failed to receive any bytes (%s) state %d\n",
222 coap_session_str(session), coap_socket_strerror(), session->state);
223 errno = keep_errno;
224 }
225 return bytes_read;
226 }
227
228 /*
229 * strm
230 * return +ve Number of bytes written.
231 * -1 Error (error in errno).
232 */
233 ssize_t
coap_netif_strm_write(coap_session_t * session,const uint8_t * data,size_t datalen)234 coap_netif_strm_write(coap_session_t *session, const uint8_t *data,
235 size_t datalen) {
236 ssize_t bytes_written = coap_socket_write(&session->sock, data, datalen);
237 int keep_errno = errno;
238
239 if (bytes_written <= 0) {
240 coap_log_debug("* %s: netif: failed to send %zd bytes (%s) state %d\n",
241 coap_session_str(session), datalen,
242 coap_socket_strerror(), session->state);
243 errno = keep_errno;
244 } else {
245 coap_ticks(&session->last_rx_tx);
246 if (bytes_written == (ssize_t)datalen)
247 coap_log_debug("* %s: netif: sent %4zd bytes\n",
248 coap_session_str(session), bytes_written);
249 else
250 coap_log_debug("* %s: netif: sent %4zd of %4zd bytes\n",
251 coap_session_str(session), bytes_written, datalen);
252 }
253 return bytes_written;
254 }
255 #endif /* COAP_DISABLE_TCP */
256
257 void
coap_netif_close(coap_session_t * session)258 coap_netif_close(coap_session_t *session) {
259 if (coap_netif_available(session))
260 coap_socket_close(&session->sock);
261 }
262
263 #if COAP_SERVER_SUPPORT
264 void
coap_netif_close_ep(coap_endpoint_t * endpoint)265 coap_netif_close_ep(coap_endpoint_t *endpoint) {
266 coap_socket_close(&endpoint->sock);
267 }
268 #endif /* COAP_SERVER_SUPPORT */
269