Unified coap_request_state and added status for extra information

This commit is contained in:
carlosgp143@gmail.com 2018-05-31 16:22:01 +02:00
parent 8a863a7a76
commit 2db8fa80e2
6 changed files with 216 additions and 133 deletions

View File

@ -60,37 +60,36 @@
void
coap_blocking_request_callback(void *callback_data, coap_message_t *response)
{
coap_request_state_t *state = (coap_request_state_t *)callback_data;
coap_blocking_request_state_t *blocking_state = (coap_blocking_request_state_t *)callback_data;
state->response = response;
process_poll(state->process);
blocking_state->state.response = response;
process_poll(blocking_state->process);
}
/*---------------------------------------------------------------------------*/
PT_THREAD(coap_blocking_request
(coap_request_state_t *state, process_event_t ev,
(coap_blocking_request_state_t *blocking_state, process_event_t ev,
coap_endpoint_t *remote_ep,
coap_message_t *request,
coap_blocking_response_handler_t request_callback))
{
PT_BEGIN(&state->pt);
/* Before PT_BEGIN in order to not be a local variable in the PT_Thread and maintain it */
coap_request_state_t *state = &blocking_state->state;
static uint32_t res_block;
static uint8_t more;
static uint8_t block_error;
PT_BEGIN(&blocking_state->pt);
state->block_num = 0;
state->response = NULL;
state->process = PROCESS_CURRENT();
blocking_state->process = PROCESS_CURRENT();
more = 0;
res_block = 0;
block_error = 0;
state->more = 0;
state->res_block = 0;
state->block_error = 0;
do {
request->mid = coap_get_mid();
if((state->transaction = coap_new_transaction(request->mid, remote_ep))) {
state->transaction->callback = coap_blocking_request_callback;
state->transaction->callback_data = state;
state->transaction->callback_data = blocking_state;
if(state->block_num > 0) {
coap_set_header_block2(request, state->block_num, 0,
@ -104,33 +103,46 @@ PT_THREAD(coap_blocking_request
coap_send_transaction(state->transaction);
LOG_DBG("Requested #%"PRIu32" (MID %u)\n", state->block_num, request->mid);
PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL);
PT_YIELD_UNTIL(&blocking_state->pt, ev == PROCESS_EVENT_POLL);
if(!state->response) {
LOG_WARN("Server not responding\n");
PT_EXIT(&state->pt);
state->status = COAP_REQUEST_STATUS_TIMEOUT;
PT_EXIT(&blocking_state->pt);
}
coap_get_header_block2(state->response, &res_block, &more, NULL, NULL);
coap_get_header_block2(state->response, &state->res_block, &state->more, NULL, NULL);
LOG_DBG("Received #%"PRIu32"%s (%u bytes)\n", res_block, more ? "+" : "",
LOG_DBG("Received #%"PRIu32"%s (%u bytes)\n", state->res_block, state->more ? "+" : "",
state->response->payload_len);
if(state->more) {
state->status = COAP_REQUEST_STATUS_MORE;
} else {
state->status = COAP_REQUEST_STATUS_RESPONSE;
}
if(res_block == state->block_num) {
if(state->res_block == state->block_num) {
request_callback(state->response);
++(state->block_num);
} else {
LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n",
res_block, state->block_num);
++block_error;
state->res_block, state->block_num);
++(state->block_error);
}
} else {
LOG_WARN("Could not allocate transaction buffer");
PT_EXIT(&state->pt);
PT_EXIT(&blocking_state->pt);
}
} while(more && block_error < COAP_MAX_ATTEMPTS);
} while(state->more && (state->block_error) < COAP_MAX_ATTEMPTS);
PT_END(&state->pt);
if((state->block_error) >= COAP_MAX_ATTEMPTS) {
/* failure - now we give up */
state->status = COAP_REQUEST_STATUS_BLOCK_ERROR;
} else {
/* No more blocks, request finished */
state->status = COAP_REQUEST_STATUS_FINISHED;
}
PT_END(&blocking_state->pt);
}
/*---------------------------------------------------------------------------*/
/** @} */

View File

@ -39,31 +39,30 @@
#include "sys/pt.h"
#include "coap-transactions.h"
#include "coap-request-state.h"
/*---------------------------------------------------------------------------*/
/*- Client Part -------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
typedef struct coap_request_state {
typedef struct coap_blocking_request_state {
coap_request_state_t state;
struct pt pt;
struct process *process;
coap_transaction_t *transaction;
coap_message_t *response;
uint32_t block_num;
} coap_request_state_t;
} coap_blocking_request_state_t;
typedef void (* coap_blocking_response_handler_t)(coap_message_t *response);
PT_THREAD(coap_blocking_request
(coap_request_state_t *state, process_event_t ev,
(coap_blocking_request_state_t *blocking_state, process_event_t ev,
coap_endpoint_t *remote,
coap_message_t *request,
coap_blocking_response_handler_t request_callback));
#define COAP_BLOCKING_REQUEST(server_endpoint, request, chunk_handler) \
{ \
static coap_request_state_t request_state; \
PT_SPAWN(process_pt, &request_state.pt, \
coap_blocking_request(&request_state, ev, \
static coap_blocking_request_state_t blocking_state; \
PT_SPAWN(process_pt, &blocking_state.pt, \
coap_blocking_request(&blocking_state, ev, \
server_endpoint, \
request, chunk_handler) \
); \

View File

@ -54,19 +54,13 @@
#define LOG_MODULE "coap"
#define LOG_LEVEL LOG_LEVEL_COAP
/* These should go into the state struct so that we can have multiple
requests */
static uint32_t res_block;
static uint8_t more;
static uint8_t block_error;
static void coap_request_callback(void *callback_data, coap_message_t *response);
/*---------------------------------------------------------------------------*/
static int
progress_request(coap_request_state_t *state) {
progress_request(coap_callback_request_state_t *callback_state) {
coap_request_state_t *state = &callback_state->state;
coap_message_t *request = state->request;
request->mid = coap_get_mid();
if((state->transaction =
@ -93,7 +87,9 @@ progress_request(coap_request_state_t *state) {
static void
coap_request_callback(void *callback_data, coap_message_t *response)
{
coap_request_state_t *state = (coap_request_state_t *)callback_data;
coap_callback_request_state_t *callback_state = (coap_callback_request_state_t*)callback_data;
coap_request_state_t *state = &callback_state->state;
uint32_t res_block1;
state->response = response;
@ -102,58 +98,70 @@ coap_request_callback(void *callback_data, coap_message_t *response)
if(!state->response) {
LOG_WARN("Server not responding giving up...\n");
state->callback(state);
state->status = COAP_REQUEST_STATUS_TIMEOUT;
callback_state->callback(callback_state);
return;
}
/* Got a response */
coap_get_header_block2(state->response, &res_block, &more, NULL, NULL);
coap_get_header_block2(state->response, &state->res_block, &state->more, NULL, NULL);
coap_get_header_block1(state->response, &res_block1, NULL, NULL, NULL);
LOG_DBG("Received #%lu%s B1:%lu (%u bytes)\n",
(unsigned long)res_block, (unsigned)more ? "+" : "",
(unsigned long)state->res_block, (unsigned)state->more ? "+" : "",
(unsigned long)res_block1,
state->response->payload_len);
if(res_block == state->block_num) {
if(state->res_block == state->block_num) {
/* Call the callback function as we have more data */
state->callback(state);
if(state->more) {
state->status = COAP_REQUEST_STATUS_MORE;
} else {
state->status = COAP_REQUEST_STATUS_RESPONSE;
}
callback_state->callback(callback_state);
/* this is only for counting BLOCK2 blocks.*/
++(state->block_num);
} else {
LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", res_block, state->block_num);
++block_error;
LOG_WARN("WRONG BLOCK %"PRIu32"/%"PRIu32"\n", state->res_block, state->block_num);
++(state->block_error);
}
if(more && block_error < COAP_MAX_ATTEMPTS) {
progress_request(state);
if(state->more) {
if((state->block_error) < COAP_MAX_ATTEMPTS) {
progress_request(callback_state);
} else {
/* failure - now we give up and notify the callback */
state->status = COAP_REQUEST_STATUS_BLOCK_ERROR;
callback_state->callback(callback_state);
}
} else {
/* failure - now we give up and notify the callback */
/* No more blocks, finish and notify the callback */
state->status = COAP_REQUEST_STATUS_FINISHED;
state->response = NULL;
state->callback(state);
callback_state->callback(callback_state);
}
}
/*---------------------------------------------------------------------------*/
int
coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint,
coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint,
coap_message_t *request,
void (*callback)(coap_request_state_t *state))
void (*callback)(coap_callback_request_state_t *callback_state))
{
/* can we have these variables shared between multiple requests? */
/* ripped from blocking request */
more = 0;
res_block = 0;
block_error = 0;
coap_request_state_t *state = &callback_state->state;
state->more = 0;
state->res_block = 0;
state->block_error = 0;
state->block_num = 0;
state->response = NULL;
state->request = request;
state->remote_endpoint = endpoint;
state->callback = callback;
callback_state->callback = callback;
return progress_request(state);
return progress_request(callback_state);
}
/*---------------------------------------------------------------------------*/
/** @} */

View File

@ -47,35 +47,30 @@
#include "coap-engine.h"
#include "coap-transactions.h"
#include "coap-request-state.h"
#include "sys/cc.h"
/*---------------------------------------------------------------------------*/
/*- Client Part -------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
typedef struct coap_request_state coap_request_state_t;
typedef struct coap_callback_request_state coap_callback_request_state_t;
struct coap_request_state {
coap_transaction_t *transaction;
coap_message_t *response;
coap_message_t *request;
coap_endpoint_t *remote_endpoint;
uint32_t block_num;
void *user_data;
coap_timer_t coap_timer;
void (*callback)(coap_request_state_t *state);
struct coap_callback_request_state {
coap_request_state_t state;
void (*callback)(coap_callback_request_state_t *state);
};
/**
* \brief Send a CoAP request to a remote endpoint
* \param state The state to handle the CoAP request
* \param callback_state The callback state to handle the CoAP request
* \param endpoint The destination endpoint
* \param request The request to be sent
* \param callback callback to execute when the response arrives or the timeout expires
* \return 1 if there is a transaction available to send, 0 otherwise
*/
int coap_send_request(coap_request_state_t *state, coap_endpoint_t *endpoint,
int coap_send_request(coap_callback_request_state_t *callback_state, coap_endpoint_t *endpoint,
coap_message_t *request,
void (*callback)(coap_request_state_t *state));
void (*callback)(coap_callback_request_state_t *callback_state));
#endif /* COAP_CALLBACK_API_H_ */
/** @} */

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2018, RISE SICS AB.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \addtogroup coap
* @{
*/
/**
* \file
* Common request state for all the APIs
* \author
* Carlos Gonzalo Peces <carlosgp143@gmail.com>
*/
#ifndef COAP_REQUEST_STATE_H_
#define COAP_REQUEST_STATE_H_
typedef enum {
COAP_REQUEST_STATUS_RESPONSE, /* Response received and no more blocks */
COAP_REQUEST_STATUS_MORE, /* Response received and there are more blocks */
COAP_REQUEST_STATUS_FINISHED, /* Request finished */
COAP_REQUEST_STATUS_TIMEOUT, /* Request Timeout after all retransmissions */
COAP_REQUEST_STATUS_BLOCK_ERROR /* Blocks in wrong order */
} coap_request_status_t;
typedef struct coap_request_state {
coap_transaction_t *transaction;
coap_message_t *response;
coap_message_t *request;
coap_endpoint_t *remote_endpoint;
uint32_t block_num;
uint32_t res_block;
uint8_t more;
uint8_t block_error;
void *user_data;
coap_request_status_t status;
} coap_request_state_t;
#endif /* COAP_REQUEST_STATE_H_ */
/** @} */

View File

@ -84,7 +84,7 @@
#define STATE_MACHINE_UPDATE_INTERVAL 500
static struct lwm2m_session_info session_info;
static coap_request_state_t rd_request_state;
static coap_callback_request_state_t rd_request_state;
static coap_message_t request[1]; /* This way the message can be treated as pointer as usual. */
@ -118,7 +118,6 @@ static uint8_t rd_state = 0;
static uint8_t rd_flags = FLAG_RD_DATA_UPDATE_ON_DIRTY;
static uint64_t wait_until_network_check = 0;
static uint64_t last_update;
static uint64_t last_rd_progress = 0;
static char query_data[64]; /* allocate some data for queries and updates */
static uint8_t rd_data[128]; /* allocate some data for the RD */
@ -126,7 +125,7 @@ static uint8_t rd_data[128]; /* allocate some data for the RD */
static uint32_t rd_block1;
static uint8_t rd_more;
static coap_timer_t rd_timer;
static void (*rd_callback)(coap_request_state_t *state);
static void (*rd_callback)(coap_callback_request_state_t *callback_state);
static coap_timer_t block1_timer;
@ -143,7 +142,7 @@ static void queue_mode_awake_timer_callback(coap_timer_t *timer);
#endif
static void check_periodic_observations();
static void update_callback(coap_request_state_t *state);
static void update_callback(coap_callback_request_state_t *callback_state);
static int
set_rd_data(coap_message_t *request)
@ -370,10 +369,11 @@ update_bootstrap_server(void)
* TODO
*/
static void
bootstrap_callback(coap_request_state_t *state)
bootstrap_callback(coap_callback_request_state_t *callback_state)
{
coap_request_state_t *state = &callback_state->state;
LOG_DBG("Bootstrap callback Response: %d, ", state->response != NULL);
if(state->response) {
if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
if(CHANGED_2_04 == state->response->code) {
LOG_DBG_("Considered done!\n");
rd_state = BOOTSTRAP_DONE;
@ -383,12 +383,14 @@ bootstrap_callback(coap_request_state_t *state)
LOG_DBG_("Failed with code %d. Retrying\n", state->response->code);
/* TODO Application callback? */
rd_state = INIT;
} else if(BOOTSTRAP_SENT == rd_state) { /* this can handle double invocations */
/* Failure! */
LOG_DBG("Bootstrap failed! Retry?");
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding! Retry?");
rd_state = DO_BOOTSTRAP;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED) {
LOG_DBG_("Request finished. Ignore\n");
} else {
LOG_DBG("Ignore\n");
LOG_DBG_("Unexpected error! Retry?");
rd_state = DO_BOOTSTRAP;
}
}
/*---------------------------------------------------------------------------*/
@ -427,10 +429,11 @@ block1_rd_callback(coap_timer_t *timer)
* Page 65-66 in 07 April 2016 spec.
*/
static void
registration_callback(coap_request_state_t *state)
registration_callback(coap_callback_request_state_t *callback_state)
{
LOG_DBG("Registration callback. Response: %d, ", state->response != NULL);
if(state->response) {
coap_request_state_t *state = &callback_state->state;
LOG_DBG("Registration callback. Status: %d. Response: %d, ", state->status, state->response != NULL);
if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
/* check state and possibly set registration to done */
/* If we get a continue - we need to call the rd generator one more time */
if(CONTINUE_2_31 == state->response->code) {
@ -472,10 +475,14 @@ registration_callback(coap_request_state_t *state)
}
/* TODO Application callback? */
rd_state = INIT;
/* remember last progress time */
last_rd_progress = coap_timer_uptime();
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding, trying to reconnect\n");
rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED){
LOG_DBG_("Request finished. Ignore\n");
} else {
LOG_DBG_("Ignore\n");
LOG_DBG_("Unexpected error, trying to reconnect\n");
rd_state = INIT;
}
}
/*---------------------------------------------------------------------------*/
@ -483,11 +490,12 @@ registration_callback(coap_request_state_t *state)
* Page 65-66 in 07 April 2016 spec.
*/
static void
update_callback(coap_request_state_t *state)
update_callback(coap_callback_request_state_t *callback_state)
{
LOG_DBG("Update callback. Response: %d, ", state->response != NULL);
coap_request_state_t *state = &callback_state->state;
LOG_DBG("Update callback. Status: %d. Response: %d, ", state->status, state->response != NULL);
if(state->response) {
if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
/* If we get a continue - we need to call the rd generator one more time */
if(CONTINUE_2_31 == state->response->code) {
/* We assume that size never change?! */
@ -522,20 +530,26 @@ update_callback(coap_request_state_t *state)
state->response->code);
rd_state = DO_REGISTRATION;
}
/* remember last progress */
last_rd_progress = coap_timer_uptime();
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding, trying to reconnect\n");
rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED){
LOG_DBG_("Request finished. Ignore\n");
} else {
LOG_DBG("Ignore\n");
LOG_DBG_("Unexpected error, trying to reconnect\n");
rd_state = INIT;
}
}
/*---------------------------------------------------------------------------*/
static void
deregister_callback(coap_request_state_t *state)
deregister_callback(coap_callback_request_state_t *callback_state)
{
LOG_DBG("Deregister callback. Response Code: %d\n",
coap_request_state_t *state = &callback_state->state;
LOG_DBG("Deregister callback. Status: %d. Response Code: %d\n",
state->status,
state->response != NULL ? state->response->code : 0);
if(state->response && (DELETED_2_02 == state->response->code)) {
if(state->status == COAP_REQUEST_STATUS_RESPONSE && (DELETED_2_02 == state->response->code)) {
LOG_DBG("Deregistration success\n");
rd_state = DEREGISTERED;
perform_session_callback(LWM2M_RD_CLIENT_DEREGISTERED);
@ -548,13 +562,6 @@ deregister_callback(coap_request_state_t *state)
}
}
/*---------------------------------------------------------------------------*/
static void
recover_from_rd_delay(void)
{
/* This can be improved in the future... */
rd_state = INIT;
}
/*---------------------------------------------------------------------------*/
/* CoAP timer callback */
static void
periodic_process(coap_timer_t *timer)
@ -611,10 +618,10 @@ periodic_process(coap_timer_t *timer)
LOG_INFO_COAP_EP(&session_info.bs_server_ep);
LOG_INFO_("] as '%s'\n", query_data);
coap_send_request(&rd_request_state, &session_info.bs_server_ep,
request, bootstrap_callback);
rd_state = BOOTSTRAP_SENT;
if(coap_send_request(&rd_request_state, &session_info.bs_server_ep,
request, bootstrap_callback)) {
rd_state = BOOTSTRAP_SENT;
}
}
}
break;
@ -710,18 +717,14 @@ periodic_process(coap_timer_t *timer)
}
LOG_INFO_("' More:%d\n", rd_more);
coap_send_request(&rd_request_state, &session_info.server_ep,
request, registration_callback);
last_rd_progress = coap_timer_uptime();
rd_state = REGISTRATION_SENT;
if(coap_send_request(&rd_request_state, &session_info.server_ep,
request, registration_callback)){
rd_state = REGISTRATION_SENT;
}
}
break;
case REGISTRATION_SENT:
/* just wait until the callback kicks us to the next state... */
if(last_rd_progress + MAX_RD_UPDATE_WAIT < coap_timer_uptime()) {
/* Timeout on the update - something is wrong? */
recover_from_rd_delay();
}
break;
case REGISTRATION_DONE:
/* All is done! */
@ -733,10 +736,10 @@ periodic_process(coap_timer_t *timer)
((uint32_t)session_info.lifetime * 500) <= now - last_update) {
/* triggered or time to send an update to the server, at half-time! sec vs ms */
prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
coap_send_request(&rd_request_state, &session_info.server_ep, request,
update_callback);
last_rd_progress = coap_timer_uptime();
rd_state = UPDATE_SENT;
if(coap_send_request(&rd_request_state, &session_info.server_ep, request,
update_callback)) {
rd_state = UPDATE_SENT;
}
}
break;
#if LWM2M_QUEUE_MODE_ENABLED
@ -754,27 +757,24 @@ periodic_process(coap_timer_t *timer)
LWM2M_QUEUE_MODE_WAKE_UP();
#endif /* LWM2M_QUEUE_MODE_WAKE_UP */
prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
coap_send_request(&rd_request_state, &session_info.server_ep, request,
update_callback);
last_rd_progress = coap_timer_uptime();
rd_state = UPDATE_SENT;
if(coap_send_request(&rd_request_state, &session_info.server_ep, request,
update_callback)) {
rd_state = UPDATE_SENT;
}
break;
#endif /* LWM2M_QUEUE_MODE_ENABLED */
case UPDATE_SENT:
/* just wait until the callback kicks us to the next state... */
if(last_rd_progress + MAX_RD_UPDATE_WAIT < coap_timer_uptime()) {
/* Timeout on the update - something is wrong? */
recover_from_rd_delay();
}
break;
case DEREGISTER:
LOG_INFO("DEREGISTER %s\n", session_info.assigned_ep);
coap_init_message(request, COAP_TYPE_CON, COAP_DELETE, 0);
coap_set_header_uri_path(request, session_info.assigned_ep);
coap_send_request(&rd_request_state, &session_info.server_ep, request,
deregister_callback);
rd_state = DEREGISTER_SENT;
if(coap_send_request(&rd_request_state, &session_info.server_ep, request,
deregister_callback)) {
rd_state = DEREGISTER_SENT;
}
break;
case DEREGISTER_SENT:
break;