mqtt_sn_client_transport.c
Go to the documentation of this file.
1 /**
2  * @file mqtt_sn_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 MQTT_SN_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "mqtt_sn/mqtt_sn_client.h"
38 #include "debug.h"
39 
40 //Check TCP/IP stack configuration
41 #if (MQTT_SN_CLIENT_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Open network connection
46  * @param[in] context Pointer to the MQTT-SN client context
47  * @param[in] secure Secure/non-secure connection
48  * @return Error code
49  **/
50 
52 {
53  error_t error;
54 
55  //Open a UDP socket
56  context->socket = socketOpenEx(context->netContext, SOCKET_TYPE_DGRAM,
58  //Failed to open socket?
59  if(context->socket == NULL)
60  return ERROR_OPEN_FAILED;
61 
62  //Associate the socket with the relevant interface
63  error = socketBindToInterface(context->socket, context->interface);
64  //Any error to report?
65  if(error)
66  return error;
67 
68  //Set timeout
69  error = socketSetTimeout(context->socket, MQTT_SN_CLIENT_TICK_INTERVAL);
70  //Any error to report?
71  if(error)
72  return error;
73 
74 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
75  //DTLS transport protocol?
76  if(secure && context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
77  {
78  //Allocate DTLS context
79  context->dtlsContext = tlsInit();
80  //Failed to allocate DTLS context?
81  if(context->dtlsContext == NULL)
82  return ERROR_OPEN_FAILED;
83 
84  //Select client operation mode
85  error = tlsSetConnectionEnd(context->dtlsContext,
87  //Any error to report?
88  if(error)
89  return error;
90 
91  //Set the transport protocol to be used (DTLS)
92  error = tlsSetTransportProtocol(context->dtlsContext,
94  //Any error to report?
95  if(error)
96  return error;
97 
98  //Bind DTLS to the relevant socket
99  error = tlsSetSocket(context->dtlsContext, context->socket);
100  //Any error to report?
101  if(error)
102  return error;
103 
104  //Set timeout
105  error = tlsSetTimeout(context->dtlsContext, MQTT_SN_CLIENT_TICK_INTERVAL);
106  //Any error to report?
107  if(error)
108  return error;
109 
110  //Restore DTLS session, if any
111  error = tlsRestoreSessionState(context->dtlsContext, &context->dtlsSession);
112  //Any error to report?
113  if(error)
114  return error;
115 
116  //Invoke user-defined callback, if any
117  if(context->dtlsInitCallback != NULL)
118  {
119  //Perform DTLS related initialization
120  error = context->dtlsInitCallback(context, context->dtlsContext);
121  //Any error to report?
122  if(error)
123  return error;
124  }
125  }
126 #endif
127 
128  //Successful processing
129  return NO_ERROR;
130 }
131 
132 
133 /**
134  * @brief Establish network connection
135  * @param[in] context Pointer to the MQTT-SN client context
136  * @return Error code
137  **/
138 
140 {
141 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
142  //DTLS transport protocol?
143  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
144  {
145  error_t error;
146 
147  //Only accept datagrams from the specified MQTT-SN gateway
148  error = socketConnect(context->socket, &context->gwIpAddr,
149  context->gwPort);
150  //Any error to report?
151  if(error)
152  return error;
153 
154  //Perform DTLS handshake
155  error = tlsConnect(context->dtlsContext);
156  //Any error to report?
157  if(error)
158  return error;
159  }
160 #endif
161 
162  //Successful processing
163  return NO_ERROR;
164 }
165 
166 
167 /**
168  * @brief Shutdown network connection
169  * @param[in] context Pointer to the MQTT-SN client context
170  * @return Error code
171  **/
172 
174 {
175  error_t error;
176 
177  //Initialize status code
178  error = NO_ERROR;
179 
180 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
181  //DTLS transport protocol?
182  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
183  {
184  //Shutdown DTLS session
185  error = tlsShutdown(context->dtlsContext);
186  }
187 #endif
188 
189  //Return status code
190  return error;
191 }
192 
193 
194 /**
195  * @brief Close network connection
196  * @param[in] context Pointer to the MQTT-SN client context
197  **/
198 
200 {
201 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
202  //DTLS transport protocol?
203  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
204  {
205  //Valid DTLS context?
206  if(context->dtlsContext != NULL)
207  {
208  //Release DTLS context
209  tlsFree(context->dtlsContext);
210  context->dtlsContext = NULL;
211  }
212  }
213 #endif
214 
215  //Valid socket?
216  if(context->socket != NULL)
217  {
218  //Close UDP socket
219  socketClose(context->socket);
220  context->socket = NULL;
221  }
222 }
223 
224 
225 /**
226  * @brief Broadcast a datagram
227  * @param[in] context Pointer to the MQTT-SN client context
228  * @param[in] destIpAddr Destination IP address
229  * @param[in] destPort Destination port number
230  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
231  * @param[in] length Length of the datagram, in bytes
232  * @return Error code
233  **/
234 
236  const IpAddr *destIpAddr, uint16_t destPort, const void *data,
237  size_t length)
238 {
239  //Transmit datagram
240  return socketSendTo(context->socket, destIpAddr, destPort, data, length,
241  NULL, 0);
242 }
243 
244 
245 /**
246  * @brief Send a datagram
247  * @param[in] context Pointer to the MQTT-SN client context
248  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
249  * @param[in] length Length of the datagram, in bytes
250  * @return Error code
251  **/
252 
254  const void *data, size_t length)
255 {
256  error_t error;
257 
258 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
259  //DTLS transport protocol?
260  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
261  {
262  //Transmit datagram
263  error = tlsWrite(context->dtlsContext, data, length, NULL, 0);
264  }
265  else
266 #endif
267  //UDP transport protocol?
268  {
269  //Transmit datagram
270  error = socketSendTo(context->socket, &context->gwIpAddr,
271  context->gwPort, data, length, NULL, 0);
272  }
273 
274  //Return status code
275  return error;
276 }
277 
278 
279 /**
280  * @brief Receive a datagram
281  * @param[in] context Pointer to the MQTT-SN client context
282  * @param[out] srcIpAddr Source IP address
283  * @param[out] srcPort Source port number
284  * @param[out] data Buffer into which the received datagram will be placed
285  * @param[in] size Maximum number of bytes that can be received
286  * @param[out] received Number of bytes that have been received
287  * @param[in] timeout Maximum time to wait before returning
288  * @return Error code
289  **/
290 
292  IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size,
293  size_t *received, systime_t timeout)
294 {
295  error_t error;
296 
297  //No data has been read yet
298  *received = 0;
299 
300  //Set timeout
301  socketSetTimeout(context->socket, timeout);
302 
303 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
304  //DTLS transport protocol?
305  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
306  {
307  //Set timeout
308  tlsSetTimeout(context->dtlsContext, timeout);
309 
310  //Receive datagram
311  error = tlsRead(context->dtlsContext, data, size, received, 0);
312 
313  //Use the gateway's address as source address
314  *srcIpAddr = context->gwIpAddr;
315  *srcPort = context->gwPort;
316  }
317  else
318 #endif
319  //UDP transport protocol?
320  {
321  //Receive datagram
322  error = socketReceiveFrom(context->socket, srcIpAddr, srcPort, data,
323  size, received, 0);
324  }
325 
326  //Return status code
327  return error;
328 }
329 
330 
331 /**
332  * @brief Save DTLS session
333  * @param[in] context Pointer to the MQTT-SN client context
334  * @return Error code
335  **/
336 
338 {
339  error_t error;
340 
341  //Initialize status code
342  error = NO_ERROR;
343 
344 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
345  //DTLS transport protocol?
346  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
347  {
348  //Save DTLS session
349  error = tlsSaveSessionState(context->dtlsContext, &context->dtlsSession);
350  }
351 #endif
352 
353  //Return status code
354  return error;
355 }
356 
357 #endif
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
int bool_t
Definition: compiler_port.h:63
error_t tlsSetTransportProtocol(TlsContext *context, TlsTransportProtocol transportProtocol)
Set the transport protocol to be used.
Definition: tls.c:340
IP network address.
Definition: ip.h:90
@ MQTT_SN_TRANSPORT_PROTOCOL_DTLS
DTLS protocol.
#define MqttSnClientContext
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
error_t mqttSnClientReceiveDatagram(MqttSnClientContext *context, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, systime_t timeout)
Receive a datagram.
@ SOCKET_TYPE_DGRAM
Definition: socket.h:93
uint16_t destPort
Definition: tcp.h:347
Ipv4Addr srcIpAddr
Definition: ipcp.h:79
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:3073
@ ERROR_OPEN_FAILED
Definition: error.h:75
error_t mqttSnClientOpenConnection(MqttSnClientContext *context, bool_t secure)
Open network connection.
#define MQTT_SN_CLIENT_TICK_INTERVAL
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2621
#define tlsSetSocket(context, socket)
Definition: tls.h:1008
error_t
Error codes.
Definition: error.h:43
error_t tlsSetTimeout(TlsContext *context, systime_t timeout)
Set timeout for blocking calls (for DTLS only)
Definition: tls.c:1619
error_t mqttSnClientSendDatagram(MqttSnClientContext *context, const void *data, size_t length)
Send a datagram.
error_t socketReceiveFrom(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, uint_t flags)
Receive a datagram from a connectionless socket.
Definition: socket.c:1746
error_t mqttSnClientEstablishConnection(MqttSnClientContext *context)
Establish network connection.
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
void mqttSnClientCloseConnection(MqttSnClientContext *context)
Close network connection.
#define socketBindToInterface
Definition: net_legacy.h:193
error_t mqttSnClientShutdownConnection(MqttSnClientContext *context)
Shutdown network connection.
uint32_t systime_t
System time.
Transport protocol abstraction layer.
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 socketSendTo(Socket *socket, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length, size_t *written, uint_t flags)
Send a datagram to a specific destination.
Definition: socket.c:1535
error_t mqttSnClientBroadcastDatagram(MqttSnClientContext *context, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length)
Broadcast a datagram.
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2816
MQTT-SN client.
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
error_t mqttSnClientSaveSession(MqttSnClientContext *context)
Save DTLS session.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
Ipv4Addr destIpAddr
Definition: ipcp.h:80