Skip to content

Commit

Permalink
fixup! Calcuate crc64 for a resource
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 committed Oct 21, 2023
1 parent b8d40af commit 662dcb2
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 77 deletions.
127 changes: 72 additions & 55 deletions api/oc_etag.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "api/oc_discovery_internal.h"
#include "api/oc_etag_internal.h"
#include "api/oc_helpers_internal.h"
#include "api/oc_rep_decode_internal.h"
#include "api/oc_rep_encode_internal.h"
#include "api/oc_rep_internal.h"
Expand Down Expand Up @@ -221,53 +222,55 @@ oc_etag_dump_ignore_resource(const char *uri, size_t uri_len)
(void)uri_len;
return false;
}

static bool
etag_iterate_encode_resource(oc_resource_t *resource, void *data)
oc_resource_encode_status_t
oc_etag_encode_resource_etag(CborEncoder *encoder, oc_resource_t *resource)
{
(void)data;
OC_DBG("encoding resource [%zu:%s]", resource->device,
oc_string(resource->uri));
if (oc_etag_dump_ignore_resource(oc_string(resource->uri),
oc_string_len(resource->uri))) {
OC_DBG("skipping resource %s", oc_string(resource->uri));
return true;
}
oc_string_view_t uri = oc_string_view2(&resource->uri);
uint64_t etag = oc_resource_get_etag(resource);
if (etag == OC_ETAG_UNINITIALIZED) {
OC_DBG("skipping uninitialized etag for resource %s",
oc_string(resource->uri));
return true;
OC_DBG("skipping uninitialized etag for resource %s", uri.data);
return OC_RESOURCE_ENCODE_SKIPPED;
}

uint64_t crc64 = 0;
if (oc_resource_get_crc64(resource, &crc64) != OC_RESOURCE_CRC64_OK) {
OC_DBG("cannot calculate crc64 for device(%zu) resource(%s)",
resource->device, oc_string(resource->uri));
return true;
resource->device, uri.data);
return OC_RESOURCE_ENCODE_SKIPPED;
}

CborError err =
oc_rep_encode_text_string(oc_rep_object(root), oc_string(resource->uri),
oc_string_len(resource->uri));
CborError err = oc_rep_encode_text_string(encoder, uri.data, uri.length);
CborEncoder etag_map;
memset(&etag_map, 0, sizeof(etag_map));
err |= oc_rep_encoder_create_map(oc_rep_object(root), &etag_map,
CborIndefiniteLength);
err |= oc_rep_encoder_create_map(encoder, &etag_map, CborIndefiniteLength);
err |=
oc_rep_encode_text_string(&etag_map, "etag", OC_CHAR_ARRAY_LEN("etag"));
err |= oc_rep_encode_uint(&etag_map, etag);
err |= oc_rep_encode_text_string(&etag_map, "crc", OC_CHAR_ARRAY_LEN("crc"));
err |= oc_rep_encode_uint(&etag_map, crc64);
err |= oc_rep_encoder_close_container(oc_rep_object(root), &etag_map);
err |= oc_rep_encoder_close_container(encoder, &etag_map);

if (err != CborNoError) {
OC_ERR("failed to encode device(%zu) resource %s", resource->device,
oc_string(resource->uri));
uri.data);
g_err |= err;
return false;
return OC_RESOURCE_ENCODE_ERROR;
}
return true;
return OC_RESOURCE_ENCODE_OK;
}

static bool
etag_iterate_encode_resource(oc_resource_t *resource, void *data)
{
(void)data;
oc_string_view_t uri = oc_string_view2(&resource->uri);
OC_DBG("encoding resource [%zu:%s]", resource->device, uri.data);
if (oc_etag_dump_ignore_resource(uri.data, uri.length)) {
OC_DBG("skipping resource %s", uri.data);
return true;
}
return oc_etag_encode_resource_etag(oc_rep_object(root), resource) !=
OC_RESOURCE_ENCODE_ERROR;
}

static int
Expand Down Expand Up @@ -306,56 +309,70 @@ oc_etag_dump(void)
return success;
}

typedef struct etag_update_from_rep_data_t
{
const oc_rep_t *rep;
uint64_t *etag;
} etag_update_from_rep_data_t;

static bool
etag_iterate_update_resources_by_rep(oc_resource_t *resource, void *data)
bool
oc_etag_decode_resource_etag(oc_resource_t *resource, const oc_rep_t *rep,
uint64_t *etag)
{
etag_update_from_rep_data_t *rep_data = (etag_update_from_rep_data_t *)data;
oc_rep_t *res_rep;
if (!oc_rep_get_object(rep_data->rep, oc_string(resource->uri), &res_rep)) {
OC_DBG("no representation for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
}

int64_t etag = 0;
if (!oc_rep_get_int(res_rep, "etag", &etag) || etag < 0 ||
etag == OC_ETAG_UNINITIALIZED) {
OC_DBG("ignoring invalid etag for resource %zu:%s", resource->device,
int64_t etag_store = 0;
if (!oc_rep_get_int(rep, "etag", &etag_store) ||
etag_store == OC_ETAG_UNINITIALIZED) {
OC_DBG("etag missing or invalid for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
return false;
}

int64_t crc64_store = 0;
if (!oc_rep_get_int(res_rep, "crc", &crc64_store)) {
if (!oc_rep_get_int(rep, "crc", &crc64_store)) {
OC_DBG("no checksum for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
return false;
}

uint64_t crc64 = 0;
if (oc_resource_get_crc64(resource, &crc64) != OC_RESOURCE_CRC64_OK) {
OC_DBG("cannot calculate crc64 for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
return false;
}

if ((uint64_t)crc64_store != crc64) {
OC_DBG("ignoring invalid checksum for resource %zu:%s: store (%" PRIu64
") vs current(%" PRIu64 ")",
resource->device, oc_string(resource->uri), (uint64_t)crc64_store,
crc64);
return false;
}
*etag = (uint64_t)etag_store;
return true;
}

typedef struct etag_update_from_rep_data_t
{
const oc_rep_t *rep;
uint64_t *etag;
} etag_update_from_rep_data_t;

static bool
etag_iterate_update_resources_by_rep(oc_resource_t *resource, void *data)
{
etag_update_from_rep_data_t *rep_data = (etag_update_from_rep_data_t *)data;
oc_rep_t *res_rep;
if (!oc_rep_get_object(rep_data->rep, oc_string(resource->uri), &res_rep)) {
OC_DBG("no representation for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
}

uint64_t etag;
if (!oc_etag_decode_resource_etag(resource, res_rep, &etag)) {
OC_DBG("failed to decode etag for resource %zu:%s", resource->device,
oc_string(resource->uri));
return true;
}

oc_resource_set_etag(resource, (uint64_t)etag);
if ((uint64_t)etag > *rep_data->etag) {
*rep_data->etag = (uint64_t)etag;
oc_resource_set_etag(resource, etag);
if (etag > *rep_data->etag) {
*rep_data->etag = etag;
}
return true;
}
Expand Down Expand Up @@ -551,7 +568,7 @@ resource_print_payload(oc_resource_t *resource, oc_interface_mask_t iface)

#endif /* OC_DBG_IS_ENABLED */

int
oc_resource_crc64_status_t
oc_resource_get_crc64(oc_resource_t *resource, uint64_t *crc64)
{
assert(resource != NULL);
Expand All @@ -568,7 +585,7 @@ oc_resource_get_crc64(oc_resource_t *resource, uint64_t *crc64)
OC_ERR("cannot calculate crc64 for device(%zu) resource(%s): get handler "
"not available",
resource->device, oc_string(resource->uri));
return -1;
return OC_RESOURCE_CRC64_ERROR;
}

oc_rep_encoder_reset_t prevEncoder = oc_rep_global_encoder_reset(NULL);
Expand All @@ -591,7 +608,7 @@ oc_resource_get_crc64(oc_resource_t *resource, uint64_t *crc64)
response_buffer.buffer_size = OC_ARRAY_SIZE(buffer);
if (!resource_get_payload_by_encoder(OC_REP_CRC_ENCODER, resource, iface,
&response_buffer, 0)) {
return -1;
return OC_RESOURCE_CRC64_ERROR;
}

int payload_size = oc_rep_get_encoded_payload_size();
Expand Down
38 changes: 34 additions & 4 deletions api/oc_etag_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,44 @@ bool oc_etag_dump_for_device(size_t device);
/** Do not dump resource with given URI to storage. */
bool oc_etag_dump_ignore_resource(const char *uri, size_t uri_len) OC_NONNULL();

enum {
typedef enum {
OC_RESOURCE_CRC64_OK, ///< resource has a payload and crc64 is calculated
OC_RESOURCE_CRC64_NO_PAYLOAD, ///< resource has no payload
};

OC_RESOURCE_CRC64_ERROR = -1, ///< error occured
} oc_resource_crc64_status_t;

/** Calculate crc64 checksum for given resource */
int oc_resource_get_crc64(oc_resource_t *resource, uint64_t *crc64)
OC_NONNULL();
oc_resource_crc64_status_t oc_resource_get_crc64(oc_resource_t *resource,
uint64_t *crc64) OC_NONNULL();

typedef enum {
OC_RESOURCE_ENCODE_OK,
OC_RESOURCE_ENCODE_SKIPPED,

OC_RESOURCE_ENCODE_ERROR = -1,
} oc_resource_encode_status_t;

/** @brief Encode resource ETag
*
* Format:
* "${resource-uri}": {
* "etag": ${resource->etag}
* "crc": ${resource payload crc64 checksum}
* }
*
* @param encoder encoder (cannot be NULL)
* @param resource resource to encode (cannot be NULL)
* @return OC_RESOURCE_ENCODE_OK if resource was encoded
* @return OC_RESOURCE_ENCODE_SKIPPED if resource encoding was skipped
* @return OC_RESOURCE_ENCODE_ERROR if error occured
*/
oc_resource_encode_status_t oc_etag_encode_resource_etag(
CborEncoder *encoder, oc_resource_t *resource) OC_NONNULL();

/** Decode resource ETag */
bool oc_etag_decode_resource_etag(oc_resource_t *resource, const oc_rep_t *rep,
uint64_t *etag) OC_NONNULL();

#endif /* OC_STORAGE */

Expand Down
6 changes: 0 additions & 6 deletions api/unittest/discoverytest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,6 @@ class TestDiscoveryWithServer : public ::testing::Test {
public:
static void SetUpTestCase()
{
// TODO: rm
oc_log_set_level(OC_LOG_LEVEL_DEBUG);

#if defined(OC_DYNAMIC_ALLOCATION) && !defined(OC_APP_DATA_BUFFER_SIZE)
oc_set_max_app_data_size(16384);
#endif /* OC_DYNAMIC_ALLOCATION && !OC_APP_DATA_BUFFER_SIZE */
Expand Down Expand Up @@ -145,9 +142,6 @@ class TestDiscoveryWithServer : public ::testing::Test {
#if defined(OC_DYNAMIC_ALLOCATION) && !defined(OC_APP_DATA_BUFFER_SIZE)
oc_set_max_app_data_size(g_max_app_data_size);
#endif /* OC_DYNAMIC_ALLOCATION && !OC_APP_DATA_BUFFER_SIZE */

// TODO: rm
oc_log_set_level(OC_LOG_LEVEL_INFO);
}

void SetUp() override
Expand Down
Loading

0 comments on commit 662dcb2

Please sign in to comment.