Contiki-NG
coap-callback-api.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, SICS Swedish ICT
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *
30  */
31 
32 /**
33  * \file
34  * Callback API for doing CoAP requests
35  * Adapted from the blocking API
36  * \author
37  * Joakim Eriksson, joakime@sics.se
38  */
39 
40 /**
41  * \addtogroup coap
42  * @{
43  */
44 
45 #include "coap-engine.h"
46 #include "coap-callback-api.h"
47 #include "coap-transactions.h"
48 #include "sys/cc.h"
49 #include <stdlib.h>
50 #include <string.h>
51 #include <inttypes.h>
52 
53 /* Log configuration */
54 #include "coap-log.h"
55 #define LOG_MODULE "coap"
56 #define LOG_LEVEL LOG_LEVEL_COAP
57 
58 static void coap_request_callback(void *callback_data, coap_message_t *response);
59 
60 /*---------------------------------------------------------------------------*/
61 
62 static int
63 progress_request(coap_callback_request_state_t *callback_state) {
64  coap_request_state_t *state = &callback_state->state;
65  coap_message_t *request = state->request;
66  request->mid = coap_get_mid();
67  if((state->transaction =
68  coap_new_transaction(request->mid, state->remote_endpoint))) {
69  state->transaction->callback = coap_request_callback;
70  state->transaction->callback_data = state;
71 
72  if(state->block_num > 0) {
73  coap_set_header_block2(request, state->block_num, 0,
74  COAP_MAX_CHUNK_SIZE);
75  }
76  state->transaction->message_len =
77  coap_serialize_message(request, state->transaction->message);
78 
79  coap_send_transaction(state->transaction);
80  LOG_DBG("Requested #%"PRIu32" (MID %u)\n", state->block_num, request->mid);
81  return 1;
82  }
83  return 0;
84 }
85 
86 /*---------------------------------------------------------------------------*/
87 
88 static void
89 coap_request_callback(void *callback_data, coap_message_t *response)
90 {
91  coap_callback_request_state_t *callback_state = (coap_callback_request_state_t*)callback_data;
92  coap_request_state_t *state = &callback_state->state;
93 
94  uint32_t res_block1;
95 
96  state->response = response;
97 
98  LOG_DBG("request callback\n");
99 
100  if(!state->response) {
101  LOG_WARN("Server not responding giving up...\n");
102  state->status = COAP_REQUEST_STATUS_TIMEOUT;
103  callback_state->callback(callback_state);
104  return;
105  }
106 
107  /* Got a response */
108  coap_get_header_block2(state->response, &state->res_block, &state->more, NULL, NULL);
109  coap_get_header_block1(state->response, &res_block1, NULL, NULL, NULL);
110 
111  LOG_DBG("Received #%lu%s B1:%lu (%u bytes)\n",
112  (unsigned long)state->res_block, (unsigned)state->more ? "+" : "",
113  (unsigned long)res_block1,
114  state->response->payload_len);
115 
116  if(state->res_block == state->block_num) {
117  /* Call the callback function as we have more data */
118  if(state->more) {
119  state->status = COAP_REQUEST_STATUS_MORE;
120  } else {
121  state->status = COAP_REQUEST_STATUS_RESPONSE;
122  }
123  callback_state->callback(callback_state);
124  /* this is only for counting BLOCK2 blocks.*/
125  ++(state->block_num);
126  } else {
127  LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", state->res_block, state->block_num);
128  ++(state->block_error);
129  }
130 
131  if(state->more) {
132  if((state->block_error) < COAP_MAX_ATTEMPTS) {
133  progress_request(callback_state);
134  } else {
135  /* failure - now we give up and notify the callback */
136  state->status = COAP_REQUEST_STATUS_BLOCK_ERROR;
137  callback_state->callback(callback_state);
138  }
139  } else {
140  /* No more blocks, finish and notify the callback */
141  state->status = COAP_REQUEST_STATUS_FINISHED;
142  state->response = NULL;
143  callback_state->callback(callback_state);
144  }
145 }
146 
147 /*---------------------------------------------------------------------------*/
148 
149 int
150 coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint,
151  coap_message_t *request,
152  void (*callback)(coap_callback_request_state_t *callback_state))
153 {
154  coap_request_state_t *state = &callback_state->state;
155 
156  state->more = 0;
157  state->res_block = 0;
158  state->block_error = 0;
159  state->block_num = 0;
160  state->response = NULL;
161  state->request = request;
162  state->remote_endpoint = endpoint;
163  callback_state->callback = callback;
164 
165  return progress_request(callback_state);
166 }
167 /*---------------------------------------------------------------------------*/
168 /** @} */
Log support for CoAP
int coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint, coap_message_t *request, void(*callback)(coap_callback_request_state_t *callback_state))
Send a CoAP request to a remote endpoint.
CoAP engine implementation.
Callback API for doing CoAP requests Adapted from the blocking API
CoAP module for reliable transport
Default definitions of C compiler quirk work-arounds.