Skip to content

Commit

Permalink
Split unpublish request into multiple requests
Browse files Browse the repository at this point in the history
When attempting to unpublish multiple resource links the query
can exceed the allowed COAP COAP_MAX_HEADER_SIZE limit.
To avoid this issue the query is split between mutliple requests
when necessary.
  • Loading branch information
Danielius1922 authored and Daniel Adam committed Oct 31, 2023
1 parent 9a7ed7a commit 19901c3
Show file tree
Hide file tree
Showing 36 changed files with 1,213 additions and 396 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/cmake-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ jobs:
-D BUILD_TESTING=${{ matrix.config.build_testing }}
-D OC_CLOUD_ENABLED=ON
-D OC_COLLECTIONS_IF_CREATE_ENABLED=ON
-D OC_PUSH_ENABLED=ON
-D OC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON
-D PLGD_DEV_TIME_ENABLED=ON
-D OC_ETAG_ENABLED=ON
-D OC_DEBUG_ENABLED=ON
-G Ninja
-D CMAKE_MAKE_PROGRAM=${ninja_program}
Expand Down
16 changes: 13 additions & 3 deletions api/client/oc_client_cb.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "util/oc_macros_internal.h"

#ifdef OC_TCP
#include "api/oc_ping_internal.h"
#include "messaging/coap/signal_internal.h"
#endif /* OC_TCP */

Expand Down Expand Up @@ -189,6 +190,9 @@ client_cb_remove_from_lists(const oc_client_cb_t *cb)
oc_ri_remove_timed_event_callback(cb, &oc_client_cb_remove_async);
oc_ri_remove_timed_event_callback(
cb, &oc_client_cb_remove_with_notify_timeout_async);
#ifdef OC_TCP
oc_ri_remove_timed_event_callback(cb, &oc_remove_ping_handler_async);
#endif /* OC_TCP */
oc_list_remove(g_client_cbs, cb);
}

Expand All @@ -213,6 +217,12 @@ oc_client_cb_dealloc(oc_client_cb_t *cb)
cb, oc_client_cb_remove_with_notify_timeout_async) ||
!oc_ri_has_timed_event_callback(
cb, oc_client_cb_remove_with_notify_timeout_async, false));
#ifdef OC_TCP
assert(
oc_timed_event_callback_is_currently_processed(
cb, oc_remove_ping_handler_async) ||
!oc_ri_has_timed_event_callback(cb, oc_remove_ping_handler_async, false));
#endif /* OC_TCP */
#ifdef OC_BLOCK_WISE
oc_blockwise_scrub_buffers_for_client_cb(cb);
#endif /* OC_BLOCK_WISE */
Expand Down Expand Up @@ -259,7 +269,7 @@ client_cb_notify_with_code(oc_client_cb_t *cb, oc_status_t code)

#ifdef OC_TCP
if (client_cb_is_ping_response(cb)) {
oc_ri_remove_timed_event_callback(cb, oc_remove_ping_handler_async);
oc_ri_remove_timed_event_callback(cb, &oc_remove_ping_handler_async);
}
#endif /* OC_TCP */

Expand Down Expand Up @@ -509,7 +519,7 @@ oc_client_cb_invoke(const coap_packet_t *response, oc_client_cb_t *cb,

#ifdef OC_TCP
if (response->code == PONG_7_03 || client_cb_is_ping_response(cb)) {
oc_ri_remove_timed_event_callback(cb, oc_remove_ping_handler_async);
oc_ri_remove_timed_event_callback(cb, &oc_remove_ping_handler_async);
}
#endif /* OC_TCP */

Expand Down Expand Up @@ -543,7 +553,7 @@ client_cb_free_all(void)
{
oc_client_cb_t *cb = oc_list_pop(g_client_cbs);
while (cb != NULL) {
oc_client_cb_dealloc(cb);
oc_client_cb_free(cb);
cb = oc_list_pop(g_client_cbs);
}
}
Expand Down
6 changes: 4 additions & 2 deletions api/cloud/oc_cloud_log_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ extern "C" {
#ifndef OC_CLOUD_NOTE
#if OC_NOTE_IS_ENABLED
#define OC_CLOUD_NOTE(...) \
OC_LOG_WITH_COMPONENT(OC_LOG_LEVEL_NOTE, OC_LOG_COMPONENT_CLOUD, __VA_ARGS__)
OC_LOG_WITH_COMPONENT(OC_LOG_LEVEL_NOTICE, OC_LOG_COMPONENT_CLOUD, \
__VA_ARGS__)
#else /* !OC_NOTE_IS_ENABLED */
#define OC_CLOUD_NOTE(...)
#endif /* OC_NOTE_IS_ENABLED */
Expand All @@ -64,7 +65,8 @@ extern "C" {
#ifndef OC_CLOUD_WRN
#if OC_WRN_IS_ENABLED
#define OC_CLOUD_WRN(...) \
OC_LOG_WITH_COMPONENT(OC_LOG_LEVEL_WARN, OC_LOG_COMPONENT_CLOUD, __VA_ARGS__)
OC_LOG_WITH_COMPONENT(OC_LOG_LEVEL_WARNING, OC_LOG_COMPONENT_CLOUD, \
__VA_ARGS__)
#else /* !OC_WRN_IS_ENABLED */
#define OC_CLOUD_WRN(...)
#endif /* OC_WRN_IS_ENABLED */
Expand Down
133 changes: 89 additions & 44 deletions api/cloud/oc_cloud_rd.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#ifdef OC_CLOUD

#include "api/oc_link_internal.h"
#include "api/oc_ri_internal.h"
#include "oc_api.h"
#include "oc_cloud_internal.h"
#include "oc_cloud_log_internal.h"
Expand Down Expand Up @@ -109,7 +110,7 @@ rd_link_remove_by_resource(oc_link_t **head, const oc_resource_t *res)
}

static void
publish_resources_handler(oc_client_response_t *data)
cloud_publish_resources_handler(oc_client_response_t *data)
{
oc_cloud_context_t *ctx = (oc_cloud_context_t *)data->user_data;
OC_CLOUD_DBG("publish resources handler(%d)", data->code);
Expand All @@ -122,43 +123,56 @@ publish_resources_handler(oc_client_response_t *data)
}

oc_rep_t *link = NULL;
if (oc_rep_get_object_array(data->payload, OC_RSRVD_LINKS, &link)) {
while (link != NULL) {
char *href = NULL;
size_t href_size = 0;
int64_t instance_id = -1;
if (oc_rep_get_string(link->value.object, OC_RSRVD_HREF, &href,
&href_size) &&
oc_rep_get_int(link->value.object, OC_RSRVD_INSTANCEID,
&instance_id)) {
oc_link_t *l =
rd_link_find_by_href(ctx->rd_publish_resources, href, href_size);
if (l) {
l->ins = instance_id;
rd_link_remove(&ctx->rd_publish_resources, l);
rd_link_add(&ctx->rd_published_resources, l);
}
}
link = link->next;
if (!oc_rep_get_object_array(data->payload, OC_RSRVD_LINKS, &link)) {
return;
}
for (; link != NULL; link = link->next) {
char *href = NULL;
size_t href_size = 0;
if (!oc_rep_get_string(link->value.object, OC_RSRVD_HREF, &href,
&href_size)) {
OC_CLOUD_DBG("link skipped: no href");
continue;
}
int64_t instance_id = -1;
if (!oc_rep_get_int(link->value.object, OC_RSRVD_INSTANCEID,
&instance_id)) {
OC_CLOUD_DBG("link skipped: no instanceID");
continue;
}
oc_link_t *l =
rd_link_find_by_href(ctx->rd_publish_resources, href, href_size);
if (l == NULL) {
OC_CLOUD_DBG("link(%s) skipped: not found", href);
continue;
}
l->ins = instance_id;
rd_link_remove(&ctx->rd_publish_resources, l);
OC_CLOUD_DBG("link(href=%s,ins=%" PRId64 ") published", href, instance_id);
rd_link_add(&ctx->rd_published_resources, l);
}
}

static void
publish_resources(oc_cloud_context_t *ctx)
cloud_publish_resources(oc_cloud_context_t *ctx)
{
#ifdef OC_SECURITY
const oc_sec_pstat_t *pstat = oc_sec_get_pstat(ctx->device);
if (pstat->s != OC_DOS_RFNOP) {
if (!oc_sec_pstat_is_in_dos_state(ctx->device,
OC_PSTAT_DOS_ID_FLAG(OC_DOS_RFNOP))) {
OC_CLOUD_DBG("cannot publish resource links when not in RFNOP");
return;
}
#endif /* OC_SECURITY */
if ((ctx->store.status & OC_CLOUD_LOGGED_IN) == 0) {
OC_CLOUD_DBG("cannot publish resource links when not logged in");
return;
}

rd_publish(ctx->cloud_ep, ctx->rd_publish_resources, ctx->device,
ctx->time_to_live, publish_resources_handler, LOW_QOS, ctx);
if (!rd_publish(ctx->rd_publish_resources, ctx->cloud_ep, ctx->device,
ctx->time_to_live, cloud_publish_resources_handler, LOW_QOS,
ctx)) {
OC_CLOUD_ERR("cannot send publish resource links request");
}
}

int
Expand Down Expand Up @@ -186,8 +200,11 @@ oc_cloud_add_resource(oc_resource_t *res)
}

oc_link_t *link = oc_new_link(res);
if (link == NULL) {
return -1;
}
rd_link_add(&ctx->rd_publish_resources, link);
publish_resources(ctx);
cloud_publish_resources(ctx);
return 0;
}

Expand All @@ -205,23 +222,37 @@ publish_published_resources(void *data)
{
oc_cloud_context_t *ctx = (oc_cloud_context_t *)data;
move_published_to_publish_resources(ctx);
publish_resources(ctx);
cloud_publish_resources(ctx);
return OC_EVENT_CONTINUE;
}

static void cloud_delete_resources(oc_cloud_context_t *ctx);

static void
delete_resources_handler(oc_client_response_t *data)
{
OC_CLOUD_DBG("delete resources handler(%d)", data->code);
(void)data;
oc_cloud_context_t *ctx = (oc_cloud_context_t *)data->user_data;
if (ctx->rd_delete_resources == NULL) {
return;
}
if (oc_status_is_internal_code(data->code)) {
OC_CLOUD_ERR("unpublishing of remaining resource links skipped for "
"internal response code(%d)",
(int)data->code);
return;
}
cloud_delete_resources(ctx);
}

static void
delete_resources(oc_cloud_context_t *ctx)
cloud_delete_resources(oc_cloud_context_t *ctx)
{
assert(ctx->rd_delete_resources != NULL);
#ifdef OC_SECURITY
const oc_sec_pstat_t *pstat = oc_sec_get_pstat(ctx->device);
if (pstat->s != OC_DOS_RFNOP) {
if (!oc_sec_pstat_is_in_dos_state(ctx->device,
OC_PSTAT_DOS_ID_FLAG(OC_DOS_RFNOP))) {
OC_CLOUD_DBG("cannot unpublish resource links when not in RFNOP");
return;
}
#endif /* OC_SECURITY */
Expand All @@ -230,16 +261,24 @@ delete_resources(oc_cloud_context_t *ctx)
return;
}

if (ctx->rd_delete_resources == NULL) {
rd_links_partition_t partition;
memset(&partition, 0, sizeof(rd_links_partition_t));
if (rd_delete(ctx->rd_delete_resources, ctx->cloud_ep, ctx->device,
delete_resources_handler, LOW_QOS, ctx,
&partition) == RD_DELETE_ERROR) {
OC_CLOUD_ERR("unpublishing of resource links failed");
return;
}

if (!rd_delete(ctx->cloud_ep, ctx->rd_delete_resources, ctx->device,
delete_resources_handler, LOW_QOS, ctx)) {
OC_CLOUD_ERR("cannot send unpublish resource links request");
return;
#if OC_DBG_IS_ENABLED
for (const oc_link_t *link = partition.not_deleted; link != NULL;
link = link->next) {
OC_CLOUD_DBG("link(href=%s, ins=%" PRId64 ") not unpublished",
oc_string(link->resource->uri), link->ins);
}
rd_link_free(&ctx->rd_delete_resources);
#endif /* OC_DBG_IS_ENABLED */
ctx->rd_delete_resources = partition.not_deleted;
rd_link_free(&partition.deleted);
}

void
Expand All @@ -254,9 +293,12 @@ cloud_rd_manager_status_changed(oc_cloud_context_t *ctx)
return;
}
if (ctx->rd_publish_resources != NULL) {
publish_resources(ctx);
cloud_publish_resources(ctx);
}
if (ctx->rd_delete_resources != NULL) {
cloud_delete_resources(ctx);
}
delete_resources(ctx);

oc_remove_delayed_callback(ctx, publish_published_resources);
if (ctx->time_to_live != RD_PUBLISH_TTL_UNLIMITED) {
oc_set_delayed_callback(ctx, publish_published_resources, ONE_HOUR);
Expand Down Expand Up @@ -316,20 +358,23 @@ oc_cloud_delete_resource(oc_resource_t *res)
published->resource = NULL;
}
rd_link_add(&ctx->rd_delete_resources, published);
delete_resources(ctx);
cloud_delete_resources(ctx);
}
}

int
oc_cloud_publish_resources(size_t device)
{
oc_cloud_context_t *ctx = oc_cloud_get_context(device);
if (ctx) {
publish_published_resources(ctx);
delete_resources(ctx);
return 0;
if (ctx == NULL) {
OC_ERR("cannot publish resource: invalid device(%zu)", device);
return -1;
}
publish_published_resources(ctx);
if (ctx->rd_delete_resources != NULL) {
cloud_delete_resources(ctx);
}
return -1;
return 0;
}

#else /* OC_CLOUD*/
Expand Down
Loading

0 comments on commit 19901c3

Please sign in to comment.