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-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 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
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  //Set timeout
68  error = socketSetTimeout(context->socket, MQTT_SN_CLIENT_TICK_INTERVAL);
69  //Any error to report?
70  if(error)
71  return error;
72 
73 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
74  //DTLS transport protocol?
75  if(secure && context->transportProtocol == MQTT_SN_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  //Set timeout
104  error = tlsSetTimeout(context->dtlsContext, MQTT_SN_CLIENT_TICK_INTERVAL);
105  //Any error to report?
106  if(error)
107  return error;
108 
109  //Restore DTLS session, if any
110  error = tlsRestoreSessionState(context->dtlsContext, &context->dtlsSession);
111  //Any error to report?
112  if(error)
113  return error;
114 
115  //Invoke user-defined callback, if any
116  if(context->dtlsInitCallback != NULL)
117  {
118  //Perform DTLS related initialization
119  error = context->dtlsInitCallback(context, context->dtlsContext);
120  //Any error to report?
121  if(error)
122  return error;
123  }
124  }
125 #endif
126 
127  //Successful processing
128  return NO_ERROR;
129 }
130 
131 
132 /**
133  * @brief Establish network connection
134  * @param[in] context Pointer to the MQTT-SN client context
135  * @return Error code
136  **/
137 
139 {
140 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
141  //DTLS transport protocol?
142  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
143  {
144  error_t error;
145 
146  //Only accept datagrams from the specified MQTT-SN gateway
147  error = socketConnect(context->socket, &context->gwIpAddr,
148  context->gwPort);
149  //Any error to report?
150  if(error)
151  return error;
152 
153  //Perform DTLS handshake
154  error = tlsConnect(context->dtlsContext);
155  //Any error to report?
156  if(error)
157  return error;
158 
159  //Save DTLS session
160  error = tlsSaveSessionState(context->dtlsContext, &context->dtlsSession);
161  //Any error to report?
162  if(error)
163  return error;
164  }
165 #endif
166 
167  //Successful processing
168  return NO_ERROR;
169 }
170 
171 
172 /**
173  * @brief Shutdown network connection
174  * @param[in] context Pointer to the MQTT-SN client context
175  * @return Error code
176  **/
177 
179 {
180  error_t error;
181 
182  //Initialize status code
183  error = NO_ERROR;
184 
185 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
186  //DTLS transport protocol?
187  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
188  {
189  //Shutdown DTLS session
190  error = tlsShutdown(context->dtlsContext);
191  }
192 #endif
193 
194  //Return status code
195  return error;
196 }
197 
198 
199 /**
200  * @brief Close network connection
201  * @param[in] context Pointer to the MQTT-SN client context
202  **/
203 
205 {
206 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
207  //DTLS transport protocol?
208  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
209  {
210  //Valid DTLS context?
211  if(context->dtlsContext != NULL)
212  {
213  //Release DTLS context
214  tlsFree(context->dtlsContext);
215  context->dtlsContext = NULL;
216  }
217  }
218 #endif
219 
220  //Valid socket?
221  if(context->socket != NULL)
222  {
223  //Close UDP socket
224  socketClose(context->socket);
225  context->socket = NULL;
226  }
227 }
228 
229 
230 /**
231  * @brief Broadcast a datagram
232  * @param[in] context Pointer to the MQTT-SN client context
233  * @param[in] destIpAddr Destination IP address
234  * @param[in] destPort Destination port number
235  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
236  * @param[in] length Length of the datagram, in bytes
237  * @return Error code
238  **/
239 
241  const IpAddr *destIpAddr, uint16_t destPort, const void *data,
242  size_t length)
243 {
244  //Transmit datagram
245  return socketSendTo(context->socket, destIpAddr, destPort, data, length,
246  NULL, 0);
247 }
248 
249 
250 /**
251  * @brief Send a datagram
252  * @param[in] context Pointer to the MQTT-SN client context
253  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
254  * @param[in] length Length of the datagram, in bytes
255  * @return Error code
256  **/
257 
259  const void *data, size_t length)
260 {
261  error_t error;
262 
263 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
264  //DTLS transport protocol?
265  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
266  {
267  //Transmit datagram
268  error = tlsWrite(context->dtlsContext, data, length, NULL, 0);
269  }
270  else
271 #endif
272  //UDP transport protocol?
273  {
274  //Transmit datagram
275  error = socketSendTo(context->socket, &context->gwIpAddr,
276  context->gwPort, data, length, NULL, 0);
277  }
278 
279  //Return status code
280  return error;
281 }
282 
283 
284 /**
285  * @brief Receive a datagram
286  * @param[in] context Pointer to the MQTT-SN client context
287  * @param[out] srcIpAddr Source IP address
288  * @param[out] srcPort Source port number
289  * @param[out] data Buffer into which the received datagram will be placed
290  * @param[in] size Maximum number of bytes that can be received
291  * @param[out] received Number of bytes that have been received
292  * @param[in] timeout Maximum time to wait before returning
293  * @return Error code
294  **/
295 
297  IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size,
298  size_t *received, systime_t timeout)
299 {
300  error_t error;
301 
302  //No data has been read yet
303  *received = 0;
304 
305  //Set timeout
306  socketSetTimeout(context->socket, timeout);
307 
308 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
309  //DTLS transport protocol?
310  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
311  {
312  //Set timeout
313  tlsSetTimeout(context->dtlsContext, timeout);
314 
315  //Receive datagram
316  error = tlsRead(context->dtlsContext, data, size, received, 0);
317 
318  //Use the gateway's address as source address
319  *srcIpAddr = context->gwIpAddr;
320  *srcPort = context->gwPort;
321  }
322  else
323 #endif
324  //UDP transport protocol?
325  {
326  //Receive datagram
327  error = socketReceiveFrom(context->socket, srcIpAddr, srcPort, data,
328  size, received, 0);
329  }
330 
331  //Return status code
332  return error;
333 }
334 
335 #endif
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
error_t
Error codes.
Definition: error.h:43
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t data[]
Definition: ethernet.h:222
Ipv4Addr destIpAddr
Definition: ipcp.h:80
Ipv4Addr srcIpAddr
Definition: ipcp.h:79
MQTT-SN client.
#define MQTT_SN_CLIENT_TICK_INTERVAL
#define MqttSnClientContext
void mqttSnClientCloseConnection(MqttSnClientContext *context)
Close network connection.
error_t mqttSnClientOpenConnection(MqttSnClientContext *context, bool_t secure)
Open network connection.
error_t mqttSnClientReceiveDatagram(MqttSnClientContext *context, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, systime_t timeout)
Receive a datagram.
error_t mqttSnClientShutdownConnection(MqttSnClientContext *context)
Shutdown network connection.
error_t mqttSnClientEstablishConnection(MqttSnClientContext *context)
Establish network connection.
error_t mqttSnClientBroadcastDatagram(MqttSnClientContext *context, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length)
Broadcast a datagram.
error_t mqttSnClientSendDatagram(MqttSnClientContext *context, const void *data, size_t length)
Send a datagram.
Transport protocol abstraction layer.
@ MQTT_SN_TRANSPORT_PROTOCOL_DTLS
DTLS protocol.
TCP/IP stack core.
#define socketBindToInterface
Definition: net_legacy.h:193
uint32_t systime_t
System time.
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:1174
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:967
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
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
IP network address.
Definition: ip.h:79
uint8_t length
Definition: tcp.h:368
uint16_t destPort
Definition: tcp.h:340
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
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