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