Loading...
Searching...
No Matches
coap_subscribe.c
Go to the documentation of this file.
/* coap_subscribe.c -- subscription handling for CoAP
* see RFC7641
*
* Copyright (C) 2010-2019,2022-2023 Olaf Bergmann <bergmann@tzi.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#include "coap3/coap_internal.h"
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#if COAP_SERVER_SUPPORT
void
coap_subscription_init(coap_subscription_t *s) {
assert(s);
memset(s, 0, sizeof(coap_subscription_t));
}
void
coap_persist_track_funcs(coap_context_t *context,
coap_observe_added_t observe_added,
coap_observe_deleted_t observe_deleted,
coap_track_observe_value_t track_observe_value,
coap_dyn_resource_added_t dyn_resource_added,
coap_resource_deleted_t resource_deleted,
uint32_t save_freq,
void *user_data) {
context->observe_added = observe_added;
context->observe_deleted = observe_deleted;
context->observe_user_data = user_data;
context->observe_save_freq = save_freq ? save_freq : 1;
context->track_observe_value = track_observe_value;
context->dyn_resource_added = dyn_resource_added;
context->resource_deleted = resource_deleted;
}
coap_subscription_t *
coap_persist_observe_add(coap_context_t *context,
coap_proto_t e_proto,
const coap_address_t *e_listen_addr,
const coap_addr_tuple_t *s_addr_info,
const coap_bin_const_t *raw_packet,
const coap_bin_const_t *oscore_info) {
coap_session_t *session = NULL;
const uint8_t *data;
size_t data_len;
coap_pdu_t *pdu = NULL;
#if COAP_CONSTRAINED_STACK
/* e_packet protected by mutex m_persist_add */
static coap_packet_t e_packet;
#else /* ! COAP_CONSTRAINED_STACK */
coap_packet_t e_packet;
#endif /* ! COAP_CONSTRAINED_STACK */
coap_packet_t *packet = &e_packet;
coap_tick_t now;
coap_string_t *uri_path = NULL;
coap_opt_iterator_t opt_iter;
coap_opt_t *observe;
int observe_action;
coap_resource_t *r;
coap_subscription_t *s;
coap_endpoint_t *ep;
if (e_listen_addr == NULL || s_addr_info == NULL || raw_packet == NULL)
return NULL;
/* Will be creating a local 'open' session */
if (e_proto != COAP_PROTO_UDP)
return NULL;
ep = context->endpoint;
while (ep) {
if (ep->proto == e_proto &&
memcmp(e_listen_addr, &ep->bind_addr, sizeof(ep->bind_addr)) == 0)
break;
ep = ep->next;
}
if (!ep)
return NULL;
#if COAP_CONSTRAINED_STACK
coap_mutex_lock(&m_persist_add);
#endif /* COAP_CONSTRAINED_STACK */
/* Build up packet */
memcpy(&packet->addr_info, s_addr_info, sizeof(packet->addr_info));
packet->ifindex = 0;
memcpy(&packet->payload, &raw_packet->s, sizeof(packet->payload));
packet->length = raw_packet->length;
data = raw_packet->s;
data_len = raw_packet->length;
if (data_len < 4)
goto malformed;
/* Get the session */
coap_ticks(&now);
session = coap_endpoint_get_session(ep, packet, now);
if (session == NULL)
goto fail;
/* Need max space incase PDU is updated with updated token, huge size etc. */
pdu = coap_pdu_init(0, 0, 0, 0);
if (!pdu)
goto fail;
if (!coap_pdu_parse(session->proto, data, data_len, pdu)) {
goto malformed;
}
pdu->max_size = pdu->used_size;
if (pdu->code != COAP_REQUEST_CODE_GET &&
pdu->code != COAP_REQUEST_CODE_FETCH)
goto malformed;
observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
if (observe == NULL)
goto malformed;
observe_action = coap_decode_var_bytes(coap_opt_value(observe),
coap_opt_length(observe));
if (observe_action != COAP_OBSERVE_ESTABLISH)
goto malformed;
/* Get the resource */
uri_path = coap_get_uri_path(pdu);
if (!uri_path)
goto malformed;
r = coap_get_resource_from_uri_path(session->context,
(coap_str_const_t *)uri_path);
if (r == NULL) {
coap_log_warn("coap_persist_observe_add: resource '%s' not defined\n",
uri_path->s);
goto fail;
}
if (!r->observable) {
coap_log_warn("coap_persist_observe_add: resource '%s' not observable\n",
uri_path->s);
goto fail;
}
coap_delete_string(uri_path);
uri_path = NULL;
/* Create / update subscription for observing */
/* Now set up the subscription */
s = coap_add_observer(r, session, &pdu->actual_token, pdu);
if (s == NULL)
goto fail;
#if COAP_OSCORE_SUPPORT
if (oscore_info) {
coap_log_debug("persist: OSCORE association being updated\n");
/*
* Need to track the association used for tracking this observe, done as
* a CBOR array. Written in coap_add_observer().
*
* If an entry is null, then use nil, else a set of bytes
*
* Currently tracking 5 items
* recipient_id
* id_context
* aad (from oscore_association_t)
* partial_iv (from oscore_association_t)
* nonce (from oscore_association_t)
*/
oscore_ctx_t *osc_ctx;
const uint8_t *info_buf = oscore_info->s;
size_t info_buf_len = oscore_info->length;
size_t ret = 0;
coap_bin_const_t oscore_key_id;
coap_bin_const_t partial_iv;
coap_bin_const_t aad;
coap_bin_const_t id_context;
coap_bin_const_t nonce;
int have_aad = 0;
int have_partial_iv = 0;
int have_id_context = 0;
int have_nonce = 0;
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret != CBOR_ARRAY)
goto oscore_fail;
if (oscore_cbor_get_element_size(&info_buf, &info_buf_len) != 5)
goto oscore_fail;
/* recipient_id */
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret != CBOR_BYTE_STRING)
goto oscore_fail;
oscore_key_id.length = oscore_cbor_get_element_size(&info_buf,
&info_buf_len);
oscore_key_id.s = info_buf;
info_buf += oscore_key_id.length;
/* id_context */
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret == CBOR_BYTE_STRING) {
id_context.length = oscore_cbor_get_element_size(&info_buf,
&info_buf_len);
id_context.s = info_buf;
info_buf += id_context.length;
have_id_context = 1;
} else if (ret == CBOR_SIMPLE_VALUE &&
oscore_cbor_get_element_size(&info_buf,
&info_buf_len) == CBOR_NULL) {
} else
goto oscore_fail;
/* aad */
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret == CBOR_BYTE_STRING) {
aad.length = oscore_cbor_get_element_size(&info_buf, &info_buf_len);
aad.s = info_buf;
info_buf += aad.length;
have_aad = 1;
} else if (ret == CBOR_SIMPLE_VALUE &&
oscore_cbor_get_element_size(&info_buf,
&info_buf_len) == CBOR_NULL) {
} else
goto oscore_fail;
/* partial_iv */
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret == CBOR_BYTE_STRING) {
partial_iv.length = oscore_cbor_get_element_size(&info_buf,
&info_buf_len);
partial_iv.s = info_buf;
info_buf += partial_iv.length;
have_partial_iv = 1;
} else if (ret == CBOR_SIMPLE_VALUE &&
oscore_cbor_get_element_size(&info_buf,
&info_buf_len) == CBOR_NULL) {
} else
goto oscore_fail;
/* nonce */
ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
if (ret == CBOR_BYTE_STRING) {
nonce.length = oscore_cbor_get_element_size(&info_buf,
&info_buf_len);
nonce.s = info_buf;
info_buf += nonce.length;
have_nonce = 1;
} else if (ret == CBOR_SIMPLE_VALUE &&
oscore_cbor_get_element_size(&info_buf,
&info_buf_len) == CBOR_NULL) {
} else
goto oscore_fail;
osc_ctx = oscore_find_context(session->context, oscore_key_id,
have_id_context ? &id_context : NULL, NULL,
&session->recipient_ctx);
if (osc_ctx) {
session->oscore_encryption = 1;
oscore_new_association(session, pdu, &pdu->actual_token,
session->recipient_ctx,
have_aad ? &aad : NULL,
have_nonce ? &nonce : NULL,
have_partial_iv ? &partial_iv : NULL,
1);
coap_log_debug("persist: OSCORE association added\n");
oscore_log_hex_value(COAP_LOG_OSCORE, "partial_iv",
have_partial_iv ? &partial_iv : NULL);
}
}
oscore_fail:
#else /* ! COAP_OSCORE_SUPPORT */
(void)oscore_info;
#endif /* ! COAP_OSCORE_SUPPORT */
coap_delete_pdu(pdu);
#if COAP_CONSTRAINED_STACK
coap_mutex_unlock(&m_persist_add);
#endif /* COAP_CONSTRAINED_STACK */
return s;
malformed:
coap_log_warn("coap_persist_observe_add: discard malformed PDU\n");
fail:
#if COAP_CONSTRAINED_STACK
coap_mutex_unlock(&m_persist_add);
#endif /* COAP_CONSTRAINED_STACK */
coap_delete_string(uri_path);
coap_delete_pdu(pdu);
return NULL;
}
#if COAP_WITH_OBSERVE_PERSIST
#include <stdio.h>
/*
* read in active observe entry.
*/
static int
coap_op_observe_read(FILE *fp, coap_subscription_t **observe_key,
coap_proto_t *e_proto, coap_address_t *e_listen_addr,
coap_addr_tuple_t *s_addr_info,
coap_bin_const_t **raw_packet, coap_bin_const_t **oscore_info) {
ssize_t size;
coap_binary_t *scratch = NULL;
assert(fp && observe_key && e_proto && e_listen_addr && s_addr_info &&
raw_packet && oscore_info);
*raw_packet = NULL;
*oscore_info = NULL;
if (fread(observe_key, sizeof(*observe_key), 1, fp) == 1) {
/* New record 'key proto listen addr_info len raw_packet len oscore' */
if (fread(e_proto, sizeof(*e_proto), 1, fp) != 1)
goto fail;
if (fread(e_listen_addr, sizeof(*e_listen_addr), 1, fp) != 1)
goto fail;
if (fread(s_addr_info, sizeof(*s_addr_info), 1, fp) != 1)
goto fail;
if (fread(&size, sizeof(size), 1, fp) != 1)
goto fail;
if (size < 0 || size > 0x10000)
goto fail;
scratch = coap_new_binary(size);
if ((scratch) == NULL)
goto fail;
if (fread(scratch->s, scratch->length, 1, fp) != 1)
goto fail;
*raw_packet = (coap_bin_const_t *)scratch;
scratch = NULL;
if (fread(&size, sizeof(size), 1, fp) != 1)
goto fail;
/* If size == -1, then no oscore information */
if (size == -1)
return 1;
else if (size < 0 || size > 0x10000)
goto fail;
else {
scratch = coap_new_binary(size);
if (scratch == NULL)
goto fail;
if (fread(scratch->s, scratch->length, 1, fp) != 1)
goto fail;
*oscore_info = (coap_bin_const_t *)scratch;
}
return 1;
}
fail:
coap_delete_bin_const(*raw_packet);
coap_delete_binary(scratch);
*observe_key = NULL;
memset(e_proto, 0, sizeof(*e_proto));
memset(e_listen_addr, 0, sizeof(*e_listen_addr));
memset(s_addr_info, 0, sizeof(*s_addr_info));
*raw_packet = NULL;
return 0;
}
/*
* write out active observe entry.
*/
static int
coap_op_observe_write(FILE *fp, coap_subscription_t *observe_key,
coap_proto_t e_proto, coap_address_t e_listen_addr,
coap_addr_tuple_t s_addr_info,
coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info) {
if (fwrite(&observe_key, sizeof(observe_key), 1, fp) != 1)
goto fail;
if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
goto fail;
if (fwrite(&e_listen_addr, sizeof(e_listen_addr),
1, fp) != 1)
goto fail;
if (fwrite(&s_addr_info, sizeof(s_addr_info), 1, fp) != 1)
goto fail;
if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
goto fail;
if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
goto fail;
if (oscore_info) {
if (fwrite(&oscore_info->length, sizeof(oscore_info->length), 1, fp) != 1)
goto fail;
if (fwrite(oscore_info->s, oscore_info->length, 1, fp) != 1)
goto fail;
} else {
ssize_t not_defined = -1;
if (fwrite(&not_defined, sizeof(not_defined), 1, fp) != 1)
goto fail;
}
return 1;
fail:
return 0;
}
/*
* This should be called before coap_persist_track_funcs() to prevent
* coap_op_observe_added() getting unnecessarily called.
* It should be called after init_resources() and coap_op_resource_load_disk()
* so that all the resources are in place.
*/
static void
coap_op_observe_load_disk(coap_context_t *ctx) {
FILE *fp_orig = fopen((const char *)ctx->observe_save_file->s, "r");
FILE *fp_new = NULL;
coap_subscription_t *observe_key = NULL;
coap_proto_t e_proto;
coap_address_t e_listen_addr;
coap_addr_tuple_t s_addr_info;
coap_bin_const_t *raw_packet = NULL;
coap_bin_const_t *oscore_info = NULL;
char *new = NULL;
if (fp_orig == NULL)
goto fail;
new = coap_malloc_type(COAP_STRING, ctx->observe_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)ctx->observe_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and load oscore entry, updating key on the way */
while (1) {
if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
&s_addr_info, &raw_packet, &oscore_info))
break;
coap_log_debug("persist: New session/observe being created\n");
observe_key = coap_persist_observe_add(ctx, e_proto,
&e_listen_addr,
&s_addr_info,
raw_packet,
oscore_info);
if (observe_key) {
if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
s_addr_info, raw_packet, oscore_info))
goto fail;
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
}
}
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)ctx->observe_save_file->s);
coap_free_type(COAP_STRING, new);
return;
fail:
coap_delete_bin_const(raw_packet);
coap_delete_bin_const(oscore_info);
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return;
}
/*
* client has registered a new observe subscription request.
*/
static int
coap_op_observe_added(coap_session_t *session,
coap_subscription_t *a_observe_key,
coap_proto_t a_e_proto, coap_address_t *a_e_listen_addr,
coap_addr_tuple_t *a_s_addr_info,
coap_bin_const_t *a_raw_packet,
coap_bin_const_t *a_oscore_info, void *user_data) {
FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
"r");
FILE *fp_new = NULL;
coap_subscription_t *observe_key = NULL;
coap_proto_t e_proto;
coap_address_t e_listen_addr;
coap_addr_tuple_t s_addr_info;
coap_bin_const_t *raw_packet = NULL;
coap_bin_const_t *oscore_info = NULL;
char *new = NULL;
(void)user_data;
new = coap_malloc_type(COAP_STRING,
session->context->observe_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)session->context->observe_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and delete observe entry if it exists */
while (fp_orig) {
if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
&s_addr_info, &raw_packet, &oscore_info))
break;
if (observe_key != a_observe_key) {
if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
s_addr_info, raw_packet, oscore_info))
goto fail;
}
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
}
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
/* Add in new entry to the end */
if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
*a_s_addr_info, a_raw_packet, a_oscore_info))
goto fail;
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)session->context->observe_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
coap_delete_bin_const(raw_packet);
coap_delete_bin_const(oscore_info);
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
/*
* client has de-registered a observe subscription request.
*/
static int
coap_op_observe_deleted(coap_session_t *session,
coap_subscription_t *d_observe_key,
void *user_data) {
FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
"r");
FILE *fp_new = NULL;
coap_subscription_t *observe_key = NULL;
coap_proto_t e_proto;
coap_address_t e_listen_addr;
coap_addr_tuple_t s_addr_info;
coap_bin_const_t *raw_packet = NULL;
coap_bin_const_t *oscore_info = NULL;
char *new = NULL;
(void)user_data;
if (fp_orig == NULL)
goto fail;
new = coap_malloc_type(COAP_STRING,
session->context->observe_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)session->context->observe_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and locate observe entry to delete and not copy it across */
while (1) {
if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
&s_addr_info, &raw_packet, &oscore_info))
break;
if (observe_key != d_observe_key) {
if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
s_addr_info, (coap_bin_const_t *)raw_packet,
(coap_bin_const_t *)oscore_info))
goto fail;
}
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
}
coap_delete_bin_const(raw_packet);
raw_packet = NULL;
coap_delete_bin_const(oscore_info);
oscore_info = NULL;
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)session->context->observe_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
coap_delete_bin_const(raw_packet);
coap_delete_bin_const(oscore_info);
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
/*
* This should be called before coap_persist_track_funcs() to prevent
* coap_op_obs_cnt_track_observe() getting unnecessarily called.
* Should be called after coap_op_dyn_resource_load_disk() to make sure that
* all the resources are in the right place.
*/
static void
coap_op_obs_cnt_load_disk(coap_context_t *context) {
FILE *fp = fopen((const char *)context->obs_cnt_save_file->s, "r");
char buf[1500];
if (fp == NULL)
return;
while (fgets(buf, sizeof(buf), fp) != NULL) {
char *cp = strchr(buf, ' ');
coap_str_const_t resource_key;
uint32_t observe_num;
coap_resource_t *r;
if (!cp)
break;
*cp = '\000';
cp++;
observe_num = atoi(cp);
/*
* Need to assume 0 .. (context->observe_save_freq-1) have in addition
* been sent so need to round up to latest possible send value
*/
observe_num = ((observe_num + context->observe_save_freq) /
context->observe_save_freq) *
context->observe_save_freq - 1;
resource_key.s = (uint8_t *)buf;
resource_key.length = strlen(buf);
r = coap_get_resource_from_uri_path(context, &resource_key);
if (r) {
coap_log_debug("persist: Initial observe number being updated\n");
coap_persist_set_observe_num(r, observe_num);
}
}
fclose(fp);
}
/*
* Called when the observe value of a resource has been changed, but limited
* to be called every context->context->observe_save_freq to reduce update
* overheads.
*/
static int
coap_op_obs_cnt_track_observe(coap_context_t *context,
coap_str_const_t *resource_name,
uint32_t n_observe_num,
void *user_data) {
FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
FILE *fp_new = NULL;
char buf[1500];
char *new = NULL;
(void)user_data;
new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)context->obs_cnt_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and locate resource entry to update */
while (fp_orig && fgets(buf, sizeof(buf), fp_orig) != NULL) {
char *cp = strchr(buf, ' ');
uint32_t observe_num;
coap_bin_const_t resource_key;
if (!cp)
break;
*cp = '\000';
cp++;
observe_num = atoi(cp);
resource_key.s = (uint8_t *)buf;
resource_key.length = strlen(buf);
if (!coap_binary_equal(resource_name, &resource_key)) {
if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
goto fail;
}
}
if (fprintf(fp_new, "%s %u\n", resource_name->s, n_observe_num) < 0)
goto fail;
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)context->obs_cnt_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
/*
* Called when a resource has been deleted.
*/
static int
coap_op_obs_cnt_deleted(coap_context_t *context,
coap_str_const_t *resource_name) {
FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
FILE *fp_new = NULL;
char buf[1500];
char *new = NULL;
if (fp_orig == NULL)
goto fail;
new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)context->obs_cnt_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and locate resource entry to delete */
while (fgets(buf, sizeof(buf), fp_orig) != NULL) {
char *cp = strchr(buf, ' ');
uint32_t observe_num;
coap_bin_const_t resource_key;
if (!cp)
break;
*cp = '\000';
cp++;
observe_num = atoi(cp);
resource_key.s = (uint8_t *)buf;
resource_key.length = strlen(buf);
if (!coap_binary_equal(resource_name, &resource_key)) {
if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
goto fail;
}
}
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)context->obs_cnt_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
/*
* read in dynamic resource entry, allocating name & raw_packet
* which need to be freed off by caller.
*/
static int
coap_op_dyn_resource_read(FILE *fp, coap_proto_t *e_proto,
coap_string_t **name,
coap_binary_t **raw_packet) {
ssize_t size;
*name = NULL;
*raw_packet = NULL;
if (fread(e_proto, sizeof(*e_proto), 1, fp) == 1) {
/* New record 'proto len resource_name len raw_packet' */
if (fread(&size, sizeof(size), 1, fp) != 1)
goto fail;
if (size < 0 || size > 0x10000)
goto fail;
*name = coap_new_string(size);
if (!(*name))
goto fail;
if (fread((*name)->s, size, 1, fp) != 1)
goto fail;
if (fread(&size, sizeof(size), 1, fp) != 1)
goto fail;
if (size < 0 || size > 0x10000)
goto fail;
*raw_packet = coap_new_binary(size);
if (!(*raw_packet))
goto fail;
if (fread((*raw_packet)->s, size, 1, fp) != 1)
goto fail;
return 1;
}
fail:
return 0;
}
/*
* write out dynamic resource entry.
*/
static int
coap_op_dyn_resource_write(FILE *fp, coap_proto_t e_proto,
coap_str_const_t *name,
coap_bin_const_t *raw_packet) {
if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
goto fail;
if (fwrite(&name->length, sizeof(name->length), 1, fp) != 1)
goto fail;
if (fwrite(name->s, name->length, 1, fp) != 1)
goto fail;
if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
goto fail;
if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
goto fail;
return 1;
fail:
return 0;
}
/*
* This should be called before coap_persist_track_funcs() to prevent
* coap_op_dyn_resource_added() getting unnecessarily called.
*
* Each record 'proto len resource_name len raw_packet'
*/
static void
coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
FILE *fp_orig = NULL;
coap_proto_t e_proto;
coap_string_t *name = NULL;
coap_binary_t *raw_packet = NULL;
coap_resource_t *r;
coap_session_t *session = NULL;
coap_pdu_t *request = NULL;
coap_pdu_t *response = NULL;
coap_string_t *query = NULL;
if (!ctx->unknown_resource)
return;
fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
if (fp_orig == NULL)
return;
session = (coap_session_t *)coap_malloc_type(COAP_SESSION,
sizeof(coap_session_t));
if (!session)
goto fail;
memset(session, 0, sizeof(coap_session_t));
session->context = ctx;
/* Go through and create each dynamic resource if it does not exist*/
while (1) {
if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
break;
r = coap_get_resource_from_uri_path(ctx, (coap_str_const_t *)name);
if (!r) {
/* Create the new resource using the application logic */
coap_log_debug("persist: dynamic resource being re-created\n");
/*
* Need max space incase PDU is updated with updated token,
* huge size etc.
* */
request = coap_pdu_init(0, 0, 0, 0);
if (!request)
goto fail;
session->proto = e_proto;
if (!coap_pdu_parse(session->proto, raw_packet->s,
raw_packet->length, request)) {
goto fail;
}
if (!ctx->unknown_resource->handler[request->code-1])
goto fail;
response = coap_pdu_init(0, 0, 0, 0);
if (!response)
goto fail;
query = coap_get_query(request);
/* Call the application handler to set up this dynamic resource */
ctx->unknown_resource->handler[request->code-1](ctx->unknown_resource,
session, request,
query, response);
coap_delete_string(query);
query = NULL;
coap_delete_pdu(request);
request = NULL;
coap_delete_pdu(response);
response = NULL;
}
coap_delete_string(name);
coap_delete_binary(raw_packet);
}
fail:
coap_delete_string(name);
coap_delete_binary(raw_packet);
coap_delete_string(query);
coap_delete_pdu(request);
coap_delete_pdu(response);
fclose(fp_orig);
coap_free_type(COAP_SESSION, session);
}
/*
* Server has set up a new dynamic resource agains a request for an unknown
* resource.
*/
static int
coap_op_dyn_resource_added(coap_session_t *session,
coap_str_const_t *resource_name,
coap_bin_const_t *packet,
void *user_data) {
FILE *fp_orig;
FILE *fp_new = NULL;
char *new = NULL;
coap_context_t *context = session->context;
coap_string_t *name = NULL;
coap_binary_t *raw_packet = NULL;
coap_proto_t e_proto;
(void)user_data;
fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "a");
if (fp_orig == NULL)
return 0;
new = coap_malloc_type(COAP_STRING,
context->dyn_resource_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)context->dyn_resource_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and locate duplicate resource to delete */
while (1) {
if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
break;
if (!coap_string_equal(resource_name, name)) {
/* Copy across non-matching entry */
if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
(coap_bin_const_t *)raw_packet))
break;
}
coap_delete_string(name);
name = NULL;
coap_delete_binary(raw_packet);
raw_packet = NULL;
}
coap_delete_string(name);
coap_delete_binary(raw_packet);
/* Add new entry to the end */
if (!coap_op_dyn_resource_write(fp_new, session->proto,
resource_name, packet))
goto fail;
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)context->dyn_resource_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
/*
* Server has deleted a resource
*/
static int
coap_op_resource_deleted(coap_context_t *context,
coap_str_const_t *resource_name,
void *user_data) {
FILE *fp_orig = NULL;
FILE *fp_new = NULL;
char *new = NULL;
coap_proto_t e_proto;
coap_string_t *name = NULL;
coap_binary_t *raw_packet = NULL;
(void)user_data;
coap_op_obs_cnt_deleted(context, resource_name);
fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "r");
if (fp_orig == NULL)
return 1;
new = coap_malloc_type(COAP_STRING,
context->dyn_resource_save_file->length + 5);
if (!new)
goto fail;
strcpy(new, (const char *)context->dyn_resource_save_file->s);
strcat(new, ".tmp");
fp_new = fopen(new, "w+");
if (fp_new == NULL)
goto fail;
/* Go through and locate resource to delete and not copy it across */
while (1) {
if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
break;
if (!coap_string_equal(resource_name, name)) {
/* Copy across non-matching entry */
if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
(coap_bin_const_t *)raw_packet))
break;
}
coap_delete_string(name);
name = NULL;
coap_delete_binary(raw_packet);
raw_packet = NULL;
}
coap_delete_string(name);
coap_delete_binary(raw_packet);
if (fflush(fp_new) == EOF)
goto fail;
fclose(fp_new);
fclose(fp_orig);
/* Either old or new is in place */
(void)rename(new, (const char *)context->dyn_resource_save_file->s);
coap_free_type(COAP_STRING, new);
return 1;
fail:
if (fp_new)
fclose(fp_new);
if (fp_orig)
fclose(fp_orig);
if (new) {
(void)remove(new);
}
coap_free_type(COAP_STRING, new);
return 0;
}
int
coap_persist_startup(coap_context_t *context,
const char *dyn_resource_save_file,
const char *observe_save_file,
const char *obs_cnt_save_file,
uint32_t save_freq) {
if (dyn_resource_save_file) {
context->dyn_resource_save_file =
coap_new_bin_const((const uint8_t *)dyn_resource_save_file,
strlen(dyn_resource_save_file));
if (!context->dyn_resource_save_file)
return 0;
coap_op_dyn_resource_load_disk(context);
context->dyn_resource_added = coap_op_dyn_resource_added;
context->resource_deleted = coap_op_resource_deleted;
}
if (obs_cnt_save_file) {
context->obs_cnt_save_file =
coap_new_bin_const((const uint8_t *)obs_cnt_save_file,
strlen(obs_cnt_save_file));
if (!context->obs_cnt_save_file)
return 0;
context->observe_save_freq = save_freq ? save_freq : 1;
coap_op_obs_cnt_load_disk(context);
context->track_observe_value = coap_op_obs_cnt_track_observe;
context->resource_deleted = coap_op_resource_deleted;
}
if (observe_save_file) {
context->observe_save_file =
coap_new_bin_const((const uint8_t *)observe_save_file,
strlen(observe_save_file));
if (!context->observe_save_file)
return 0;
coap_op_observe_load_disk(context);
context->observe_added = coap_op_observe_added;
context->observe_deleted = coap_op_observe_deleted;
}
return 1;
}
void
coap_persist_cleanup(coap_context_t *context) {
coap_delete_bin_const(context->dyn_resource_save_file);
coap_delete_bin_const(context->obs_cnt_save_file);
coap_delete_bin_const(context->observe_save_file);
context->dyn_resource_save_file = NULL;
context->obs_cnt_save_file = NULL;
context->observe_save_file = NULL;
/* Close down any tracking */
coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
NULL, 0, NULL);
}
void
coap_persist_stop(coap_context_t *context) {
if (context == NULL)
return;
context->observe_no_clear = 1;
coap_persist_cleanup(context);
}
#else /* ! COAP_WITH_OBSERVE_PERSIST */
int
coap_persist_startup(coap_context_t *context,
const char *dyn_resource_save_file,
const char *observe_save_file,
const char *obs_cnt_save_file,
uint32_t save_freq) {
(void)context;
(void)dyn_resource_save_file;
(void)observe_save_file;
(void)obs_cnt_save_file;
(void)save_freq;
return 0;
}
void
coap_persist_stop(coap_context_t *context) {
context->observe_no_clear = 1;
/* Close down any tracking */
coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
NULL, 0, NULL);
}
#endif /* ! COAP_WITH_OBSERVE_PERSIST */
#endif /* COAP_SERVER_SUPPORT */
coap_internal.h
Pulls together all the internal only header files.
COAP_SESSION
@ COAP_SESSION
Definition coap_mem.h:50
COAP_STRING
@ COAP_STRING
Definition coap_mem.h:38
coap_malloc_type
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
coap_free_type
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
coap_opt_t
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition coap_option.h:26
coap_tick_t
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition coap_time.h:144
coap_get_resource_from_uri_path
coap_resource_t * coap_get_resource_from_uri_path(coap_context_t *context, coap_str_const_t *uri_path)
Returns the resource identified by the unique string uri_path.
coap_ticks
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
coap_decode_var_bytes
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition coap_encode.c:38
coap_log_debug
#define coap_log_debug(...)
Definition coap_debug.h:120
coap_log_warn
#define coap_log_warn(...)
Definition coap_debug.h:102
COAP_LOG_OSCORE
@ COAP_LOG_OSCORE
Definition coap_debug.h:59
coap_dyn_resource_added_t
int(* coap_dyn_resource_added_t)(coap_session_t *session, coap_str_const_t *resource_name, coap_bin_const_t *raw_packet, void *user_data)
Callback handler definition called when a dynamic resource is getting created, as defined in coap_per...
Definition coap_subscribe.h:141
coap_persist_stop
void coap_persist_stop(coap_context_t *context)
Stop tracking persist information, leaving the current persist information in the files defined in co...
coap_persist_set_observe_num
void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t observe_num)
Sets the current observe number value.
coap_resource_deleted_t
int(* coap_resource_deleted_t)(coap_context_t *context, coap_str_const_t *resource_name, void *user_data)
Callback handler definition called when resource is removed, as defined in coap_persist_track_funcs()...
Definition coap_subscribe.h:160
coap_observe_added_t
int(* coap_observe_added_t)(coap_session_t *session, coap_subscription_t *observe_key, coap_proto_t e_proto, coap_address_t *e_listen_addr, coap_addr_tuple_t *s_addr_info, coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info, void *user_data)
Callback handler definition called when a new observe has been set up, as defined in coap_persist_tra...
Definition coap_subscribe.h:84
COAP_OBSERVE_ESTABLISH
#define COAP_OBSERVE_ESTABLISH
The value COAP_OBSERVE_ESTABLISH in a GET/FETCH request option COAP_OPTION_OBSERVE indicates a new ob...
Definition coap_subscribe.h:33
coap_persist_track_funcs
void coap_persist_track_funcs(coap_context_t *context, coap_observe_added_t observe_added, coap_observe_deleted_t observe_deleted, coap_track_observe_value_t track_observe_value, coap_dyn_resource_added_t dyn_resource_added, coap_resource_deleted_t resource_deleted, uint32_t save_freq, void *user_data)
Set up callbacks to handle persist tracking so on a coap-server inadvertent restart,...
coap_track_observe_value_t
int(* coap_track_observe_value_t)(coap_context_t *context, coap_str_const_t *resource_name, uint32_t observe_num, void *user_data)
Callback handler definition called when an observe unsolicited response is being sent,...
Definition coap_subscribe.h:123
coap_observe_deleted_t
int(* coap_observe_deleted_t)(coap_session_t *session, coap_subscription_t *observe_key, void *user_data)
Callback handler definition called when an observe is being removed, as defined in coap_persist_track...
Definition coap_subscribe.h:104
coap_persist_startup
int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq)
Start up persist tracking using the libcoap module.
coap_persist_observe_add
coap_subscription_t * coap_persist_observe_add(coap_context_t *context, coap_proto_t e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info)
Set up an active subscription for an observe that was previously active over a coap-server inadvertan...
coap_opt_length
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition coap_option.c:212
coap_check_option
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition coap_option.c:199
coap_opt_value
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition coap_option.c:249
CBOR_BYTE_STRING
#define CBOR_BYTE_STRING
Definition oscore_cbor.h:62
oscore_cbor_get_element_size
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len)
Definition oscore_cbor.c:240
CBOR_NULL
#define CBOR_NULL
Definition oscore_cbor.h:72
CBOR_SIMPLE_VALUE
#define CBOR_SIMPLE_VALUE
Definition oscore_cbor.h:67
oscore_cbor_get_next_element
uint8_t oscore_cbor_get_next_element(const uint8_t **buffer, size_t *buf_len)
Definition oscore_cbor.c:227
CBOR_ARRAY
#define CBOR_ARRAY
Definition oscore_cbor.h:64
oscore_new_association
int oscore_new_association(coap_session_t *session, coap_pdu_t *sent_pdu, coap_bin_const_t *token, oscore_recipient_ctx_t *recipient_ctx, coap_bin_const_t *aad, coap_bin_const_t *nonce, coap_bin_const_t *partial_iv, int is_observe)
Definition oscore_context.c:686
oscore_log_hex_value
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
Definition oscore_context.c:235
oscore_find_context
oscore_ctx_t * oscore_find_context(const coap_context_t *c_context, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
Definition oscore_context.c:185
coap_delete_pdu
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition coap_pdu.c:163
coap_proto_t
coap_proto_t
CoAP protocol types.
Definition coap_pdu.h:304
coap_pdu_parse
int coap_pdu_parse(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition coap_pdu.c:1382
coap_pdu_init
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition coap_pdu.c:97
COAP_OPTION_OBSERVE
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:119
COAP_PROTO_UDP
@ COAP_PROTO_UDP
Definition coap_pdu.h:306
COAP_REQUEST_CODE_GET
@ COAP_REQUEST_CODE_GET
Definition coap_pdu.h:321
COAP_REQUEST_CODE_FETCH
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:325
coap_endpoint_get_session
coap_session_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Lookup the server session for the packet received on an endpoint, or create a new one.
coap_delete_bin_const
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition coap_str.c:120
coap_new_binary
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition coap_str.c:77
coap_new_bin_const
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition coap_str.c:110
coap_delete_binary
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition coap_str.c:105
coap_binary_equal
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition coap_str.h:203
coap_string_equal
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition coap_str.h:189
coap_new_string
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition coap_str.c:21
coap_delete_string
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition coap_str.c:46
coap_persist_cleanup
void coap_persist_cleanup(coap_context_t *context)
Close down persist tracking, releasing any memory used.
coap_subscription_init
void coap_subscription_init(coap_subscription_t *)
coap_add_observer
coap_subscription_t * coap_add_observer(coap_resource_t *resource, coap_session_t *session, const coap_bin_const_t *token, const coap_pdu_t *pdu)
Adds the specified peer as observer for resource.
coap_get_uri_path
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition coap_uri.c:769
coap_get_query
coap_string_t * coap_get_query(const coap_pdu_t *request)
Extract query string from request PDU according to escape rules in 6.5.8.
Definition coap_uri.c:718
coap_addr_tuple_t
Definition coap_io.h:55
coap_address_t
Multi-purpose address abstraction.
Definition coap_address.h:109
coap_bin_const_t
CoAP binary data definition with const data.
Definition coap_str.h:64
coap_bin_const_t::length
size_t length
length of binary data
Definition coap_str.h:65
coap_bin_const_t::s
const uint8_t * s
read-only binary data
Definition coap_str.h:66
coap_binary_t
CoAP binary data definition.
Definition coap_str.h:56
coap_binary_t::length
size_t length
length of binary data
Definition coap_str.h:57
coap_binary_t::s
uint8_t * s
binary data
Definition coap_str.h:58
coap_context_t
The CoAP stack's global state is stored in a coap_context_t object.
Definition coap_net_internal.h:49
coap_context_t::observe_added
coap_observe_added_t observe_added
Called when there is a new observe subscription request.
Definition coap_net_internal.h:109
coap_context_t::dyn_resource_added
coap_dyn_resource_added_t dyn_resource_added
Callback to save dynamic resource when created.
Definition coap_net_internal.h:118
coap_context_t::observe_user_data
void * observe_user_data
App provided data for use in observe_added or observe_deleted.
Definition coap_net_internal.h:113
coap_context_t::track_observe_value
coap_track_observe_value_t track_observe_value
Callback to save observe value when updated.
Definition coap_net_internal.h:116
coap_context_t::endpoint
coap_endpoint_t * endpoint
the endpoints used for listening
Definition coap_net_internal.h:75
coap_context_t::observe_save_freq
uint32_t observe_save_freq
How frequently to update observe value.
Definition coap_net_internal.h:115
coap_context_t::observe_no_clear
uint8_t observe_no_clear
Observe 4.04 not to be sent on deleting resource.
Definition coap_net_internal.h:186
coap_context_t::observe_deleted
coap_observe_deleted_t observe_deleted
Called when there is a observe subscription de-register request.
Definition coap_net_internal.h:111
coap_context_t::unknown_resource
coap_resource_t * unknown_resource
can be used for handling unknown resources
Definition coap_net_internal.h:54
coap_context_t::resource_deleted
coap_resource_deleted_t resource_deleted
Invoked when resource is deleted.
Definition coap_net_internal.h:120
coap_endpoint_t
Abstraction of virtual endpoint that can be attached to coap_context_t.
Definition coap_session_internal.h:219
coap_endpoint_t::next
struct coap_endpoint_t * next
Definition coap_session_internal.h:220
coap_endpoint_t::bind_addr
coap_address_t bind_addr
local interface address
Definition coap_session_internal.h:226
coap_endpoint_t::proto
coap_proto_t proto
protocol used on this interface
Definition coap_session_internal.h:222
coap_opt_iterator_t
Iterator to run through PDU options.
Definition coap_option.h:168
coap_packet_t
Definition coap_io_internal.h:207
coap_packet_t::length
size_t length
length of payload
Definition coap_io_internal.h:210
coap_packet_t::addr_info
coap_addr_tuple_t addr_info
local and remote addresses
Definition coap_io_internal.h:208
coap_packet_t::payload
unsigned char * payload
payload
Definition coap_io_internal.h:211
coap_packet_t::ifindex
int ifindex
the interface index
Definition coap_io_internal.h:209
coap_pdu_t
structure for CoAP PDUs
Definition coap_pdu_internal.h:119
coap_pdu_t::max_size
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
Definition coap_pdu_internal.h:137
coap_pdu_t::code
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
Definition coap_pdu_internal.h:121
coap_pdu_t::actual_token
coap_bin_const_t actual_token
Actual token in pdu.
Definition coap_pdu_internal.h:132
coap_pdu_t::used_size
size_t used_size
used bytes of storage for token, options and payload
Definition coap_pdu_internal.h:135
coap_resource_t
Abstraction of resource that can be attached to coap_context_t.
Definition coap_resource_internal.h:53
coap_resource_t::handler
coap_method_handler_t handler[7]
Used to store handlers for the seven coap methods GET, POST, PUT, DELETE, FETCH, PATCH and IPATCH.
Definition coap_resource_internal.h:69
coap_resource_t::observable
unsigned int observable
can be observed
Definition coap_resource_internal.h:57
coap_session_t
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
Definition coap_session_internal.h:68
coap_session_t::proto
coap_proto_t proto
protocol used
Definition coap_session_internal.h:69
coap_session_t::context
coap_context_t * context
session's context
Definition coap_session_internal.h:86
coap_str_const_t
CoAP string data definition with const data.
Definition coap_str.h:46
coap_str_const_t::s
const uint8_t * s
read-only string data
Definition coap_str.h:48
coap_str_const_t::length
size_t length
length of string
Definition coap_str.h:47
coap_string_t
CoAP string data definition.
Definition coap_str.h:38
coap_string_t::s
uint8_t * s
string data
Definition coap_str.h:40
coap_subscription_t
Number of notifications that may be sent non-confirmable before a confirmable message is sent to dete...
Definition coap_subscribe_internal.h:57
oscore_ctx_t
Definition oscore_context.h:84