coap_client_transport.c
Go to the documentation of this file.
1 /**
2  * @file coap_client_transport.c
3  * @brief Transport protocol abstraction layer
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL COAP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "coap/coap_client.h"
38 #include "debug.h"
39 
40 //Check TCP/IP stack configuration
41 #if (COAP_CLIENT_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Open network connection
46  * @param[in] context Pointer to the CoAP client context
47  * @return Error code
48  **/
49 
51 {
52  error_t error;
53 
54  //Open a UDP socket
55  context->socket = socketOpenEx(context->netContext, SOCKET_TYPE_DGRAM,
57  //Failed to open socket?
58  if(context->socket == NULL)
59  return ERROR_OPEN_FAILED;
60 
61  //Associate the socket with the relevant interface
62  error = socketBindToInterface(context->socket, context->interface);
63  //Any error to report?
64  if(error)
65  return error;
66 
67  //Force the socket to operate in non-blocking mode
68  error = socketSetTimeout(context->socket, 0);
69  //Any error to report?
70  if(error)
71  return error;
72 
73 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
74  //DTLS transport protocol?
75  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
76  {
77  //Allocate DTLS context
78  context->dtlsContext = tlsInit();
79  //Failed to allocate DTLS context?
80  if(context->dtlsContext == NULL)
81  return ERROR_OPEN_FAILED;
82 
83  //Select client operation mode
84  error = tlsSetConnectionEnd(context->dtlsContext,
86  //Any error to report?
87  if(error)
88  return error;
89 
90  //Set the transport protocol to be used (DTLS)
91  error = tlsSetTransportProtocol(context->dtlsContext,
93  //Any error to report?
94  if(error)
95  return error;
96 
97  //Bind DTLS to the relevant socket
98  error = tlsSetSocket(context->dtlsContext, context->socket);
99  //Any error to report?
100  if(error)
101  return error;
102 
103 #if (TLS_ALPN_SUPPORT == ENABLED)
104  //For CoAP over DTLS, a short ALPN ID "co" is allocated (refer to
105  //RFC 9952, section 2)
106  error = tlsSetAlpnProtocolList(context->dtlsContext, "co");
107  //Any error to report?
108  if(error)
109  return error;
110 #endif
111 
112  //Force DTLS to operate in non-blocking mode
113  error = tlsSetTimeout(context->dtlsContext, 0);
114  //Any error to report?
115  if(error)
116  return error;
117 
118  //Restore DTLS session, if any
119  error = tlsRestoreSessionState(context->dtlsContext, &context->dtlsSession);
120  //Any error to report?
121  if(error)
122  return error;
123 
124  //Invoke user-defined callback, if any
125  if(context->dtlsInitCallback != NULL)
126  {
127  //Perform DTLS related initialization
128  error = context->dtlsInitCallback(context, context->dtlsContext);
129  //Any error to report?
130  if(error)
131  return error;
132  }
133  }
134 #endif
135 
136  //Successful processing
137  return NO_ERROR;
138 }
139 
140 
141 /**
142  * @brief Establish network connection
143  * @param[in] context Pointer to the CoAP client context
144  * @param[in] serverIpAddr IP address of the CoAP server
145  * @param[in] serverPort UDP port number
146  * @return Error code
147  **/
148 
150  const IpAddr *serverIpAddr, uint16_t serverPort)
151 {
152  error_t error;
153 
154  //Only accept datagrams from the specified CoAP server
155  error = socketConnect(context->socket, serverIpAddr, serverPort);
156  //Any error to report?
157  if(error)
158  return error;
159 
160 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
161  //DTLS transport protocol?
162  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
163  {
164  //Perform DTLS handshake
165  error = tlsConnect(context->dtlsContext);
166  //Any error to report?
167  if(error)
168  return error;
169 
170  //At any time after the server has received the client Finished
171  //message, it may send a NewSessionTicket message (refer to RFC 8446,
172  //section 4.6.1)
173  context->dtlsSessionSaved = FALSE;
174  }
175 #endif
176 
177  //Successful processing
178  return NO_ERROR;
179 }
180 
181 
182 /**
183  * @brief Shutdown network connection
184  * @param[in] context Pointer to the CoAP client context
185  * @return Error code
186  **/
187 
189 {
190  error_t error;
191 
192  //Initialize status code
193  error = NO_ERROR;
194 
195 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
196  //DTLS transport protocol?
197  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
198  {
199  //Shutdown DTLS session
200  error = tlsShutdown(context->dtlsContext);
201  }
202 #endif
203 
204  //Return status code
205  return error;
206 }
207 
208 
209 /**
210  * @brief Close network connection
211  * @param[in] context Pointer to the CoAP client context
212  **/
213 
215 {
216 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
217  //DTLS transport protocol?
218  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
219  {
220  //Valid DTLS context?
221  if(context->dtlsContext != NULL)
222  {
223  //Release DTLS context
224  tlsFree(context->dtlsContext);
225  context->dtlsContext = NULL;
226  }
227  }
228 #endif
229 
230  //Valid socket?
231  if(context->socket != NULL)
232  {
233  //Close UDP socket
234  socketClose(context->socket);
235  context->socket = NULL;
236  }
237 }
238 
239 
240 /**
241  * @brief Send a datagram
242  * @param[in] context Pointer to the CoAP client context
243  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
244  * @param[in] length Length of the datagram, in bytes
245  * @return Error code
246  **/
247 
249  const void *data, size_t length)
250 {
251  error_t error;
252 
253 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
254  //DTLS transport protocol?
255  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
256  {
257  //Transmit datagram
258  error = tlsWrite(context->dtlsContext, data, length, NULL, 0);
259  }
260  else
261 #endif
262  //UDP transport protocol?
263  {
264  //Transmit datagram
265  error = socketSend(context->socket, data, length, NULL, 0);
266  }
267 
268  //Return status code
269  return error;
270 }
271 
272 
273 /**
274  * @brief Receive a datagram
275  * @param[in] context Pointer to the CoAP client context
276  * @param[out] data Buffer into which the received datagram will be placed
277  * @param[in] size Maximum number of bytes that can be received
278  * @param[out] received Number of bytes that have been received
279  * @return Error code
280  **/
281 
283  void *data, size_t size, size_t *received)
284 {
285  error_t error;
286 
287  //No data has been read yet
288  *received = 0;
289 
290 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
291  //DTLS transport protocol?
292  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
293  {
294  //Receive datagram
295  error = tlsRead(context->dtlsContext, data, size, received, 0);
296 
297  //Check status code
298  if(!error)
299  {
300  //At any time after the server has received the client Finished
301  //message, it may send a NewSessionTicket message (refer to RFC 8446,
302  //section 4.6.1)
303  if(!context->dtlsSessionSaved)
304  {
305  //Save DTLS session
306  error = tlsSaveSessionState(context->dtlsContext,
307  &context->dtlsSession);
308 
309  //Update flag
310  context->dtlsSessionSaved = TRUE;
311  }
312  }
313  }
314  else
315 #endif
316  //UDP transport protocol?
317  {
318  //Receive datagram
319  error = socketReceive(context->socket, data, size, received, 0);
320  }
321 
322  //Return status code
323  return error;
324 }
325 
326 
327 /**
328  * @brief Wait for incoming datagrams
329  * @param[in] context Pointer to the CoAP client context
330  * @param[in] timeout Maximum time to wait before returning
331  * @return Error code
332  **/
333 
335  systime_t timeout)
336 {
337  error_t error;
338  SocketEventDesc eventDesc[1];
339 
340  //Initialize status code
341  error = ERROR_BUFFER_EMPTY;
342 
343 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
344  //DTLS transport protocol?
345  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
346  {
347  //Check whether a datagram is pending in the receive buffer
348  if(tlsIsRxReady(context->dtlsContext))
349  {
350  //No need to poll the underlying socket for incoming traffic...
351  error = NO_ERROR;
352  }
353  }
354 #endif
355 
356  //Check status code
357  if(error == ERROR_BUFFER_EMPTY)
358  {
359  //Set the events the application is interested in
360  eventDesc[0].socket = context->socket;
361  eventDesc[0].eventMask = SOCKET_EVENT_RX_READY;
362 
363  //Release exclusive access to the CoAP client context
364  osReleaseMutex(&context->mutex);
365 
366  //Wait for incoming traffic
367  error = socketPoll(eventDesc, arraysize(eventDesc), &context->event,
368  timeout);
369 
370  //Acquire exclusive access to the CoAP client context
371  osAcquireMutex(&context->mutex);
372  }
373 
374  //Return status code
375  return error;
376 }
377 
378 #endif
error_t socketSend(Socket *socket, const void *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: socket.c:1514
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:68
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:108
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:371
error_t tlsSetTransportProtocol(TlsContext *context, TlsTransportProtocol transportProtocol)
Set the transport protocol to be used.
Definition: tls.c:340
error_t coapClientSendDatagram(CoapClientContext *context, const void *data, size_t length)
Send a datagram.
IP network address.
Definition: ip.h:90
error_t coapClientShutdownConnection(CoapClientContext *context)
Shutdown network connection.
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2094
@ TLS_TRANSPORT_PROTOCOL_DATAGRAM
Definition: tls.h:1038
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
error_t coapClientEstablishConnection(CoapClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
#define CoapClientContext
Definition: coap_client.h:144
Structure describing socket events.
Definition: socket.h:433
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:3073
@ ERROR_OPEN_FAILED
Definition: error.h:75
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2621
#define FALSE
Definition: os_port.h:46
#define tlsSetSocket(context, socket)
Definition: tls.h:1008
error_t
Error codes.
Definition: error.h:43
error_t coapClientWaitForDatagram(CoapClientContext *context, systime_t timeout)
Wait for incoming datagrams.
error_t socketReceive(Socket *socket, void *data, size_t size, size_t *received, uint_t flags)
Receive data from a connected socket.
Definition: socket.c:1724
error_t coapClientReceiveDatagram(CoapClientContext *context, void *data, size_t size, size_t *received)
Receive a datagram.
error_t tlsSetTimeout(TlsContext *context, systime_t timeout)
Set timeout for blocking calls (for DTLS only)
Definition: tls.c:1619
error_t coapClientOpenConnection(CoapClientContext *context)
Open network connection.
CoAP client.
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1377
error_t tlsSaveSessionState(const TlsContext *context, TlsSessionState *session)
Save TLS session.
Definition: tls.c:3004
uint8_t length
Definition: tcp.h:375
error_t tlsRead(TlsContext *context, void *data, size_t size, size_t *received, uint_t flags)
Receive application data from a the remote host using TLS.
Definition: tls.c:2286
error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
Wait for one of a set of sockets to become ready to perform I/O.
Definition: socket.c:2182
#define socketBindToInterface
Definition: net_legacy.h:193
uint32_t systime_t
System time.
bool_t tlsIsRxReady(TlsContext *context)
Check whether some data is available in the receive buffer.
Definition: tls.c:2576
@ COAP_TRANSPORT_PROTOCOL_DTLS
DTLS protocol.
Definition: coap_common.h:79
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Socket * socketOpenEx(NetContext *context, uint_t type, uint_t protocol)
Create a socket.
Definition: socket.c:146
@ TLS_CONNECTION_END_CLIENT
Definition: tls.h:1050
error_t tlsWrite(TlsContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Send application data to the remote host using TLS.
Definition: tls.c:2145
error_t tlsSetAlpnProtocolList(TlsContext *context, const char_t *protocolList)
Set the list of supported ALPN protocols.
Definition: tls.c:906
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2816
void coapClientCloseConnection(CoapClientContext *context)
Close network connection.
Transport protocol abstraction layer.
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:434
TCP/IP stack core.
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:169
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1805
uint_t eventMask
Requested events.
Definition: socket.h:435
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define arraysize(a)
Definition: os_port.h:71