Added support for multiple server session in LwM2M

This commit is contained in:
carlosgp143@gmail.com 2018-04-30 13:04:23 +02:00 committed by Carlos Gonzalo
parent 21f9d1710c
commit be71b5fc1d
4 changed files with 537 additions and 399 deletions

View File

@ -34,6 +34,7 @@
* \author * \author
* Joakim Eriksson, joakime@sics.se * Joakim Eriksson, joakime@sics.se
* Niclas Finne, nfi@sics.se * Niclas Finne, nfi@sics.se
* Carlos Gonzalo Peces, carlosgp143@gmail.com
*/ */
#include "contiki.h" #include "contiki.h"
@ -63,6 +64,20 @@
#define LWM2M_SERVER_ADDRESS "coap://[fd00::1]" #define LWM2M_SERVER_ADDRESS "coap://[fd00::1]"
#endif #endif
#ifndef LWM2M_SERVER_ADDRESS_SECOND
#define LWM2M_SERVER_ADDRESS_SECOND "coap://[fd00::1]:5686"
#endif
#ifndef LWM2M_SESSIONS
#define LWM2M_SESSIONS 2
#endif
static lwm2m_session_info_t session_info;
#if LWM2M_SESSIONS == 2
static lwm2m_session_info_t session_info_second;
#endif
#if BOARD_SENSORTAG #if BOARD_SENSORTAG
#include "board-peripherals.h" #include "board-peripherals.h"
@ -148,13 +163,27 @@ setup_lwm2m_servers(void)
coap_endpoint_t server_ep; coap_endpoint_t server_ep;
if(coap_endpoint_parse(LWM2M_SERVER_ADDRESS, strlen(LWM2M_SERVER_ADDRESS), if(coap_endpoint_parse(LWM2M_SERVER_ADDRESS, strlen(LWM2M_SERVER_ADDRESS),
&server_ep) != 0) { &server_ep) != 0) {
lwm2m_rd_client_register_with_bootstrap_server(&server_ep); #if REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER
lwm2m_rd_client_register_with_server(&server_ep); lwm2m_rd_client_register_with_bootstrap_server(&session_info, &server_ep);
#else
lwm2m_rd_client_register_with_server(&session_info, &server_ep);
#endif
} }
#endif /* LWM2M_SERVER_ADDRESS */ #endif /* LWM2M_SERVER_ADDRESS */
lwm2m_rd_client_use_bootstrap_server(REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER); #if LWM2M_SESSIONS == 2
lwm2m_rd_client_use_registration_server(REGISTER_WITH_LWM2M_SERVER); #ifdef LWM2M_SERVER_ADDRESS_SECOND
coap_endpoint_t server_ep_second;
if(coap_endpoint_parse(LWM2M_SERVER_ADDRESS_SECOND, strlen(LWM2M_SERVER_ADDRESS_SECOND),
&server_ep_second) != 0) {
#if REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER
lwm2m_rd_client_register_with_bootstrap_server(&session_info_second, &server_ep_second);
#else
lwm2m_rd_client_register_with_server(&session_info_second, &server_ep_second);
#endif
}
#endif /* LWM2M_SERVER_ADDRESS_SECOND */
#endif /* LWM2M_SESSIONS == 2 */
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_ipso_objects, ev, data) PROCESS_THREAD(example_ipso_objects, ev, data)

View File

@ -54,6 +54,7 @@
#include "coap-endpoint.h" #include "coap-endpoint.h"
#include "coap-callback-api.h" #include "coap-callback-api.h"
#include "lwm2m-security.h" #include "lwm2m-security.h"
#include "lib/list.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
@ -76,18 +77,11 @@
#define LWM2M_DEFAULT_CLIENT_LIFETIME 30 /* sec */ #define LWM2M_DEFAULT_CLIENT_LIFETIME 30 /* sec */
#endif #endif
#define MAX_RD_UPDATE_WAIT 5000
#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) #define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT)
#define BS_REMOTE_PORT UIP_HTONS(5685) #define BS_REMOTE_PORT UIP_HTONS(5685)
#define STATE_MACHINE_UPDATE_INTERVAL 500 #define STATE_MACHINE_UPDATE_INTERVAL 500
static struct lwm2m_session_info session_info;
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. */
/* The states for the RD client state machine */ /* The states for the RD client state machine */
/* When node is unregistered it ends up in UNREGISTERED /* When node is unregistered it ends up in UNREGISTERED
and this is going to be there until use X or Y kicks it and this is going to be there until use X or Y kicks it
@ -114,20 +108,18 @@ static coap_message_t request[1]; /* This way the message can be treated as
#define FLAG_RD_DATA_UPDATE_TRIGGERED 0x02 #define FLAG_RD_DATA_UPDATE_TRIGGERED 0x02
#define FLAG_RD_DATA_UPDATE_ON_DIRTY 0x10 #define FLAG_RD_DATA_UPDATE_ON_DIRTY 0x10
static uint8_t rd_state = 0; /* The type of server to use: bootstrap or registration */
static uint8_t rd_flags = FLAG_RD_DATA_UPDATE_ON_DIRTY; #define USE_BOOTSTRAP_SERVER 0
static uint64_t wait_until_network_check = 0; #define USE_REGISTRATION_SERVER 1
static uint64_t last_update;
LIST(session_info_list);
/* Shared by all sessions, used by only one at a time in the FSM */
static char query_data[64]; /* allocate some data for queries and updates */ static char query_data[64]; /* allocate some data for queries and updates */
static uint8_t rd_data[128]; /* allocate some data for the RD */ static uint8_t rd_data[128]; /* allocate some data for the RD */
static uint32_t rd_block1; static coap_timer_t rd_timer; /* Timer to tick the FSM periodically */
static uint8_t rd_more; static char default_ep [20];
static coap_timer_t rd_timer;
static void (*rd_callback)(coap_callback_request_state_t *callback_state);
static coap_timer_t block1_timer;
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
static coap_timer_t queue_mode_client_awake_timer; /* Timer to control the client's static coap_timer_t queue_mode_client_awake_timer; /* Timer to control the client's
@ -145,7 +137,7 @@ static void check_periodic_observations();
static void update_callback(coap_callback_request_state_t *callback_state); static void update_callback(coap_callback_request_state_t *callback_state);
static int static int
set_rd_data(coap_message_t *request) set_rd_data(lwm2m_session_info_t *session_info)
{ {
lwm2m_buffer_t outbuf; lwm2m_buffer_t outbuf;
@ -155,31 +147,31 @@ set_rd_data(coap_message_t *request)
outbuf.len = 0; outbuf.len = 0;
/* this will also set the request payload */ /* this will also set the request payload */
rd_more = lwm2m_engine_set_rd_data(&outbuf, 0); session_info->rd_more = lwm2m_engine_set_rd_data(&outbuf, 0);
coap_set_payload(request, rd_data, outbuf.len); coap_set_payload(session_info->request, rd_data, outbuf.len);
if(rd_more) { if(session_info->rd_more) {
/* set the first block here */ /* set the first block here */
LOG_DBG("Setting block1 in request\n"); LOG_DBG("Setting block1 in request\n");
coap_set_header_block1(request, 0, 1, sizeof(rd_data)); coap_set_header_block1(session_info->request, 0, 1, sizeof(rd_data));
} }
return outbuf.len; return outbuf.len;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
prepare_update(coap_message_t *request, int triggered) prepare_update(lwm2m_session_info_t *session_info, int triggered)
{ {
coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_init_message(session_info->request, COAP_TYPE_CON, COAP_POST, 0);
coap_set_header_uri_path(request, session_info.assigned_ep); coap_set_header_uri_path(session_info->request, session_info->assigned_ep);
snprintf(query_data, sizeof(query_data) - 1, "?lt=%d&b=%s", session_info.lifetime, session_info.binding); snprintf(query_data, sizeof(query_data) - 1, "?lt=%d&b=%s", session_info->lifetime, session_info->binding);
LOG_DBG("UPDATE:%s %s\n", session_info.assigned_ep, query_data); LOG_DBG("UPDATE:%s %s\n", session_info->assigned_ep, query_data);
coap_set_header_uri_query(request, query_data); coap_set_header_uri_query(session_info->request, query_data);
if((triggered || rd_flags & FLAG_RD_DATA_UPDATE_ON_DIRTY) && (rd_flags & FLAG_RD_DATA_DIRTY)) { if((triggered || session_info->rd_flags & FLAG_RD_DATA_UPDATE_ON_DIRTY) && (session_info->rd_flags & FLAG_RD_DATA_DIRTY)) {
rd_flags &= ~FLAG_RD_DATA_DIRTY; session_info->rd_flags &= ~FLAG_RD_DATA_DIRTY;
set_rd_data(request); set_rd_data(session_info);
rd_callback = update_callback; session_info->rd_callback = update_callback;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -198,90 +190,119 @@ has_network_access(void)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int int
lwm2m_rd_client_is_registered(void) lwm2m_rd_client_is_registered(lwm2m_session_info_t *session_info)
{ {
return rd_state == REGISTRATION_DONE || rd_state == UPDATE_SENT; return session_info->rd_state == REGISTRATION_DONE || session_info->rd_state == UPDATE_SENT;
}
/*---------------------------------------------------------------------------*/
void
lwm2m_rd_client_use_bootstrap_server(int use)
{
session_info.use_bootstrap = use != 0;
if(session_info.use_bootstrap) {
rd_state = INIT;
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* will take another argument when we support multiple sessions */ /* will take another argument when we support multiple sessions */
void void
lwm2m_rd_client_set_session_callback(session_callback_t cb) lwm2m_rd_client_set_session_callback(lwm2m_session_info_t *session_info, session_callback_t cb)
{ {
session_info.callback = cb; session_info->callback = cb;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
perform_session_callback(int state) perform_session_callback(lwm2m_session_info_t *session_info, int state)
{ {
if(session_info.callback != NULL) { if(session_info->callback != NULL) {
LOG_DBG("Performing session callback: %d cb:%p\n", LOG_DBG("Performing session callback: %d cb:%p\n",
state, session_info.callback); state, session_info->callback);
session_info.callback(&session_info, state); session_info->callback(session_info, state);
}
}
/*---------------------------------------------------------------------------*/
void
lwm2m_rd_client_use_registration_server(int use)
{
session_info.use_registration = use != 0;
if(session_info.use_registration) {
rd_state = INIT;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
uint16_t uint16_t
lwm2m_rd_client_get_lifetime(void) lwm2m_rd_client_get_lifetime(lwm2m_session_info_t *session_info)
{ {
return session_info.lifetime; return session_info->lifetime;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_set_lifetime(uint16_t lifetime) lwm2m_rd_client_set_lifetime(lwm2m_session_info_t *session_info, uint16_t lifetime)
{ {
if(lifetime > 0) { if(lifetime > 0) {
session_info.lifetime = lifetime; session_info->lifetime = lifetime;
} else { } else {
session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME; session_info->lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME;
}
}
/*---------------------------------------------------------------------------*/
void
lwm2m_rd_client_set_endpoint_name(lwm2m_session_info_t *session_info, const char *endpoint)
{
if(endpoint != NULL) {
session_info->ep = endpoint;
}
}
/*---------------------------------------------------------------------------*/
void
lwm2m_rd_client_set_default_endpoint_name(const char *endpoint)
{
if(default_ep != NULL) {
strcpy(default_ep, endpoint);
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_set_update_rd(void) lwm2m_rd_client_set_update_rd(void)
{ {
rd_flags |= FLAG_RD_DATA_DIRTY; lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
session_info->rd_flags |= FLAG_RD_DATA_DIRTY;
session_info = session_info->next;
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_set_automatic_update(int update) lwm2m_rd_client_set_automatic_update(lwm2m_session_info_t *session_info, int update)
{ {
rd_flags = (rd_flags & ~FLAG_RD_DATA_UPDATE_ON_DIRTY) | session_info->rd_flags = (session_info->rd_flags & ~FLAG_RD_DATA_UPDATE_ON_DIRTY) |
(update != 0 ? FLAG_RD_DATA_UPDATE_ON_DIRTY : 0); (update != 0 ? FLAG_RD_DATA_UPDATE_ON_DIRTY : 0);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void static void
lwm2m_rd_client_register_with_server(const coap_endpoint_t *server) setup_session_default_values(lwm2m_session_info_t *session_info)
{ {
coap_endpoint_copy(&session_info.server_ep, server); if(session_info->ep == NULL) {
session_info.has_registration_server_info = 1; session_info->ep = default_ep;
session_info.registered = 0;
if(session_info.use_registration) {
rd_state = INIT;
} }
/* default binding U = UDP, UQ = UDP Q-mode*/
#if LWM2M_QUEUE_MODE_CONF_ENABLED
session_info->binding = "UQ";
/* Enough margin to ensure that the client is not unregistered (we
* do not know the time it can stay awake)
*/
session_info->lifetime = (LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2;
#else
session_info->binding = "U";
if(session_info->lifetime == 0) {
session_info->lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME;
}
#endif /* LWM2M_QUEUE_MODE_CONF_ENABLED */
session_info->rd_flags = FLAG_RD_DATA_UPDATE_ON_DIRTY;
session_info->wait_until_network_check = 0;
session_info->last_update = 0;
session_info->last_rd_progress = 0;
session_info->rd_state = INIT;
}
/*---------------------------------------------------------------------------*/
void
lwm2m_rd_client_register_with_server(lwm2m_session_info_t *session_info, const coap_endpoint_t *server)
{
list_add(session_info_list, session_info); /* Add to the list of sessions */
setup_session_default_values(session_info);
coap_endpoint_copy(&session_info->server_ep, server);
session_info->has_registration_server_info = 1;
session_info->use_server_type = USE_REGISTRATION_SERVER;
session_info->rd_state = INIT;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
update_registration_server(void) update_registration_server(lwm2m_session_info_t *session_info)
{ {
if(session_info.has_registration_server_info) { if(session_info->has_registration_server_info) {
return 1; return 1;
} }
@ -304,39 +325,54 @@ update_registration_server(void)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_register_with_bootstrap_server(const coap_endpoint_t *server) lwm2m_rd_client_register_with_bootstrap_server(lwm2m_session_info_t *session_info, const coap_endpoint_t *server)
{ {
coap_endpoint_copy(&session_info.bs_server_ep, server); list_add(session_info_list, session_info); /* Add to the list of sessions */
session_info.has_bs_server_info = 1; setup_session_default_values(session_info);
session_info.bootstrapped = 0; coap_endpoint_copy(&session_info->bs_server_ep, server);
session_info.registered = 0; session_info->has_bs_server_info = 1;
if(session_info.use_bootstrap) { session_info->use_server_type = USE_BOOTSTRAP_SERVER;
rd_state = INIT; session_info->bootstrapped = 0;
} session_info->rd_state = INIT;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
int int
lwm2m_rd_client_deregister(void) lwm2m_rd_client_deregister(lwm2m_session_info_t *session_info)
{ {
if(lwm2m_rd_client_is_registered()) { if(lwm2m_rd_client_is_registered(session_info)) {
rd_state = DEREGISTER; session_info->rd_state = DEREGISTER;
return 1; return 1;
} }
/* Not registered */ /* Not registered */
return 0; return 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void static lwm2m_session_info_t *
lwm2m_rd_client_update_triggered(void) get_sessio_info_from_server_ep(const coap_endpoint_t *server_ep)
{ {
rd_flags |= FLAG_RD_DATA_UPDATE_TRIGGERED; lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
if(coap_endpoint_cmp(&session_info->server_ep, server_ep)) {
return session_info;
}
session_info = session_info->next;
}
return NULL;
}
void
lwm2m_rd_client_update_triggered(const coap_endpoint_t *server_ep)
{
lwm2m_session_info_t *session_info = get_sessio_info_from_server_ep(server_ep);
if(session_info) {
session_info->rd_flags |= FLAG_RD_DATA_UPDATE_TRIGGERED;
}
/* Here we need to do an CoAP timer poll - to get a quick request transmission! */ /* Here we need to do an CoAP timer poll - to get a quick request transmission! */
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
update_bootstrap_server(void) update_bootstrap_server(lwm2m_session_info_t *session_info)
{ {
if(session_info.has_bs_server_info) { if(session_info->has_bs_server_info) {
return 1; return 1;
} }
@ -373,29 +409,32 @@ bootstrap_callback(coap_callback_request_state_t *callback_state)
{ {
coap_request_state_t *state = &callback_state->state; coap_request_state_t *state = &callback_state->state;
LOG_DBG("Bootstrap callback Response: %d, ", state->response != NULL); LOG_DBG("Bootstrap callback Response: %d, ", state->response != NULL);
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)state->user_data;
if(state->status == COAP_REQUEST_STATUS_RESPONSE) { if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
if(CHANGED_2_04 == state->response->code) { if(CHANGED_2_04 == state->response->code) {
LOG_DBG_("Considered done!\n"); LOG_DBG_("Considered done!\n");
rd_state = BOOTSTRAP_DONE; session_info->rd_state = BOOTSTRAP_DONE;
return; return;
} }
/* Possible error response codes are 4.00 Bad request & 4.15 Unsupported content format */ /* Possible error response codes are 4.00 Bad request & 4.15 Unsupported content format */
LOG_DBG_("Failed with code %d. Retrying\n", state->response->code); LOG_DBG_("Failed with code %d. Retrying\n", state->response->code);
/* TODO Application callback? */ /* TODO Application callback? */
rd_state = INIT; session_info->rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding! Retry?"); LOG_DBG_("Server not responding! Retry?");
rd_state = DO_BOOTSTRAP; session_info->rd_state = DO_BOOTSTRAP;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED) { } else if(state->status == COAP_REQUEST_STATUS_FINISHED) {
LOG_DBG_("Request finished. Ignore\n"); LOG_DBG_("Request finished. Ignore\n");
} else { } else {
LOG_DBG_("Unexpected error! Retry?"); LOG_DBG_("Unexpected error! Retry?");
rd_state = DO_BOOTSTRAP; session_info->rd_state = DO_BOOTSTRAP;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
produce_more_rd(void) produce_more_rd(lwm2m_session_info_t *session_info)
{ {
lwm2m_buffer_t outbuf; lwm2m_buffer_t outbuf;
@ -406,23 +445,23 @@ produce_more_rd(void)
outbuf.size = sizeof(rd_data); outbuf.size = sizeof(rd_data);
outbuf.len = 0; outbuf.len = 0;
rd_block1++; session_info->rd_block1++;
/* this will also set the request payload */ /* this will also set the request payload */
rd_more = lwm2m_engine_set_rd_data(&outbuf, rd_block1); session_info->rd_more = lwm2m_engine_set_rd_data(&outbuf, session_info->rd_block1);
coap_set_payload(request, rd_data, outbuf.len); coap_set_payload(session_info->request, rd_data, outbuf.len);
LOG_DBG("Setting block1 in request - block: %d more: %d\n", LOG_DBG("Setting block1 in request - block: %d more: %d\n",
(int)rd_block1, (int)rd_more); (int)session_info->rd_block1, (int)session_info->rd_more);
coap_set_header_block1(request, rd_block1, rd_more, sizeof(rd_data)); coap_set_header_block1(session_info->request, session_info->rd_block1, session_info->rd_more, sizeof(rd_data));
coap_send_request(&rd_request_state, &session_info.server_ep, request, rd_callback); coap_send_request(&session_info->rd_request_state, &session_info->server_ep, session_info->request, session_info->rd_callback);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
block1_rd_callback(coap_timer_t *timer) block1_rd_callback(coap_timer_t *timer)
{ {
produce_more_rd(); produce_more_rd((lwm2m_session_info_t *)timer->user_data);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* /*
@ -433,20 +472,24 @@ registration_callback(coap_callback_request_state_t *callback_state)
{ {
coap_request_state_t *state = &callback_state->state; coap_request_state_t *state = &callback_state->state;
LOG_DBG("Registration callback. Status: %d. Response: %d, ", state->status, state->response != NULL); LOG_DBG("Registration callback. Status: %d. Response: %d, ", state->status, state->response != NULL);
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)state->user_data;
if(state->status == COAP_REQUEST_STATUS_RESPONSE) { if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
/* check state and possibly set registration to done */ /* check state and possibly set registration to done */
/* If we get a continue - we need to call the rd generator one more time */ /* If we get a continue - we need to call the rd generator one more time */
if(CONTINUE_2_31 == state->response->code) { if(CONTINUE_2_31 == state->response->code) {
/* We assume that size never change?! */ /* We assume that size never change?! */
coap_get_header_block1(state->response, &rd_block1, NULL, NULL, NULL); coap_get_header_block1(state->response, &session_info->rd_block1, NULL, NULL, NULL);
coap_timer_set_callback(&block1_timer, block1_rd_callback); coap_timer_set_user_data(&session_info->block1_timer, (void *)session_info);
coap_timer_set(&block1_timer, 1); /* delay 1 ms */ coap_timer_set_callback(&session_info->block1_timer, block1_rd_callback);
coap_timer_set(&session_info->block1_timer, 1); /* delay 1 ms */
LOG_DBG_("Continue\n"); LOG_DBG_("Continue\n");
} else if(CREATED_2_01 == state->response->code) { } else if(CREATED_2_01 == state->response->code) {
if(state->response->location_path_len < LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN) { if(state->response->location_path_len < LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN) {
memcpy(session_info.assigned_ep, state->response->location_path, memcpy(session_info->assigned_ep, state->response->location_path,
state->response->location_path_len); state->response->location_path_len);
session_info.assigned_ep[state->response->location_path_len] = 0; session_info->assigned_ep[state->response->location_path_len] = 0;
/* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */ /* if we decide to not pass the lt-argument on registration, we should force an initial "update" to register lifetime with server */
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
#if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION #if LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION
@ -454,14 +497,14 @@ registration_callback(coap_callback_request_state_t *callback_state)
lwm2m_queue_mode_set_first_request(); lwm2m_queue_mode_set_first_request();
} }
#endif #endif
lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ lwm2m_rd_client_fsm_execute_queue_mode_awake(session_info); /* Avoid 500 ms delay and move directly to the state*/
#else #else
rd_state = REGISTRATION_DONE; session_info->rd_state = REGISTRATION_DONE;
#endif #endif
/* remember the last reg time */ /* remember the last reg time */
last_update = coap_timer_uptime(); session_info->last_update = coap_timer_uptime();
LOG_DBG_("Done (assigned EP='%s')!\n", session_info.assigned_ep); LOG_DBG_("Done (assigned EP='%s')!\n", session_info->assigned_ep);
perform_session_callback(LWM2M_RD_CLIENT_REGISTERED); perform_session_callback(session_info, LWM2M_RD_CLIENT_REGISTERED);
return; return;
} }
@ -474,15 +517,15 @@ registration_callback(coap_callback_request_state_t *callback_state)
LOG_DBG_("failed with code %d. Re-init network\n", state->response->code); LOG_DBG_("failed with code %d. Re-init network\n", state->response->code);
} }
/* TODO Application callback? */ /* TODO Application callback? */
rd_state = INIT; session_info->rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding, trying to reconnect\n"); LOG_DBG_("Server not responding, trying to reconnect\n");
rd_state = INIT; session_info->rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED) { } else if(state->status == COAP_REQUEST_STATUS_FINISHED) {
LOG_DBG_("Request finished. Ignore\n"); LOG_DBG_("Request finished. Ignore\n");
} else { } else {
LOG_DBG_("Unexpected error, trying to reconnect\n"); LOG_DBG_("Unexpected error, trying to reconnect\n");
rd_state = INIT; session_info->rd_state = INIT;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -495,18 +538,20 @@ update_callback(coap_callback_request_state_t *callback_state)
coap_request_state_t *state = &callback_state->state; coap_request_state_t *state = &callback_state->state;
LOG_DBG("Update callback. Status: %d. Response: %d, ", state->status, state->response != NULL); LOG_DBG("Update callback. Status: %d. Response: %d, ", state->status, state->response != NULL);
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)state->user_data;
if(state->status == COAP_REQUEST_STATUS_RESPONSE) { if(state->status == COAP_REQUEST_STATUS_RESPONSE) {
/* If we get a continue - we need to call the rd generator one more time */ /* If we get a continue - we need to call the rd generator one more time */
if(CONTINUE_2_31 == state->response->code) { if(CONTINUE_2_31 == state->response->code) {
/* We assume that size never change?! */ /* We assume that size never change?! */
LOG_DBG_("Continue\n"); LOG_DBG_("Continue\n");
coap_get_header_block1(state->response, &rd_block1, NULL, NULL, NULL); coap_get_header_block1(state->response, &session_info->rd_block1, NULL, NULL, NULL);
coap_timer_set_callback(&block1_timer, block1_rd_callback); coap_timer_set_callback(&session_info->block1_timer, block1_rd_callback);
coap_timer_set(&block1_timer, 1); /* delay 1 ms */ coap_timer_set(&session_info->block1_timer, 1); /* delay 1 ms */
} else if(CHANGED_2_04 == state->response->code) { } else if(CHANGED_2_04 == state->response->code) {
LOG_DBG_("Done!\n"); LOG_DBG_("Done!\n");
/* remember the last reg time */ /* remember the last reg time */
last_update = coap_timer_uptime(); session_info->last_update = coap_timer_uptime();
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
/* If it has been waked up by a notification, send the stored notifications in queue */ /* If it has been waked up by a notification, send the stored notifications in queue */
if(lwm2m_queue_mode_is_waked_up_by_notification()) { if(lwm2m_queue_mode_is_waked_up_by_notification()) {
@ -519,25 +564,26 @@ update_callback(coap_callback_request_state_t *callback_state)
lwm2m_queue_mode_set_first_request(); lwm2m_queue_mode_set_first_request();
} }
#endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */ #endif /* LWM2M_QUEUE_MODE_INCLUDE_DYNAMIC_ADAPTATION */
lwm2m_rd_client_fsm_execute_queue_mode_awake(); /* Avoid 500 ms delay and move directly to the state*/ lwm2m_rd_client_fsm_execute_queue_mode_awake(session_info); /* Avoid 500 ms delay and move directly to the state*/
#else #else
rd_state = REGISTRATION_DONE;
rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED; session_info->rd_state = REGISTRATION_DONE;
#endif /* LWM2M_QUEUE_MODE_ENABLED */ session_info->rd_flags &= ~FLAG_RD_DATA_UPDATE_TRIGGERED;
#endif /* LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME */
} else { } else {
/* Possible error response codes are 4.00 Bad request & 4.04 Not Found */ /* Possible error response codes are 4.00 Bad request & 4.04 Not Found */
LOG_DBG_("Failed with code %d. Retrying registration\n", LOG_DBG_("Failed with code %d. Retrying registration\n",
state->response->code); state->response->code);
rd_state = DO_REGISTRATION; session_info->rd_state = DO_REGISTRATION;
} }
} else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) { } else if(state->status == COAP_REQUEST_STATUS_TIMEOUT) {
LOG_DBG_("Server not responding, trying to reconnect\n"); LOG_DBG_("Server not responding, trying to reconnect\n");
rd_state = INIT; session_info->rd_state = INIT;
} else if(state->status == COAP_REQUEST_STATUS_FINISHED) { } else if(state->status == COAP_REQUEST_STATUS_FINISHED) {
LOG_DBG_("Request finished. Ignore\n"); LOG_DBG_("Request finished. Ignore\n");
} else { } else {
LOG_DBG_("Unexpected error, trying to reconnect\n"); LOG_DBG_("Unexpected error, trying to reconnect\n");
rd_state = INIT; session_info->rd_state = INIT;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -549,19 +595,49 @@ deregister_callback(coap_callback_request_state_t *callback_state)
state->status, state->status,
state->response != NULL ? state->response->code : 0); state->response != NULL ? state->response->code : 0);
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)state->user_data;
if(state->status == COAP_REQUEST_STATUS_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"); LOG_DBG("Deregistration success\n");
rd_state = DEREGISTERED; session_info->rd_state = DEREGISTERED;
perform_session_callback(LWM2M_RD_CLIENT_DEREGISTERED); perform_session_callback(session_info, LWM2M_RD_CLIENT_DEREGISTERED);
} else { } else {
LOG_DBG("Deregistration failed\n"); LOG_DBG("Deregistration failed\n");
if(rd_state == DEREGISTER_SENT) { if(session_info->rd_state == DEREGISTER_SENT) {
rd_state = DEREGISTER_FAILED; session_info->rd_state = DEREGISTER_FAILED;
perform_session_callback(LWM2M_RD_CLIENT_DEREGISTER_FAILED); perform_session_callback(session_info, LWM2M_RD_CLIENT_DEREGISTER_FAILED);
} }
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if LWM2M_QUEUE_MODE_ENABLED
static int
all_sessions_in_queue_mode_state(void)
{
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
if(((session_info->rd_state & 0xF) != 0xE)) {
return 0;
}
session_info = session_info->next;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int
all_sessions_in_queue_mode_awake(void)
{
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
if(session_info->rd_state != QUEUE_MODE_AWAKE) {
return 0;
}
session_info = session_info->next;
}
return 1;
}
#endif /* LWM2M_QUEUE_MODE_ENABLED */
/*---------------------------------------------------------------------------*/
/* CoAP timer callback */ /* CoAP timer callback */
static void static void
periodic_process(coap_timer_t *timer) periodic_process(coap_timer_t *timer)
@ -571,7 +647,7 @@ periodic_process(coap_timer_t *timer)
/* reschedule the CoAP timer */ /* reschedule the CoAP timer */
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
/* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */ /* In Queue Mode, the machine is not executed periodically, but with the awake/sleeping times */
if(!((rd_state & 0xF) == 0xE)) { if(!all_sessions_in_queue_mode_state()) {
coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL); coap_timer_reset(&rd_timer, STATE_MACHINE_UPDATE_INTERVAL);
} }
#else #else
@ -580,47 +656,52 @@ periodic_process(coap_timer_t *timer)
now = coap_timer_uptime(); now = coap_timer_uptime();
LOG_DBG("RD Client - state: %d, ms: %lu\n", rd_state, lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
LOG_DBG("RD Client with assigned ep: %s - state: %d, ms: %lu\n", session_info->assigned_ep, session_info->rd_state,
(unsigned long)coap_timer_uptime()); (unsigned long)coap_timer_uptime());
switch(rd_state) { switch(session_info->rd_state) {
case INIT: case INIT:
LOG_DBG("RD Client started with endpoint '%s' and client lifetime %d\n", session_info.ep, session_info.lifetime); LOG_DBG("RD Client started with endpoint '%s' and client lifetime %d\n", session_info->ep, session_info->lifetime);
rd_state = WAIT_NETWORK; session_info->rd_state = WAIT_NETWORK;
break; break;
case WAIT_NETWORK: case WAIT_NETWORK:
if(now > wait_until_network_check) { if(now > session_info->wait_until_network_check) {
/* check each 10 seconds before next check */ /* check each 10 seconds before next check */
LOG_DBG("Checking for network... %lu\n", LOG_DBG("Checking for network... %lu\n",
(unsigned long)wait_until_network_check); (unsigned long)session_info->wait_until_network_check);
wait_until_network_check = now + 10000; session_info->wait_until_network_check = now + 10000;
if(has_network_access()) { if(has_network_access()) {
/* Either do bootstrap then registration */ /* Either do bootstrap then registration */
if(session_info.use_bootstrap) { if(session_info->use_server_type == USE_BOOTSTRAP_SERVER) {
rd_state = DO_BOOTSTRAP; session_info->rd_state = DO_BOOTSTRAP;
} else { } else {
rd_state = DO_REGISTRATION; session_info->rd_state = DO_REGISTRATION;
} }
} }
/* Otherwise wait until for a network to join */ /* Otherwise wait until for a network to join */
} }
break; break;
case DO_BOOTSTRAP: case DO_BOOTSTRAP:
if(session_info.use_bootstrap && session_info.bootstrapped == 0) { if(session_info->use_server_type == USE_BOOTSTRAP_SERVER && session_info->bootstrapped == 0) {
if(update_bootstrap_server()) { if(update_bootstrap_server(session_info)) {
/* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */
coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_init_message(session_info->request, COAP_TYPE_CON, COAP_POST, 0);
coap_set_header_uri_path(request, "/bs"); coap_set_header_uri_path(session_info->request, "/bs");
snprintf(query_data, sizeof(query_data) - 1, "?ep=%s", session_info.ep); snprintf(query_data, sizeof(query_data) - 1, "?ep=%s", session_info->ep);
coap_set_header_uri_query(request, query_data); coap_set_header_uri_query(session_info->request, query_data);
LOG_INFO("Registering ID with bootstrap server ["); LOG_INFO("Registering ID with bootstrap server [");
LOG_INFO_COAP_EP(&session_info.bs_server_ep); LOG_INFO_COAP_EP(&session_info->bs_server_ep);
LOG_INFO_("] as '%s'\n", query_data); LOG_INFO_("] as '%s'\n", query_data);
/* Add session info as user data to use it in the callbacks */
if(coap_send_request(&rd_request_state, &session_info.bs_server_ep, session_info->rd_request_state.state.user_data = (void *)session_info;
request, bootstrap_callback)) { if(coap_send_request(&session_info->rd_request_state, &session_info->bs_server_ep,
rd_state = BOOTSTRAP_SENT; session_info->request, bootstrap_callback)) {
session_info->rd_state = BOOTSTRAP_SENT;
} }
} }
} }
@ -630,7 +711,7 @@ periodic_process(coap_timer_t *timer)
break; break;
case BOOTSTRAP_DONE: case BOOTSTRAP_DONE:
/* check that we should still use bootstrap */ /* check that we should still use bootstrap */
if(session_info.use_bootstrap) { if(session_info->use_server_type == USE_BOOTSTRAP_SERVER) {
lwm2m_security_server_t *security; lwm2m_security_server_t *security;
LOG_DBG("*** Bootstrap - checking for server info...\n"); LOG_DBG("*** Bootstrap - checking for server info...\n");
/* get the security object - ignore bootstrap servers */ /* get the security object - ignore bootstrap servers */
@ -658,17 +739,17 @@ periodic_process(coap_timer_t *timer)
if(!coap_endpoint_parse((const char *)security->server_uri, if(!coap_endpoint_parse((const char *)security->server_uri,
security->server_uri_len, security->server_uri_len,
&session_info.server_ep)) { &session_info->server_ep)) {
LOG_DBG("Failed to parse server URI!\n"); LOG_DBG("Failed to parse server URI!\n");
} else { } else {
LOG_DBG("Server address:"); LOG_DBG("Server address:");
LOG_DBG_COAP_EP(&session_info.server_ep); LOG_DBG_COAP_EP(&session_info->server_ep);
LOG_DBG_("\n"); LOG_DBG_("\n");
if(secure) { if(secure) {
LOG_DBG("Secure CoAP requested but not supported - can not bootstrap\n"); LOG_DBG("Secure CoAP requested but not supported - can not bootstrap\n");
} else { } else {
lwm2m_rd_client_register_with_server(&session_info.server_ep); lwm2m_rd_client_register_with_server(session_info, &session_info->server_ep);
session_info.bootstrapped++; session_info->bootstrapped++;
} }
} }
} else { } else {
@ -680,47 +761,52 @@ periodic_process(coap_timer_t *timer)
} }
/* if we did not register above - then fail this and restart... */ /* if we did not register above - then fail this and restart... */
if(session_info.bootstrapped == 0) { if(session_info->bootstrapped == 0) {
/* Not ready. Lets retry with the bootstrap server again */ /* Not ready. Lets retry with the bootstrap server again */
rd_state = DO_BOOTSTRAP; session_info->rd_state = DO_BOOTSTRAP;
} else { } else {
rd_state = DO_REGISTRATION; session_info->rd_state = DO_REGISTRATION;
} }
} }
break; break;
case DO_REGISTRATION: case DO_REGISTRATION:
if(!coap_endpoint_is_connected(&session_info.server_ep)) { if(!coap_endpoint_is_connected(&session_info->server_ep)) {
/* Not connected... wait a bit... and retry connection */ /* Not connected... wait a bit... and retry connection */
coap_endpoint_connect(&session_info.server_ep); coap_endpoint_connect(&session_info->server_ep);
LOG_DBG("Wait until connected... \n"); LOG_DBG("Wait until connected... \n");
return; return;
} }
if(session_info.use_registration && !session_info.registered &&
update_registration_server()) { if(session_info->use_server_type == USE_REGISTRATION_SERVER && !lwm2m_rd_client_is_registered(session_info) &&
update_registration_server(session_info)) {
int len; int len;
/* prepare request, TID was set by COAP_BLOCKING_REQUEST() */ /* prepare request, TID was set by COAP_BLOCKING_REQUEST() */
coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_init_message(session_info->request, COAP_TYPE_CON, COAP_POST, 0);
coap_set_header_uri_path(request, "/rd"); coap_set_header_uri_path(session_info->request, "/rd");
snprintf(query_data, sizeof(query_data) - 1, "?ep=%s&lt=%d&b=%s", session_info.ep, session_info.lifetime, session_info.binding); snprintf(query_data, sizeof(query_data) - 1, "?ep=%s&lt=%d&b=%s", session_info->ep, session_info->lifetime, session_info->binding);
coap_set_header_uri_query(request, query_data); coap_set_header_uri_query(session_info->request, query_data);
len = set_rd_data(request); len = set_rd_data(session_info);
rd_callback = registration_callback; session_info->rd_callback = registration_callback;
LOG_INFO("Registering with ["); LOG_INFO("Registering with [");
LOG_INFO_COAP_EP(&session_info.server_ep); LOG_INFO_COAP_EP(&session_info->server_ep);
LOG_INFO_("] lwm2m endpoint '%s': '", query_data); LOG_INFO_("] lwm2m endpoint '%s': '", query_data);
if(len) { if(len) {
LOG_INFO_COAP_STRING((const char *)rd_data, len); LOG_INFO_COAP_STRING((const char *)rd_data, len);
} }
LOG_INFO_("' More:%d\n", rd_more); LOG_INFO_("' More:%d\n", session_info->rd_more);
if(coap_send_request(&rd_request_state, &session_info.server_ep, /* Add session info as user data to use it in the callbacks */
request, registration_callback)){ session_info->rd_request_state.state.user_data = (void *)session_info;
rd_state = REGISTRATION_SENT; if(coap_send_request(&session_info->rd_request_state, &session_info->server_ep,
session_info->request, registration_callback)) {
session_info->rd_state = REGISTRATION_SENT;
} }
session_info->last_rd_progress = coap_timer_uptime();
} }
break; break;
case REGISTRATION_SENT: case REGISTRATION_SENT:
@ -732,22 +818,28 @@ periodic_process(coap_timer_t *timer)
check_periodic_observations(); /* TODO: manage periodic observations */ check_periodic_observations(); /* TODO: manage periodic observations */
/* check if it is time for the next update */ /* check if it is time for the next update */
if((rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED) || if((session_info->rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED) ||
((uint32_t)session_info.lifetime * 500) <= now - last_update) { ((uint32_t)session_info->lifetime * 500) <= now - session_info->last_update) {
/* triggered or time to send an update to the server, at half-time! sec vs ms */ /* 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); prepare_update(session_info, session_info->rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
if(coap_send_request(&rd_request_state, &session_info.server_ep, request,
/* Add session info as user data to use it in the callbacks */
session_info->rd_request_state.state.user_data = (void *)session_info;
if(coap_send_request(&session_info->rd_request_state, &session_info->server_ep, session_info->request,
update_callback)) { update_callback)) {
rd_state = UPDATE_SENT; session_info->rd_state = UPDATE_SENT;
} }
session_info->last_rd_progress = coap_timer_uptime();
} }
break; break;
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
case QUEUE_MODE_AWAKE: case QUEUE_MODE_AWAKE:
LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime()); LOG_DBG("Queue Mode: Client is AWAKE at %lu\n", (unsigned long)coap_timer_uptime());
queue_mode_client_awake = 1; if((queue_mode_client_awake = all_sessions_in_queue_mode_awake())) {
queue_mode_client_awake_time = lwm2m_queue_mode_get_awake_time(); queue_mode_client_awake_time = lwm2m_queue_mode_get_awake_time();
coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time); coap_timer_set(&queue_mode_client_awake_timer, queue_mode_client_awake_time);
}
break; break;
case QUEUE_MODE_SEND_UPDATE: case QUEUE_MODE_SEND_UPDATE:
/* Define this macro to make the necessary actions for waking up, /* Define this macro to make the necessary actions for waking up,
@ -756,11 +848,14 @@ periodic_process(coap_timer_t *timer)
#ifdef LWM2M_QUEUE_MODE_WAKE_UP #ifdef LWM2M_QUEUE_MODE_WAKE_UP
LWM2M_QUEUE_MODE_WAKE_UP(); LWM2M_QUEUE_MODE_WAKE_UP();
#endif /* LWM2M_QUEUE_MODE_WAKE_UP */ #endif /* LWM2M_QUEUE_MODE_WAKE_UP */
prepare_update(request, rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED); prepare_update(session_info, session_info->rd_flags & FLAG_RD_DATA_UPDATE_TRIGGERED);
if(coap_send_request(&rd_request_state, &session_info.server_ep, request, /* Add session info as user data to use it in the callbacks */
session_info->rd_request_state.state.user_data = (void *)session_info;
if(coap_send_request(&session_info->rd_request_state, &session_info->server_ep, session_info->request,
update_callback)) { update_callback)) {
rd_state = UPDATE_SENT; session_info->rd_state = UPDATE_SENT;
} }
session_info->last_rd_progress = coap_timer_uptime();
break; break;
#endif /* LWM2M_QUEUE_MODE_ENABLED */ #endif /* LWM2M_QUEUE_MODE_ENABLED */
@ -768,12 +863,15 @@ periodic_process(coap_timer_t *timer)
/* just wait until the callback kicks us to the next state... */ /* just wait until the callback kicks us to the next state... */
break; break;
case DEREGISTER: case DEREGISTER:
LOG_INFO("DEREGISTER %s\n", session_info.assigned_ep); LOG_INFO("DEREGISTER %s\n", session_info->assigned_ep);
coap_init_message(request, COAP_TYPE_CON, COAP_DELETE, 0); coap_init_message(session_info->request, COAP_TYPE_CON, COAP_DELETE, 0);
coap_set_header_uri_path(request, session_info.assigned_ep); coap_set_header_uri_path(session_info->request, session_info->assigned_ep);
if(coap_send_request(&rd_request_state, &session_info.server_ep, request,
/* Add session info as user data to use it in the callbacks */
session_info->rd_request_state.state.user_data = (void *)session_info;
if(coap_send_request(&session_info->rd_request_state, &session_info->server_ep, session_info->request,
deregister_callback)) { deregister_callback)) {
rd_state = DEREGISTER_SENT; session_info->rd_state = DEREGISTER_SENT;
} }
break; break;
case DEREGISTER_SENT: case DEREGISTER_SENT:
@ -784,29 +882,16 @@ periodic_process(coap_timer_t *timer)
break; break;
default: default:
LOG_WARN("Unhandled state: %d\n", rd_state); LOG_WARN("Unhandled state: %d\n", session_info->rd_state);
}
session_info = session_info->next;
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_init(const char *ep) lwm2m_rd_client_init(const char *ep)
{ {
session_info.ep = ep; strcpy(default_ep, ep);
/* default binding U = UDP, UQ = UDP Q-mode*/
#if LWM2M_QUEUE_MODE_ENABLED
session_info.binding = "UQ";
/* Enough margin to ensure that the client is not unregistered (we
* do not know the time it can stay awake)
*/
session_info.lifetime = (LWM2M_QUEUE_MODE_DEFAULT_CLIENT_SLEEP_TIME / 1000) * 2;
#else
session_info.binding = "U";
if(session_info.lifetime == 0) {
session_info.lifetime = LWM2M_DEFAULT_CLIENT_LIFETIME;
}
#endif
rd_state = INIT;
/* call the RD client periodically */ /* call the RD client periodically */
coap_timer_set_callback(&rd_timer, periodic_process); coap_timer_set_callback(&rd_timer, periodic_process);
@ -846,27 +931,31 @@ queue_mode_awake_timer_callback(coap_timer_t *timer)
LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime()); LOG_DBG("Queue Mode: Client is SLEEPING at %lu\n", (unsigned long)coap_timer_uptime());
queue_mode_client_awake = 0; queue_mode_client_awake = 0;
lwm2m_session_info_t *session_info = (lwm2m_session_info_t *)list_head(session_info_list);
while(session_info != NULL) {
session_info->rd_state = QUEUE_MODE_SEND_UPDATE;
session_info = session_info->next;
}
coap_timer_set(&rd_timer, lwm2m_queue_mode_get_sleep_time());
/* Define this macro to enter sleep mode depending on the platform */ /* Define this macro to enter sleep mode depending on the platform */
#ifdef LWM2M_QUEUE_MODE_SLEEP_MS #ifdef LWM2M_QUEUE_MODE_SLEEP_MS
LWM2M_QUEUE_MODE_SLEEP_MS(lwm2m_queue_mode_get_sleep_time()); LWM2M_QUEUE_MODE_SLEEP_MS(lwm2m_queue_mode_get_sleep_time());
#endif /* LWM2M_QUEUE_MODE_SLEEP_MS */ #endif /* LWM2M_QUEUE_MODE_SLEEP_MS */
rd_state = QUEUE_MODE_SEND_UPDATE;
coap_timer_set(&rd_timer, lwm2m_queue_mode_get_sleep_time());
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_fsm_execute_queue_mode_awake() lwm2m_rd_client_fsm_execute_queue_mode_awake(lwm2m_session_info_t *session_info)
{ {
coap_timer_stop(&rd_timer); coap_timer_stop(&rd_timer);
rd_state = QUEUE_MODE_AWAKE; session_info->rd_state = QUEUE_MODE_AWAKE;
periodic_process(&rd_timer); periodic_process(&rd_timer);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
lwm2m_rd_client_fsm_execute_queue_mode_update() lwm2m_rd_client_fsm_execute_queue_mode_update(lwm2m_session_info_t *session_info)
{ {
coap_timer_stop(&rd_timer); coap_timer_stop(&rd_timer);
rd_state = QUEUE_MODE_SEND_UPDATE; session_info->rd_state = QUEUE_MODE_SEND_UPDATE;
periodic_process(&rd_timer); periodic_process(&rd_timer);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -54,28 +54,71 @@
#include "lwm2m-object.h" #include "lwm2m-object.h"
#include "lwm2m-queue-mode-conf.h" #include "lwm2m-queue-mode-conf.h"
#include "coap-endpoint.h"
#include "coap-callback-api.h"
struct lwm2m_session_info; struct lwm2m_session_info;
typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status); typedef void (*session_callback_t)(struct lwm2m_session_info *session, int status);
int lwm2m_rd_client_is_registered(void); #ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN
void lwm2m_rd_client_use_bootstrap_server(int use); #define LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN 15
void lwm2m_rd_client_use_registration_server(int use); #endif /* LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN */
void lwm2m_rd_client_register_with_server(const coap_endpoint_t *server); /*---------------------------------------------------------------------------*/
void lwm2m_rd_client_register_with_bootstrap_server(const coap_endpoint_t *server); /*- Server session----------------------------*/
uint16_t lwm2m_rd_client_get_lifetime(void); /*---------------------------------------------------------------------------*/
void lwm2m_rd_client_set_lifetime(uint16_t lifetime); typedef struct lwm2m_session_info {
struct lwm2m_session_info *next;
/* Information */
const char *ep;
const char *binding;
char assigned_ep[LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN];
uint16_t lifetime;
coap_endpoint_t bs_server_ep;
coap_endpoint_t server_ep;
uint8_t use_server_type;
uint8_t has_bs_server_info;
uint8_t has_registration_server_info;
uint8_t bootstrapped; /* bootstrap done */
session_callback_t callback;
/* CoAP Request */
coap_callback_request_state_t rd_request_state;
coap_message_t request[1]; /* This way the message can be treated as pointer as usual. */
/* RD parameters */
uint8_t rd_state;
uint8_t rd_flags;
uint64_t wait_until_network_check;
uint64_t last_update;
uint64_t last_rd_progress;
/* Blosk Transfer */
uint32_t rd_block1;
uint8_t rd_more;
void (*rd_callback)(coap_callback_request_state_t *state);
coap_timer_t block1_timer;
} lwm2m_session_info_t;
int lwm2m_rd_client_is_registered(lwm2m_session_info_t *session_info);
void lwm2m_rd_client_register_with_server(lwm2m_session_info_t *session_info, const coap_endpoint_t *server);
void lwm2m_rd_client_register_with_bootstrap_server(lwm2m_session_info_t *session_info, const coap_endpoint_t *server);
uint16_t lwm2m_rd_client_get_lifetime(lwm2m_session_info_t *session_info);
void lwm2m_rd_client_set_lifetime(lwm2m_session_info_t *session_info, uint16_t lifetime);
void lwm2m_rd_client_set_endpoint_name(lwm2m_session_info_t *session_info, const char *endpoint);
void lwm2m_rd_client_set_default_endpoint_name(const char *endpoint);
/* Indicate that something in the object list have changed */ /* Indicate that something in the object list have changed */
void lwm2m_rd_client_set_update_rd(void); void lwm2m_rd_client_set_update_rd(void);
/* Control if the object list should be automatically updated at updates of lifetime */ /* Control if the object list should be automatically updated at updates of lifetime */
void lwm2m_rd_client_set_automatic_update(int update); void lwm2m_rd_client_set_automatic_update(lwm2m_session_info_t *session_info, int update);
/* trigger an immediate update */ /* trigger an immediate update */
void lwm2m_rd_client_update_triggered(void); void lwm2m_rd_client_update_triggered(const coap_endpoint_t *server_ep);
int lwm2m_rd_client_deregister(void); int lwm2m_rd_client_deregister(lwm2m_session_info_t *session_info);
void lwm2m_rd_client_init(const char *ep); void lwm2m_rd_client_init(const char *ep);
void lwm2m_rd_client_set_session_callback(session_callback_t cb); void lwm2m_rd_client_set_session_callback(lwm2m_session_info_t *session_info, session_callback_t cb);
#if LWM2M_QUEUE_MODE_ENABLED #if LWM2M_QUEUE_MODE_ENABLED
uint8_t lwm2m_rd_client_is_client_awake(void); uint8_t lwm2m_rd_client_is_client_awake(void);
@ -84,28 +127,5 @@ void lwm2m_rd_client_fsm_execute_queue_mode_awake();
void lwm2m_rd_client_fsm_execute_queue_mode_update(); void lwm2m_rd_client_fsm_execute_queue_mode_update();
#endif #endif
#ifndef LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN
#define LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN 15
#endif /* LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN */
/*---------------------------------------------------------------------------*/
/*- Server session-*Currently single session only*---------------------------*/
/*---------------------------------------------------------------------------*/
struct lwm2m_session_info {
const char *ep;
const char *binding;
char assigned_ep[LWM2M_RD_CLIENT_ASSIGNED_ENDPOINT_MAX_LEN];
uint16_t lifetime;
coap_endpoint_t bs_server_ep;
coap_endpoint_t server_ep;
uint8_t use_bootstrap;
uint8_t has_bs_server_info;
uint8_t use_registration;
uint8_t has_registration_server_info;
uint8_t registered;
uint8_t bootstrapped; /* bootstrap done */
session_callback_t callback;
};
#endif /* LWM2M_RD_CLIENT_H_ */ #endif /* LWM2M_RD_CLIENT_H_ */
/** @} */ /** @} */

View File

@ -221,7 +221,7 @@ lwm2m_callback(lwm2m_object_instance_t *object,
} else if(ctx->operation == LWM2M_OP_EXECUTE) { } else if(ctx->operation == LWM2M_OP_EXECUTE) {
switch(ctx->resource_id) { switch(ctx->resource_id) {
case LWM2M_SERVER_REG_UPDATE_TRIGGER_ID: case LWM2M_SERVER_REG_UPDATE_TRIGGER_ID:
lwm2m_rd_client_update_triggered(); lwm2m_rd_client_update_triggered(ctx->request->src_ep);
break; break;
} }
} else { } else {