Skip to content

Commit

Permalink
Anjay 3.8.0
Browse files Browse the repository at this point in the history
BREAKING CHANGES:
- Timeout in case of sending a Confirmable Notification does not cancel the
  observation anymore by default.

Features:
- Added a ``connection_error_is_registration_failure`` configuration option that
  allows handling connection errors as Register failures, including the
  automatic retry mechanism
- Added experimental server connection status API.

Improvements:
- (commercial version only) Changed MSISDN matching method in SMS binding
  feature to allow handling messages with Short Codes as originating number

Bugfixes:
- Fixed a corner case in which a connection error during a non-first Register
  attempt could cause uncontrolled infinite retries
- Fixed a bug in demo of Advanced Firmware Update module that prevented
  proper handling of security config for targets other than APP
- Fixed a bug that caused anjay_next_planned_notify_trigger family APIs to
  return an invalid value after canceling observations
  • Loading branch information
Kucmasz committed May 28, 2024
1 parent fc26744 commit 3ba32ac
Show file tree
Hide file tree
Showing 59 changed files with 1,223 additions and 206 deletions.
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Changelog

## 3.8.0 (May 28th, 2024)

### BREAKING CHANGES

- Timeout in case of sending a Confirmable Notification does not cancel the
observation anymore by default.

### Features

- Added a ``connection_error_is_registration_failure`` configuration option that
allows handling connection errors as Register failures, including the
automatic retry mechanism
- Added experimental server connection status API.

### Improvements

- (commercial version only) Changed MSISDN matching method in SMS binding
feature to allow handling messages with Short Codes as originating number

### Bugfixes

- Fixed a corner case in which a connection error during a non-first Register
attempt could cause uncontrolled infinite retries
- Fixed a bug in demo of Advanced Firmware Update module that prevented
proper handling of security config for targets other than APP
- Fixed a bug that caused anjay_next_planned_notify_trigger family APIs to
return an invalid value after canceling observations

## 3.7.0 (February 16th, 2024)

### Features
Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
cmake_minimum_required(VERSION 3.6.0)

project(anjay C)
set(ANJAY_VERSION "3.7.0" CACHE STRING "Anjay library version")
set(ANJAY_VERSION "3.8.0" CACHE STRING "Anjay library version")
set(ANJAY_BINARY_VERSION 1.0.0)

set(ANJAY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
Expand Down Expand Up @@ -210,6 +210,7 @@ else()
endif()

option(WITH_AVS_COAP_TCP "Enable CoAP over TCP support" "${WITH_LWM2M11}")
option(WITH_CONN_STATUS_API "Enable support for the experimental anjay_get_server_connection_status() API and related callback." ON)



Expand Down Expand Up @@ -557,6 +558,7 @@ set(ANJAY_WITH_SECURITY_STRUCTURED "${WITH_SECURITY_STRUCTURED}")
set(ANJAY_WITH_SEND "${WITH_SEND}")
set(ANJAY_WITH_SENML_JSON "${WITH_SENML_JSON}")
set(ANJAY_WITHOUT_QUEUE_MODE_AUTOCLOSE "${WITHOUT_QUEUE_MODE_AUTOCLOSE}")
set(ANJAY_WITH_CONN_STATUS_API "${WITH_CONN_STATUS_API}")

configure_file(include_public/anjay/anjay_config.h.in
include_public/anjay/anjay_config.h)
Expand Down
16 changes: 15 additions & 1 deletion demo/advanced_firmware_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ int advanced_firmware_update_install(
(int) state.result);
result = advanced_firmware_update_additional_image_install(
anjay, fw_logic_add_inst->iid, fw_table, &state,
ADD_IMG_NAMES[i]);
security_info, ADD_IMG_NAMES[i]);

if (result) {
demo_log(ERROR, "AFU instance %u install failed",
Expand Down Expand Up @@ -1261,3 +1261,17 @@ void advanced_firmware_update_uninstall(advanced_fw_update_logic_t *fw_table) {
afu_logic_destroy(&fw_table[i]);
}
}

int advanced_firmware_update_get_security_config(
anjay_iid_t iid,
void *fw_,
anjay_security_config_t *out_security_config,
const char *download_uri) {
(void) iid;
advanced_fw_update_logic_t *fw_table = (advanced_fw_update_logic_t *) fw_;
advanced_fw_update_logic_t *fw = &fw_table[FW_UPDATE_IID_APP];
(void) download_uri;
memset(out_security_config, 0, sizeof(*out_security_config));
out_security_config->security_info = fw->security_info;
return 0;
}
7 changes: 7 additions & 0 deletions demo/advanced_firmware_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ int advanced_firmware_update_additional_image_install(
anjay_iid_t iid,
advanced_fw_update_logic_t *fw_table,
anjay_advanced_fw_update_initial_state_t *init_state,
const avs_net_security_info_t *security_info,
const char *component_name);

const char *
Expand Down Expand Up @@ -143,6 +144,12 @@ int fw_update_common_perform_upgrade(
size_t requested_supplemental_iids_count);
int fw_update_common_maybe_create_firmware_file(advanced_fw_update_logic_t *fw);

int advanced_firmware_update_get_security_config(
anjay_iid_t iid,
void *fw_,
anjay_security_config_t *out_security_config,
const char *download_uri);

typedef struct {
anjay_advanced_fw_update_state_t inst_states[FW_UPDATE_IID_IMAGE_SLOTS];
anjay_advanced_fw_update_result_t inst_results[FW_UPDATE_IID_IMAGE_SLOTS];
Expand Down
11 changes: 10 additions & 1 deletion demo/advanced_firmware_update_addimg.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static int update(advanced_fw_update_logic_t *fw) {
return 0;
}

static const anjay_advanced_fw_update_handlers_t handlers = {
static anjay_advanced_fw_update_handlers_t handlers = {
.stream_open = fw_stream_open,
.stream_write = fw_update_common_write,
.stream_finish = fw_update_common_finish,
Expand All @@ -107,10 +107,19 @@ int advanced_firmware_update_additional_image_install(
anjay_iid_t iid,
advanced_fw_update_logic_t *fw_table,
anjay_advanced_fw_update_initial_state_t *init_state,
const avs_net_security_info_t *security_info,
const char *component_name) {
advanced_fw_update_logic_t *fw_logic = &fw_table[iid];
memcpy(fw_logic->current_ver, VER_DEFAULT, sizeof(VER_DEFAULT));
fw_global = fw_logic;
if (security_info) {
memcpy(&fw_logic->security_info, security_info,
sizeof(fw_logic->security_info));
handlers.get_security_config =
advanced_firmware_update_get_security_config;
} else {
handlers.get_security_config = NULL;
}
int result =
anjay_advanced_fw_update_instance_add(anjay, fw_logic->iid,
component_name, &handlers,
Expand Down
16 changes: 2 additions & 14 deletions demo/advanced_firmware_update_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,6 @@ static anjay_advanced_fw_update_handlers_t handlers = {
.perform_upgrade = fw_update_common_perform_upgrade
};

static int fw_get_security_config(anjay_iid_t iid,
void *fw_,
anjay_security_config_t *out_security_config,
const char *download_uri) {
(void) iid;
advanced_fw_update_logic_t *fw_table = (advanced_fw_update_logic_t *) fw_;
advanced_fw_update_logic_t *fw = &fw_table[FW_UPDATE_IID_APP];
(void) download_uri;
memset(out_security_config, 0, sizeof(*out_security_config));
out_security_config->security_info = fw->security_info;
return 0;
}

int advanced_firmware_update_application_install(
anjay_t *anjay,
advanced_fw_update_logic_t *fw_table,
Expand All @@ -215,7 +202,8 @@ int advanced_firmware_update_application_install(
if (security_info) {
memcpy(&fw_logic->security_info, security_info,
sizeof(fw_logic->security_info));
handlers.get_security_config = fw_get_security_config;
handlers.get_security_config =
advanced_firmware_update_get_security_config;
} else {
handlers.get_security_config = NULL;
}
Expand Down
21 changes: 21 additions & 0 deletions demo/demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,21 @@ static void reschedule_notify_time_dependent(anjay_demo_t *demo) {
}
}

// !defined(ANJAY_WITH_CONN_STATUS_API)

#ifdef ANJAY_WITH_CONN_STATUS_API
static void
server_connection_status_change_callback(void *demo_,
anjay_t *anjay,
anjay_ssid_t ssid,
anjay_server_conn_status_t status) {
(void) demo_;
(void) anjay;
demo_log(INFO, "Current status of the server with SSID %d is: %s", ssid,
translate_server_connection_status_enum_to_str(status));
}
#endif // ANJAY_WITH_CONN_STATUS_API

static int demo_init(anjay_demo_t *demo, cmdline_args_t *cmdline_args) {
demo->allocated_buffers = cmdline_args->allocated_buffers;
cmdline_args->allocated_buffers = NULL;
Expand Down Expand Up @@ -544,6 +559,8 @@ static int demo_init(anjay_demo_t *demo, cmdline_args_t *cmdline_args) {
.update_immediately_on_dm_change =
cmdline_args->update_immediately_on_dm_change,
.enable_self_notify = cmdline_args->enable_self_notify,
.connection_error_is_registration_failure =
cmdline_args->connection_error_is_registration_failure,
.default_tls_ciphersuites = {
.ids = cmdline_args->default_ciphersuites,
.num_ids = cmdline_args->default_ciphersuites_count
Expand All @@ -555,6 +572,10 @@ static int demo_init(anjay_demo_t *demo, cmdline_args_t *cmdline_args) {
#if defined(ANJAY_WITH_LWM2M11) && defined(WITH_AVS_COAP_TCP)
.coap_tcp_request_timeout = cmdline_args->tcp_request_timeout,
#endif // defined(ANJAY_WITH_LWM2M11) && defined(WITH_AVS_COAP_TCP)
#ifdef ANJAY_WITH_CONN_STATUS_API
.server_connection_status_cb = server_connection_status_change_callback,
.server_connection_status_cb_arg = demo,
#endif // ANJAY_WITH_CONN_STATUS_API
};

#ifdef ANJAY_WITH_LWM2M11
Expand Down
8 changes: 8 additions & 0 deletions demo/demo_args.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ static const cmdline_args_t DEFAULT_CMDLINE_ARGS = {
.prefer_hierarchical_formats = false,
.update_immediately_on_dm_change = false,
.enable_self_notify = false,
.connection_error_is_registration_failure = false,
.prefer_same_socket_downloads = false,
};

Expand Down Expand Up @@ -594,6 +595,9 @@ static void print_help(const struct option *options) {
"over CoAP+TCP and HTTP" },
# endif // ANJAY_WITH_DOWNLOADER
#endif // ANJAY_WITH_MODULE_SW_MGMT
{ 348, NULL, NULL,
"Treat failures of the \"connect\" socket operation (e.g. (D)TLS "
"handshake failures) as a failed LwM2M Register operation." },
};

const size_t screen_width = get_screen_width();
Expand Down Expand Up @@ -994,6 +998,7 @@ int demo_parse_argv(cmdline_args_t *parsed_args, int argc, char *argv[]) {
{ "sw-mgmt-tcp-request-timeout", required_argument, 0, 347 },
# endif // ANJAY_WITH_DOWNLOADER
#endif // ANJAY_WITH_MODULE_SW_MGMT
{ "connection-error-is-registration-failure", no_argument, 0, 348 },
{ 0, 0, 0, 0 }
// clang-format on
};
Expand Down Expand Up @@ -2001,6 +2006,9 @@ int demo_parse_argv(cmdline_args_t *parsed_args, int argc, char *argv[]) {
}
# endif // ANJAY_WITH_DOWNLOADER
#endif // ANJAY_WITH_MODULE_SW_MGMT
case 348:
parsed_args->connection_error_is_registration_failure = true;
break;
case 0:
goto process;
}
Expand Down
1 change: 1 addition & 0 deletions demo/demo_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ typedef struct cmdline_args {
bool prefer_hierarchical_formats;
bool update_immediately_on_dm_change;
bool enable_self_notify;
bool connection_error_is_registration_failure;
bool use_connection_id;
bool start_offline;

Expand Down
24 changes: 24 additions & 0 deletions demo/demo_cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,24 @@ static void cmd_last_communication_time(anjay_demo_t *demo,
}
#endif // ANJAY_WITH_COMMUNICATION_TIMESTAMP_API

#ifdef ANJAY_WITH_CONN_STATUS_API
static void cmd_get_server_connection_status(anjay_demo_t *demo,
const char *args_string) {
anjay_ssid_t ssid = ANJAY_SSID_ANY;
anjay_server_conn_status_t result;

if (*args_string && parse_ssid(args_string, &ssid)) {
demo_log(ERROR, "invalid Short Server ID: %s", args_string);
return;
}

result = anjay_get_server_connection_status(demo->anjay, ssid);

demo_log(INFO, "Current server connection status: %s",
translate_server_connection_status_enum_to_str(result));
}
#endif // ANJAY_WITH_CONN_STATUS_API

static void cmd_help(anjay_demo_t *demo, const char *args_string);

struct cmd_handler_def {
Expand Down Expand Up @@ -1665,6 +1683,12 @@ static const struct cmd_handler_def COMMAND_HANDLERS[] = {
"no argument specified) or a given server (if numeric SSID "
"argument given)."),
#endif // ANJAY_WITH_COMMUNICATION_TIMESTAMP_API
#ifdef ANJAY_WITH_CONN_STATUS_API
CMD_HANDLER("get-server-connection-status", "[SSID]",
cmd_get_server_connection_status,
"Displays current connection status for the server with SSID "
"specified by the argument."),
#endif // ANJAY_WITH_CONN_STATUS_API
CMD_HANDLER("help", "", cmd_help, "Prints this message")
// clang-format on
};
Expand Down
24 changes: 24 additions & 0 deletions demo/demo_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ static struct {
char **argv;
} g_saved_args;

#ifdef ANJAY_WITH_CONN_STATUS_API
const char *translate_server_connection_status_enum_to_str(
anjay_server_conn_status_t status) {
static const char *const demo_server_connection_states_str[] = {
[ANJAY_SERV_CONN_STATUS_INVALID] = "INVALID",
[ANJAY_SERV_CONN_STATUS_ERROR] = "ERROR",
[ANJAY_SERV_CONN_STATUS_INITIAL] = "INITIAL",
[ANJAY_SERV_CONN_STATUS_CONNECTING] = "CONNECTING",
[ANJAY_SERV_CONN_STATUS_BOOTSTRAPPING] = "BOOTSTRAPPING",
[ANJAY_SERV_CONN_STATUS_BOOTSTRAPPED] = "BOOTSTRAPPED",
[ANJAY_SERV_CONN_STATUS_REGISTERING] = "REGISTERING",
[ANJAY_SERV_CONN_STATUS_REGISTERED] = "REGISTERED",
[ANJAY_SERV_CONN_STATUS_REG_FAILURE] = "REG_FAILURE",
[ANJAY_SERV_CONN_STATUS_DEREGISTERING] = "DEREGISTERING",
[ANJAY_SERV_CONN_STATUS_DEREGISTERED] = "DEREGISTERED",
[ANJAY_SERV_CONN_STATUS_SUSPENDING] = "SUSPENDING",
[ANJAY_SERV_CONN_STATUS_SUSPENDED] = "SUSPENDED",
[ANJAY_SERV_CONN_STATUS_REREGISTERING] = "REREGISTERING",
[ANJAY_SERV_CONN_STATUS_UPDATING] = "UPDATING"
};
return demo_server_connection_states_str[status];
}
#endif // ANJAY_WITH_CONN_STATUS_API

char **argv_get(void) {
AVS_ASSERT(g_saved_args.argv, "argv_store not called before argv_get");
return g_saved_args.argv;
Expand Down
5 changes: 5 additions & 0 deletions demo/demo_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ int copy_file_contents(FILE *dst, FILE *src);

int calc_file_crc32(const char *filename, uint32_t *out_crc);

#ifdef ANJAY_WITH_CONN_STATUS_API
const char *translate_server_connection_status_enum_to_str(
anjay_server_conn_status_t status);
#endif // ANJAY_WITH_CONN_STATUS_API

#if defined(AVS_COMMONS_WITH_AVS_PERSISTENCE) \
&& defined(AVS_COMMONS_STREAM_WITH_FILE)
avs_error_t store_etag(avs_persistence_context_t *ctx,
Expand Down
1 change: 1 addition & 0 deletions deps/avs_coap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ option(WITH_AVS_COAP_TCP "Enable CoAP over TCP support" ON)

option(WITH_AVS_COAP_STREAMING_API "Enable streaming API" ON)
option(WITH_AVS_COAP_OBSERVE "Enable support for observations" ON)
option(WITH_AVS_COAP_OBSERVE_CANCEL_ON_TIMEOUT "Turn on cancelling observation on a timeout " OFF)
cmake_dependent_option(WITH_AVS_COAP_OBSERVE_PERSISTENCE "Enable observations persistence" ON "WITH_AVS_COAP_OBSERVE" OFF)
option(WITH_AVS_COAP_BLOCK "Enable support for BLOCK/BERT transfers" ON)

Expand Down
1 change: 1 addition & 0 deletions deps/avs_coap/doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ if(EXISTS "${AVS_COAP_SOURCE_DIR}/Doxyfile.in")
# TODO: List these flags automatically
foreach(FLAG WITH_AVS_COAP_BLOCK
WITH_AVS_COAP_OBSERVE
WITH_AVS_COAP_OBSERVE_CANCEL_ON_TIMEOUT
WITH_AVS_COAP_OBSERVE_PERSISTENCE
WITH_AVS_COAP_STREAMING_API
WITH_AVS_COAP_TCP
Expand Down
14 changes: 13 additions & 1 deletion deps/avs_coap/include_public/avsystem/coap/avs_coap_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,23 @@
*/
#cmakedefine WITH_AVS_COAP_OBSERVE

/**
* Turn on cancelling observation on a timeout.
*
* Only meaningful if <c>WITH_AVS_COAP_OBSERVE</c> is enabled.
*
* NOTE: LwM2M specification requires LwM2M server to send Cancel Observation
* request. Meanwhile CoAP RFC 7641 states that timeout on notification should
* cancel it. This setting is to enable both of these behaviors with default
* focused on keeping observations in case of bad connectivity.
*/
#cmakedefine WITH_AVS_COAP_OBSERVE_CANCEL_ON_TIMEOUT

/**
* Enable support for observation persistence (<c>avs_coap_observe_persist()</c>
* and <c>avs_coap_observe_restore()</c> calls).
*
* Only meaningful <c>WITH_AVS_COAP_OBSERVE</c> is enabled.
* Only meaningful if <c>WITH_AVS_COAP_OBSERVE</c> is enabled.
*/
#cmakedefine WITH_AVS_COAP_OBSERVE_PERSISTENCE

Expand Down
9 changes: 4 additions & 5 deletions deps/avs_coap/src/async/avs_coap_async_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,17 +314,16 @@ send_result_handler(avs_coap_ctx_t *ctx,
},
code);
}
#ifdef WITH_AVS_COAP_OBSERVE
#if defined(WITH_AVS_COAP_OBSERVE) \
&& defined(WITH_AVS_COAP_OBSERVE_CANCEL_ON_TIMEOUT)
else if (fail_err.category == AVS_COAP_ERR_CATEGORY
&& fail_err.code == AVS_COAP_ERR_TIMEOUT) {
// According to RFC 7641, when trying to send a Confirmable notification
// ends in a timeout, the client "is considered no longer interested in
// the resource and is removed by the server from the list of observers"
avs_coap_observe_cancel(ctx, (avs_coap_observe_id_t) {
.token = token
});
}
#endif // WITH_AVS_COAP_OBSERVE
#endif /* defined(WITH_AVS_COAP_OBSERVE) && \
defined(WITH_AVS_COAP_OBSERVE_CANCEL_ON_TIMEOUT) */

// delivery status handler or observe cancel handler
// might have canceled the exchange
Expand Down
Loading

0 comments on commit 3ba32ac

Please sign in to comment.