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  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL MQTT_SN_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
34 #include "mqtt_sn/mqtt_sn_client.h"
36 #include "debug.h"
37 
38 //Check TCP/IP stack configuration
39 #if (MQTT_SN_CLIENT_SUPPORT == ENABLED)
40 
41 
42 /**
43  * @brief Open network connection
44  * @param[in] context Pointer to the MQTT-SN client context
45  * @param[in] secure Secure/non-secure connection
46  * @return Error code
47  **/
48 
50 {
51  error_t error;
52 
53  //Open a UDP socket
55  //Failed to open socket?
56  if(context->socket == NULL)
57  return ERROR_OPEN_FAILED;
58 
59  //Associate the socket with the relevant interface
60  error = socketBindToInterface(context->socket, context->interface);
61  //Any error to report?
62  if(error)
63  return error;
64 
65  //Set timeout
66  error = socketSetTimeout(context->socket, MQTT_SN_CLIENT_TICK_INTERVAL);
67  //Any error to report?
68  if(error)
69  return error;
70 
71 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
72  //DTLS transport protocol?
73  if(secure && context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
74  {
75  //Allocate DTLS context
76  context->dtlsContext = tlsInit();
77  //Failed to allocate DTLS context?
78  if(context->dtlsContext == NULL)
79  return ERROR_OPEN_FAILED;
80 
81  //Select client operation mode
82  error = tlsSetConnectionEnd(context->dtlsContext,
84  //Any error to report?
85  if(error)
86  return error;
87 
88  //Set the transport protocol to be used (DTLS)
89  error = tlsSetTransportProtocol(context->dtlsContext,
91  //Any error to report?
92  if(error)
93  return error;
94 
95  //Bind DTLS to the relevant socket
96  error = tlsSetSocket(context->dtlsContext, context->socket);
97  //Any error to report?
98  if(error)
99  return error;
100 
101  //Set timeout
102  error = tlsSetTimeout(context->dtlsContext, MQTT_SN_CLIENT_TICK_INTERVAL);
103  //Any error to report?
104  if(error)
105  return error;
106 
107  //Restore DTLS session, if any
108  error = tlsRestoreSessionState(context->dtlsContext, &context->dtlsSession);
109  //Any error to report?
110  if(error)
111  return error;
112 
113  //Invoke user-defined callback, if any
114  if(context->dtlsInitCallback != NULL)
115  {
116  //Perform DTLS related initialization
117  error = context->dtlsInitCallback(context, context->dtlsContext);
118  //Any error to report?
119  if(error)
120  return error;
121  }
122  }
123 #endif
124 
125  //Successful processing
126  return NO_ERROR;
127 }
128 
129 
130 /**
131  * @brief Establish network connection
132  * @param[in] context Pointer to the MQTT-SN client context
133  * @return Error code
134  **/
135 
137 {
138 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
139  //DTLS transport protocol?
140  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
141  {
142  error_t error;
143 
144  //Only accept datagrams from the specified MQTT-SN gateway
145  error = socketConnect(context->socket, &context->gwIpAddr,
146  context->gwPort);
147  //Any error to report?
148  if(error)
149  return error;
150 
151  //Perform DTLS handshake
152  error = tlsConnect(context->dtlsContext);
153  //Any error to report?
154  if(error)
155  return error;
156 
157  //Save DTLS session
158  error = tlsSaveSessionState(context->dtlsContext, &context->dtlsSession);
159  //Any error to report?
160  if(error)
161  return error;
162  }
163 #endif
164 
165  //Successful processing
166  return NO_ERROR;
167 }
168 
169 
170 /**
171  * @brief Shutdown network connection
172  * @param[in] context Pointer to the MQTT-SN client context
173  * @return Error code
174  **/
175 
177 {
178  error_t error;
179 
180  //Initialize status code
181  error = NO_ERROR;
182 
183 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
184  //DTLS transport protocol?
185  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
186  {
187  //Shutdown DTLS session
188  error = tlsShutdown(context->dtlsContext);
189  }
190 #endif
191 
192  //Return status code
193  return error;
194 }
195 
196 
197 /**
198  * @brief Close network connection
199  * @param[in] context Pointer to the MQTT-SN client context
200  **/
201 
203 {
204 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
205  //DTLS transport protocol?
206  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
207  {
208  //Valid DTLS context?
209  if(context->dtlsContext != NULL)
210  {
211  //Release DTLS context
212  tlsFree(context->dtlsContext);
213  context->dtlsContext = NULL;
214  }
215  }
216 #endif
217 
218  //Valid socket?
219  if(context->socket != NULL)
220  {
221  //Close UDP socket
222  socketClose(context->socket);
223  context->socket = NULL;
224  }
225 }
226 
227 
228 /**
229  * @brief Broadcast a datagram
230  * @param[in] context Pointer to the MQTT-SN client context
231  * @param[in] destIpAddr Destination IP address
232  * @param[in] destPort Destination port number
233  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
234  * @param[in] length Length of the datagram, in bytes
235  * @return Error code
236  **/
237 
239  const IpAddr *destIpAddr, uint16_t destPort, const void *data,
240  size_t length)
241 {
242  //Transmit datagram
243  return socketSendTo(context->socket, destIpAddr, destPort, data, length,
244  NULL, 0);
245 }
246 
247 
248 /**
249  * @brief Send a datagram
250  * @param[in] context Pointer to the MQTT-SN client context
251  * @param[in] data Pointer to a buffer containing the datagram to be transmitted
252  * @param[in] length Length of the datagram, in bytes
253  * @return Error code
254  **/
255 
257  const void *data, size_t length)
258 {
259  error_t error;
260 
261 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
262  //DTLS transport protocol?
263  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
264  {
265  //Transmit datagram
266  error = tlsWrite(context->dtlsContext, data, length, NULL, 0);
267  }
268  else
269 #endif
270  //UDP transport protocol?
271  {
272  //Transmit datagram
273  error = socketSendTo(context->socket, &context->gwIpAddr,
274  context->gwPort, data, length, NULL, 0);
275  }
276 
277  //Return status code
278  return error;
279 }
280 
281 
282 /**
283  * @brief Receive a datagram
284  * @param[in] context Pointer to the MQTT-SN client context
285  * @param[out] srcIpAddr Source IP address
286  * @param[out] srcPort Source port number
287  * @param[out] data Buffer into which the received datagram will be placed
288  * @param[in] size Maximum number of bytes that can be received
289  * @param[out] received Number of bytes that have been received
290  * @param[in] timeout Maximum time to wait before returning
291  * @return Error code
292  **/
293 
295  IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size,
296  size_t *received, systime_t timeout)
297 {
298  error_t error;
299 
300  //No data has been read yet
301  *received = 0;
302 
303  //Set timeout
304  socketSetTimeout(context->socket, timeout);
305 
306 #if (MQTT_SN_CLIENT_DTLS_SUPPORT == ENABLED)
307  //DTLS transport protocol?
308  if(context->transportProtocol == MQTT_SN_TRANSPORT_PROTOCOL_DTLS)
309  {
310  //Set timeout
311  tlsSetTimeout(context->dtlsContext, timeout);
312 
313  //Receive datagram
314  error = tlsRead(context->dtlsContext, data, size, received, 0);
315 
316  //Use the gateway's address as source address
317  *srcIpAddr = context->gwIpAddr;
318  *srcPort = context->gwPort;
319  }
320  else
321 #endif
322  //UDP transport protocol?
323  {
324  //Receive datagram
325  error = socketReceiveFrom(context->socket, srcIpAddr, srcPort, data,
326  size, received, 0);
327  }
328 
329  //Return status code
330  return error;
331 }
332 
333 #endif
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:1622
uint32_t systime_t
Definition: compiler_port.h:44
error_t mqttSnClientShutdownConnection(MqttSnClientContext *context)
Shutdown network connection.
error_t tlsRestoreSessionState(TlsContext *context, const TlsSessionState *session)
Restore TLS session.
Definition: tls.c:2466
uint16_t destPort
Definition: tcp.h:301
error_t mqttSnClientReceiveDatagram(MqttSnClientContext *context, IpAddr *srcIpAddr, uint16_t *srcPort, void *data, size_t size, size_t *received, systime_t timeout)
Receive a datagram.
TCP/IP stack core.
Debugging facilities.
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1531
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:310
Transport protocol abstraction layer.
#define MQTT_SN_CLIENT_TICK_INTERVAL
error_t mqttSnClientSendDatagram(MqttSnClientContext *context, const void *data, size_t length)
Send a datagram.
IP network address.
Definition: ip.h:57
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:1740
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:797
error_t tlsSetTransportProtocol(TlsContext *context, TlsTransportProtocol transportProtocol)
Set the transport protocol to be used.
Definition: tls.c:281
error_t tlsSaveSessionState(const TlsContext *context, TlsSessionState *session)
Save TLS session.
Definition: tls.c:2333
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:604
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:216
#define tlsSetSocket(context, socket)
Definition: tls.h:821
#define MqttSnClientContext
error_t tlsSetTimeout(TlsContext *context, systime_t timeout)
Set timeout for blocking calls (for DTLS only)
Definition: tls.c:1347
void mqttSnClientCloseConnection(MqttSnClientContext *context)
Close network connection.
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2018
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2178
Ipv4Addr srcIpAddr
Definition: ipcp.h:75
Success.
Definition: error.h:42
uint16_t srcPort
Definition: tcp.h:300
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:357
error_t
Error codes.
Definition: error.h:40
Ipv4Addr destIpAddr
Definition: ipcp.h:76
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:92
uint8_t data[]
Definition: dtls_misc.h:167
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:63
MQTT-SN client.
error_t mqttSnClientBroadcastDatagram(MqttSnClientContext *context, const IpAddr *destIpAddr, uint16_t destPort, const void *data, size_t length)
Broadcast a datagram.
uint8_t length
Definition: dtls_misc.h:140
error_t mqttSnClientOpenConnection(MqttSnClientContext *context, bool_t secure)
Open network connection.
error_t mqttSnClientEstablishConnection(MqttSnClientContext *context)
Establish network connection.
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:511
int bool_t
Definition: compiler_port.h:47
error_t socketBindToInterface(Socket *socket, NetInterface *interface)
Bind a socket to a particular network interface.
Definition: socket.c:309