coap_client.c
Go to the documentation of this file.
1 /**
2  * @file coap_client.c
3  * @brief CoAP client
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 <stdlib.h>
34 #include "core/net.h"
35 #include "coap/coap_client.h"
37 #include "coap/coap_client_misc.h"
38 #include "coap/coap_debug.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (COAP_CLIENT_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Initialize CoAP client context
47  * @param[in] context Pointer to the CoAP client context
48  * @return Error code
49  **/
50 
52 {
53  error_t error;
54 
55  //Make sure the CoAP client context is valid
56  if(context == NULL)
58 
59  //Clear CoAP client context
60  memset(context, 0, sizeof(CoapClientContext));
61 
62  //Initialize status code
63  error = NO_ERROR;
64 
65  //Start of exception handling block
66  do
67  {
68  //Create a mutex to prevent simultaneous access to the context
69  if(!osCreateMutex(&context->mutex))
70  {
71  //Report an error
72  error = ERROR_OUT_OF_RESOURCES;
73  break;
74  }
75 
76  //Create a event object to receive notifications
77  if(!osCreateEvent(&context->event))
78  {
79  //Report an error
80  error = ERROR_OUT_OF_RESOURCES;
81  break;
82  }
83 
84 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
85  //Initialize DTLS session state
86  error = tlsInitSessionState(&context->dtlsSession);
87  //Any error to report?
88  if(error)
89  break;
90 #endif
91 
92  //Initialize CoAP client state
93  context->state = COAP_CLIENT_STATE_DISCONNECTED;
94 
95  //Default transport protocol
96  context->transportProtocol = COAP_TRANSPORT_PROTOCOL_UDP;
97  //Default timeout
98  context->timeout = COAP_CLIENT_DEFAULT_TIMEOUT;
99  //Default token length
100  context->tokenLen = COAP_CLIENT_DEFAULT_TOKEN_LEN;
101 
102  //It is strongly recommended that the initial value of the message ID
103  //be randomized (refer to RFC 7252, section 4.4)
104  context->mid = (uint16_t) netGetRand();
105 
106  //End of exception handling block
107  } while(0);
108 
109  //Check status code
110  if(error)
111  {
112  //Clean up side effects
113  coapClientDeinit(context);
114  }
115 
116  //Return status code
117  return error;
118 }
119 
120 
121 /**
122  * @brief Set the transport protocol to be used
123  * @param[in] context Pointer to the CoAP client context
124  * @param[in] transportProtocol Transport protocol to be used (UDP or DTLS)
125  * @return Error code
126  **/
127 
129  CoapTransportProtocol transportProtocol)
130 {
131  //Make sure the CoAP client context is valid
132  if(context == NULL)
134 
135  //Acquire exclusive access to the CoAP client context
136  osAcquireMutex(&context->mutex);
137  //Save the transport protocol to be used
138  context->transportProtocol = transportProtocol;
139  //Release exclusive access to the CoAP client context
140  osReleaseMutex(&context->mutex);
141 
142  //Successful processing
143  return NO_ERROR;
144 }
145 
146 
147 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
148 
149 /**
150  * @brief Register DTLS initialization callback function
151  * @param[in] context Pointer to the CoAP client context
152  * @param[in] callback DTLS initialization callback function
153  * @return Error code
154  **/
155 
158 {
159  //Check parameters
160  if(context == NULL || callback == NULL)
162 
163  //Acquire exclusive access to the CoAP client context
164  osAcquireMutex(&context->mutex);
165  //Save callback function
166  context->dtlsInitCallback = callback;
167  //Release exclusive access to the CoAP client context
168  osReleaseMutex(&context->mutex);
169 
170  //Successful processing
171  return NO_ERROR;
172 }
173 
174 #endif
175 
176 
177 /**
178  * @brief Set default request timeout
179  * @param[in] context Pointer to the CoAP client context
180  * @param[in] timeout Timeout value, in milliseconds
181  * @return Error code
182  **/
183 
185 {
186  //Make sure the CoAP client context is valid
187  if(context == NULL)
189 
190  //Acquire exclusive access to the CoAP client context
191  osAcquireMutex(&context->mutex);
192  //Save timeout value
193  context->timeout = timeout;
194  //Release exclusive access to the CoAP client context
195  osReleaseMutex(&context->mutex);
196 
197  //Successful processing
198  return NO_ERROR;
199 }
200 
201 
202 /**
203  * @brief Set the length of the token
204  * @param[in] context Pointer to the CoAP client context
205  * @param[in] length Token length
206  * @return Error code
207  **/
208 
210 {
211  //Make sure the CoAP client context is valid
212  if(context == NULL)
214 
215  //Make sure the token length is acceptable
218 
219  //Acquire exclusive access to the CoAP client context
220  osAcquireMutex(&context->mutex);
221  //Save token length
222  context->tokenLen = length;
223  //Release exclusive access to the CoAP client context
224  osReleaseMutex(&context->mutex);
225 
226  //Successful processing
227  return NO_ERROR;
228 }
229 
230 
231 /**
232  * @brief Bind the CoAP client to a particular network interface
233  * @param[in] context Pointer to the CoAP client context
234  * @param[in] interface Network interface to be used
235  * @return Error code
236  **/
237 
239  NetInterface *interface)
240 {
241  //Make sure the CoAP client context is valid
242  if(context == NULL)
244 
245  //Acquire exclusive access to the CoAP client context
246  osAcquireMutex(&context->mutex);
247  //Explicitly associate the CoAP client with the specified interface
248  context->interface = interface;
249  //Release exclusive access to the CoAP client context
250  osReleaseMutex(&context->mutex);
251 
252  //Successful processing
253  return NO_ERROR;
254 }
255 
256 
257 /**
258  * @brief Establish connection with the CoAP server
259  * @param[in] context Pointer to the CoAP client context
260  * @param[in] serverIpAddr IP address of the CoAP server to connect to
261  * @param[in] serverPort UDP port number that will be used
262  * @return Error code
263  **/
264 
266  const IpAddr *serverIpAddr, uint16_t serverPort)
267 {
268  error_t error;
269  systime_t time;
270 
271  //Check parameters
272  if(context == NULL || serverIpAddr == NULL)
274 
275  //Acquire exclusive access to the CoAP client context
276  osAcquireMutex(&context->mutex);
277 
278  //Initialize status code
279  error = NO_ERROR;
280 
281  //Establish connection with the CoAP server
282  while(!error)
283  {
284  //Get current time
285  time = osGetSystemTime();
286 
287  //Check current state
288  if(context->state == COAP_CLIENT_STATE_DISCONNECTED)
289  {
290  //Open network connection
291  error = coapClientOpenConnection(context);
292 
293  //Check status code
294  if(!error)
295  {
296  //Save current time
297  context->startTime = time;
298  //Update CoAP client state
299  context->state = COAP_CLIENT_STATE_CONNECTING;
300  }
301  }
302  else if(context->state == COAP_CLIENT_STATE_CONNECTING)
303  {
304  //Establish DTLS connection
305  error = coapClientEstablishConnection(context, serverIpAddr,
306  serverPort);
307 
308  //Check status code
309  if(error == NO_ERROR)
310  {
311  //Update CoAP client state
312  context->state = COAP_CLIENT_STATE_CONNECTED;
313  }
314  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
315  {
316  //Check whether the timeout has elapsed
317  if(timeCompare(time, context->startTime + context->timeout) < 0)
318  {
319  //Wait for an incoming datagram
321  //Continue processing
322  error = NO_ERROR;
323  }
324  else
325  {
326  //Report an error
327  error = ERROR_TIMEOUT;
328  }
329  }
330  else
331  {
332  //Just for sanity
333  }
334  }
335  else if(context->state == COAP_CLIENT_STATE_CONNECTED)
336  {
337  //The CoAP client is connected
338  break;
339  }
340  else
341  {
342  //Invalid state
343  error = ERROR_WRONG_STATE;
344  }
345  }
346 
347  //Failed to establish connection with the CoAP server?
348  if(error)
349  {
350  //Clean up side effects
351  coapClientCloseConnection(context);
352  //Update CoAP client state
353  context->state = COAP_CLIENT_STATE_DISCONNECTED;
354  }
355 
356  //Release exclusive access to the CoAP client context
357  osReleaseMutex(&context->mutex);
358 
359  //Return status code
360  return error;
361 }
362 
363 
364 /**
365  * @brief Process CoAP client events
366  * @param[in] context Pointer to the CoAP client context
367  * @param[in] timeout Maximum time to wait before returning
368  * @return Error code
369  **/
370 
372 {
373  error_t error;
374 
375  //Make sure the CoAP client context is valid
376  if(context == NULL)
378 
379  //Acquire exclusive access to the CoAP client context
380  osAcquireMutex(&context->mutex);
381  //Process CoAP client events
382  error = coapClientProcessEvents(context, timeout);
383  //Release exclusive access to the CoAP client context
384  osReleaseMutex(&context->mutex);
385 
386  //Return status code
387  return error;
388 }
389 
390 
391 /**
392  * @brief Disconnect from the CoAP server
393  * @param[in] context Pointer to the CoAP client context
394  * @return Error code
395  **/
396 
398 {
399  error_t error;
400 
401  //Make sure the CoAP client context is valid
402  if(context == NULL)
404 
405  //Initialize status code
406  error = NO_ERROR;
407 
408  //Acquire exclusive access to the CoAP client context
409  osAcquireMutex(&context->mutex);
410 
411  //Check current state
412  if(context->state == COAP_CLIENT_STATE_CONNECTED)
413  {
414  //Terminate DTLS connection
415  error = coapClientShutdownConnection(context);
416  }
417 
418  //Close connection
419  coapClientCloseConnection(context);
420  //Update CoAP client state
421  context->state = COAP_CLIENT_STATE_DISCONNECTED;
422 
423  //Release exclusive access to the CoAP client context
424  osReleaseMutex(&context->mutex);
425 
426  //Return status code
427  return error;
428 }
429 
430 
431 /**
432  * @brief Release CoAP client context
433  * @param[in] context Pointer to the CoAP client context
434  **/
435 
437 {
438  //Make sure the CoAP client context is valid
439  if(context != NULL)
440  {
441  //Close connection
442  coapClientCloseConnection(context);
443 
444 #if (COAP_CLIENT_DTLS_SUPPORT == ENABLED)
445  //Release DTLS session state
446  tlsFreeSessionState(&context->dtlsSession);
447 #endif
448 
449  //Release previously allocated resources
450  osDeleteMutex(&context->mutex);
451  osDeleteEvent(&context->event);
452 
453  //Clear CoAP client context
454  memset(context, 0, sizeof(CoapClientContext));
455  }
456 }
457 
458 #endif
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
CoapTransportProtocol
CoAP transport protocols.
Definition: coap_common.h:80
uint32_t systime_t
Definition: compiler_port.h:44
error_t coapClientSetTransportProtocol(CoapClientContext *context, CoapTransportProtocol transportProtocol)
Set the transport protocol to be used.
Definition: coap_client.c:128
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
#define timeCompare(t1, t2)
Definition: os_port.h:40
Helper functions for CoAP client.
error_t coapClientEstablishConnection(CoapClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish network connection.
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t time
#define COAP_MAX_TOKEN_LEN
Definition: coap_common.h:48
TCP/IP stack core.
Debugging facilities.
error_t coapClientBindToInterface(CoapClientContext *context, NetInterface *interface)
Bind the CoAP client to a particular network interface.
Definition: coap_client.c:238
error_t coapClientDisconnect(CoapClientContext *context)
Disconnect from the CoAP server.
Definition: coap_client.c:397
Invalid parameter.
Definition: error.h:45
IP network address.
Definition: ip.h:57
error_t tlsInitSessionState(TlsSessionState *session)
Initialize session state.
Definition: tls.c:2312
#define COAP_CLIENT_DEFAULT_TIMEOUT
Definition: coap_client.h:75
bool_t osCreateEvent(OsEvent *event)
Create an event object.
error_t coapClientProcessEvents(CoapClientContext *context, systime_t timeout)
Process CoAP client events.
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1523
error_t coapClientSetTimeout(CoapClientContext *context, systime_t timeout)
Set default request timeout.
Definition: coap_client.c:184
error_t coapClientInit(CoapClientContext *context)
Initialize CoAP client context.
Definition: coap_client.c:51
void tlsFreeSessionState(TlsSessionState *session)
Properly dispose a session state.
Definition: tls.c:2594
error_t coapClientShutdownConnection(CoapClientContext *context)
Shutdown network connection.
Success.
Definition: error.h:42
error_t(* CoapClientDtlsInitCallback)(CoapClientContext *context, TlsContext *dtlsContext)
DTLS initialization callback.
Definition: coap_client.h:171
error_t
Error codes.
Definition: error.h:40
error_t coapClientOpenConnection(CoapClientContext *context)
Open network connection.
void coapClientCloseConnection(CoapClientContext *context)
Close network connection.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define NetInterface
Definition: net.h:34
error_t coapClientRegisterDtlsInitCallback(CoapClientContext *context, CoapClientDtlsInitCallback callback)
Register DTLS initialization callback function.
Definition: coap_client.c:156
error_t coapClientWaitForDatagram(CoapClientContext *context, systime_t timeout)
Wait for incoming datagrams.
void osDeleteEvent(OsEvent *event)
Delete an event object.
CoAP client.
error_t coapClientSetTokenLength(CoapClientContext *context, size_t length)
Set the length of the token.
Definition: coap_client.c:209
#define COAP_CLIENT_DEFAULT_TOKEN_LEN
Definition: coap_client.h:124
void coapClientDeinit(CoapClientContext *context)
Release CoAP client context.
Definition: coap_client.c:436
Data logging functions for debugging purpose (CoAP)
error_t coapClientTask(CoapClientContext *context, systime_t timeout)
Process CoAP client events.
Definition: coap_client.c:371
uint8_t length
Definition: dtls_misc.h:140
error_t coapClientConnect(CoapClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish connection with the CoAP server.
Definition: coap_client.c:265
Transport protocol abstraction layer.
#define COAP_CLIENT_TICK_INTERVAL
Definition: coap_client.h:68
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define CoapClientContext
Definition: coap_client.h:137