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-2024 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.4.0
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
56  //Failed to open socket?
57  if(context->socket == NULL)
58  return ERROR_OPEN_FAILED;
59 
60  //Associate the socket with the relevant interface
61  error = socketBindToInterface(context->socket, context->interface);
62  //Any error to report?
63  if(error)
64  return error;
65 
66  //Force the socket to operate in non-blocking mode
67  error = socketSetTimeout(context->socket, 0);
68  //Any error to report?
69  if(error)
70  return error;
71 
72 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
73  //DTLS transport protocol?
74  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
75  {
76  //Allocate DTLS context
77  context->dtlsContext = tlsInit();
78  //Failed to allocate DTLS context?
79  if(context->dtlsContext == NULL)
80  return ERROR_OPEN_FAILED;
81 
82  //Select client operation mode
83  error = tlsSetConnectionEnd(context->dtlsContext,
85  //Any error to report?
86  if(error)
87  return error;
88 
89  //Set the transport protocol to be used (DTLS)
90  error = tlsSetTransportProtocol(context->dtlsContext,
92  //Any error to report?
93  if(error)
94  return error;
95 
96  //Bind DTLS to the relevant socket
97  error = tlsSetSocket(context->dtlsContext, context->socket);
98  //Any error to report?
99  if(error)
100  return error;
101 
102  //Force DTLS to operate in non-blocking mode
103  error = tlsSetTimeout(context->dtlsContext, 0);
104  //Any error to report?
105  if(error)
106  return error;
107 
108  //Restore DTLS session, if any
109  error = tlsRestoreSessionState(context->dtlsContext, &context->dtlsSession);
110  //Any error to report?
111  if(error)
112  return error;
113 
114  //Invoke user-defined callback, if any
115  if(context->dtlsInitCallback != NULL)
116  {
117  //Perform DTLS related initialization
118  error = context->dtlsInitCallback(context, context->dtlsContext);
119  //Any error to report?
120  if(error)
121  return error;
122  }
123  }
124 #endif
125 
126  //Successful processing
127  return NO_ERROR;
128 }
129 
130 
131 /**
132  * @brief Establish network connection
133  * @param[in] context Pointer to the CoAP client context
134  * @param[in] serverIpAddr IP address of the CoAP server
135  * @param[in] serverPort UDP port number
136  * @return Error code
137  **/
138 
140  const IpAddr *serverIpAddr, uint16_t serverPort)
141 {
142  error_t error;
143 
144  //Only accept datagrams from the specified CoAP server
145  error = socketConnect(context->socket, serverIpAddr, serverPort);
146  //Any error to report?
147  if(error)
148  return error;
149 
150 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
151  //DTLS transport protocol?
152  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
153  {
154  //Perform DTLS handshake
155  error = tlsConnect(context->dtlsContext);
156  //Any error to report?
157  if(error)
158  return error;
159 
160  //Save DTLS session
161  error = tlsSaveSessionState(context->dtlsContext, &context->dtlsSession);
162  //Any error to report?
163  if(error)
164  return error;
165  }
166 #endif
167 
168  //Successful processing
169  return NO_ERROR;
170 }
171 
172 
173 /**
174  * @brief Shutdown network connection
175  * @param[in] context Pointer to the CoAP client context
176  * @return Error code
177  **/
178 
180 {
181  error_t error;
182 
183  //Initialize status code
184  error = NO_ERROR;
185 
186 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
187  //DTLS transport protocol?
188  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
189  {
190  //Shutdown DTLS session
191  error = tlsShutdown(context->dtlsContext);
192  }
193 #endif
194 
195  //Return status code
196  return error;
197 }
198 
199 
200 /**
201  * @brief Close network connection
202  * @param[in] context Pointer to the CoAP client context
203  **/
204 
206 {
207 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
208  //DTLS transport protocol?
209  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
210  {
211  //Valid DTLS context?
212  if(context->dtlsContext != NULL)
213  {
214  //Release DTLS context
215  tlsFree(context->dtlsContext);
216  context->dtlsContext = NULL;
217  }
218  }
219 #endif
220 
221  //Valid socket?
222  if(context->socket != NULL)
223  {
224  //Close UDP socket
225  socketClose(context->socket);
226  context->socket = NULL;
227  }
228 }
229 
230 
231 /**
232  * @brief Send a datagram
233  * @param[in] context Pointer to the CoAP client context
234  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
235  * @param[in] length Length of the datagram, in bytes
236  * @return Error code
237  **/
238 
240  const void *data, size_t length)
241 {
242  error_t error;
243 
244 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
245  //DTLS transport protocol?
246  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
247  {
248  //Transmit datagram
249  error = tlsWrite(context->dtlsContext, data, length, NULL, 0);
250  }
251  else
252 #endif
253  //UDP transport protocol?
254  {
255  //Transmit datagram
256  error = socketSend(context->socket, data, length, NULL, 0);
257  }
258 
259  //Return status code
260  return error;
261 }
262 
263 
264 /**
265  * @brief Receive a datagram
266  * @param[in] context Pointer to the CoAP client context
267  * @param[out] data Buffer into which the received datagram will be placed
268  * @param[in] size Maximum number of bytes that can be received
269  * @param[out] received Number of bytes that have been received
270  * @return Error code
271  **/
272 
274  void *data, size_t size, size_t *received)
275 {
276  error_t error;
277 
278  //No data has been read yet
279  *received = 0;
280 
281 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
282  //DTLS transport protocol?
283  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
284  {
285  //Receive datagram
286  error = tlsRead(context->dtlsContext, data, size, received, 0);
287  }
288  else
289 #endif
290  //UDP transport protocol?
291  {
292  //Receive datagram
293  error = socketReceive(context->socket, data, size, received, 0);
294  }
295 
296  //Return status code
297  return error;
298 }
299 
300 
301 /**
302  * @brief Wait for incoming datagrams
303  * @param[in] context Pointer to the CoAP client context
304  * @param[in] timeout Maximum time to wait before returning
305  * @return Error code
306  **/
307 
309  systime_t timeout)
310 {
311  error_t error;
312  SocketEventDesc eventDesc[1];
313 
314  //Initialize status code
315  error = ERROR_BUFFER_EMPTY;
316 
317 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
318  //DTLS transport protocol?
319  if(context->transportProtocol == COAP_TRANSPORT_PROTOCOL_DTLS)
320  {
321  //Check whether a datagram is pending in the receive buffer
322  if(tlsIsRxReady(context->dtlsContext))
323  {
324  //No need to poll the underlying socket for incoming traffic...
325  error = NO_ERROR;
326  }
327  }
328 #endif
329 
330  //Check status code
331  if(error == ERROR_BUFFER_EMPTY)
332  {
333  //Set the events the application is interested in
334  eventDesc[0].socket = context->socket;
335  eventDesc[0].eventMask = SOCKET_EVENT_RX_READY;
336 
337  //Release exclusive access to the CoAP client context
338  osReleaseMutex(&context->mutex);
339 
340  //Wait for incoming traffic
341  error = socketPoll(eventDesc, arraysize(eventDesc), &context->event,
342  timeout);
343 
344  //Acquire exclusive access to the CoAP client context
345  osAcquireMutex(&context->mutex);
346  }
347 
348  //Return status code
349  return error;
350 }
351 
352 #endif
CoAP client.
#define CoapClientContext
Definition: coap_client.h:144
error_t coapClientEstablishConnection(CoapClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
error_t coapClientShutdownConnection(CoapClientContext *context)
Shutdown network connection.
error_t coapClientWaitForDatagram(CoapClientContext *context, systime_t timeout)
Wait for incoming datagrams.
error_t coapClientReceiveDatagram(CoapClientContext *context, void *data, size_t size, size_t *received)
Receive a datagram.
error_t coapClientSendDatagram(CoapClientContext *context, const void *data, size_t length)
Send a datagram.
void coapClientCloseConnection(CoapClientContext *context)
Close network connection.
error_t coapClientOpenConnection(CoapClientContext *context)
Open network connection.
Transport protocol abstraction layer.
@ COAP_TRANSPORT_PROTOCOL_DTLS
DTLS protocol.
Definition: coap_common.h:79
Debugging facilities.
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t data[]
Definition: ethernet.h:222
TCP/IP stack core.
#define socketBindToInterface
Definition: net_legacy.h:193
#define arraysize(a)
Definition: os_port.h:71
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint32_t systime_t
System time.
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:1592
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:1152
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
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:946
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:1517
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:811
@ SOCKET_IP_PROTO_UDP
Definition: socket.h:101
@ SOCKET_TYPE_DGRAM
Definition: socket.h:86
@ SOCKET_EVENT_RX_READY
Definition: socket.h:169
IP network address.
Definition: ip.h:79
Structure describing socket events.
Definition: socket.h:398
uint_t eventMask
Requested events.
Definition: socket.h:400
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:399
uint8_t length
Definition: tcp.h:368
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:2690
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1758
error_t tlsSaveSessionState(const TlsContext *context, TlsSessionState *session)
Save TLS session.
Definition: tls.c:2621
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:1849
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:65
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:1984
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:344
bool_t tlsIsRxReady(TlsContext *context)
Check whether some data is available in the receive buffer.
Definition: tls.c:2257
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2302
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2464
error_t tlsSetTimeout(TlsContext *context, systime_t timeout)
Set timeout for blocking calls (for DTLS only)
Definition: tls.c:1574
error_t tlsSetTransportProtocol(TlsContext *context, TlsTransportProtocol transportProtocol)
Set the transport protocol to be used.
Definition: tls.c:314
@ TLS_TRANSPORT_PROTOCOL_DATAGRAM
Definition: tls.h:942
@ TLS_CONNECTION_END_CLIENT
Definition: tls.h:953
#define tlsSetSocket(context, socket)
Definition: tls.h:912