20#define min(a,b) ((a) < (b) ? (a) : (b))
25#if COAP_SERVER_SUPPORT && COAP_WITH_OBSERVE_PERSIST
32#if COAP_SERVER_SUPPORT
48 context->observe_added_cb = observe_added;
49 context->observe_deleted_cb = observe_deleted;
50 context->observe_user_data = user_data;
51 context->observe_save_freq = save_freq ? save_freq : 1;
52 context->track_observe_value_cb = track_observe_value;
53 context->dyn_resource_added_cb = dyn_resource_added;
54 context->resource_deleted_cb = resource_deleted;
67 subs = coap_persist_observe_add_lkd(context,
88#if COAP_CONSTRAINED_STACK
105 if (e_listen_addr ==
NULL || s_addr_info ==
NULL || raw_packet ==
NULL)
112 ep = context->endpoint;
114 if (ep->proto == e_proto &&
115 memcmp(e_listen_addr, &ep->bind_addr,
sizeof(ep->bind_addr)) == 0)
121#ifndef INET6_ADDRSTRLEN
122#define INET6_ADDRSTRLEN 40
127 coap_log_warn(
"coap_persist_observe_add: Endpoint %s not defined\n",
140 data = raw_packet->
s;
141 data_len = raw_packet->
length;
148 session = coap_endpoint_get_session(ep, packet, now);
179 r = coap_get_resource_from_uri_path_lkd(session->
context,
182 coap_log_warn(
"coap_persist_observe_add: resource '%s' not defined\n",
186 if (!r->observable) {
187 coap_log_warn(
"coap_persist_observe_add: resource '%s' not observable\n",
196 s = coap_add_observer(r, session, &pdu->
actual_token, pdu);
200#if COAP_OSCORE_SUPPORT
217 const uint8_t *info_buf = oscore_info->
s;
218 size_t info_buf_len = oscore_info->
length;
226 int have_partial_iv = 0;
227 int have_id_context = 0;
242 oscore_key_id.
s = info_buf;
243 info_buf += oscore_key_id.
length;
250 id_context.
s = info_buf;
251 info_buf += id_context.
length;
277 partial_iv.
s = info_buf;
278 info_buf += partial_iv.
length;
301 have_id_context ? &id_context :
NULL,
NULL,
302 &session->recipient_ctx);
304 session->oscore_encryption = 1;
306 session->recipient_ctx,
307 have_aad ? &aad :
NULL,
308 have_nonce ? &nonce :
NULL,
309 have_partial_iv ? &partial_iv :
NULL,
313 have_partial_iv ? &partial_iv :
NULL);
324 coap_log_warn(
"coap_persist_observe_add: discard malformed PDU\n");
331#if COAP_WITH_OBSERVE_PERSIST
345 assert(fp && observe_key && e_proto && e_listen_addr && s_addr_info &&
346 raw_packet && oscore_info);
351 if (fread(observe_key,
sizeof(*observe_key), 1, fp) == 1) {
353 if (fread(e_proto,
sizeof(*e_proto), 1, fp) != 1)
355 if (fread(e_listen_addr,
sizeof(*e_listen_addr), 1, fp) != 1)
357 if (fread(s_addr_info,
sizeof(*s_addr_info), 1, fp) != 1)
359 if (fread(&size,
sizeof(size), 1, fp) != 1)
361 if (size < 0 || size > 0x10000)
364 if ((scratch) ==
NULL)
366 if (fread(scratch->
s, scratch->
length, 1, fp) != 1)
370 if (fread(&size,
sizeof(size), 1, fp) != 1)
375 else if (size < 0 || size > 0x10000)
381 if (fread(scratch->
s, scratch->
length, 1, fp) != 1)
392 memset(e_proto, 0,
sizeof(*e_proto));
393 memset(e_listen_addr, 0,
sizeof(*e_listen_addr));
394 memset(s_addr_info, 0,
sizeof(*s_addr_info));
407 if (fwrite(&observe_key,
sizeof(observe_key), 1, fp) != 1)
409 if (fwrite(&e_proto,
sizeof(e_proto), 1, fp) != 1)
411 if (fwrite(&e_listen_addr,
sizeof(e_listen_addr),
414 if (fwrite(&s_addr_info,
sizeof(s_addr_info), 1, fp) != 1)
416 if (fwrite(&raw_packet->
length,
sizeof(raw_packet->
length), 1, fp) != 1)
418 if (fwrite(raw_packet->
s, raw_packet->
length, 1, fp) != 1)
421 if (fwrite(&oscore_info->
length,
sizeof(oscore_info->
length), 1, fp) != 1)
423 if (fwrite(oscore_info->
s, oscore_info->
length, 1, fp) != 1)
426 ssize_t not_defined = -1;
428 if (fwrite(¬_defined,
sizeof(not_defined), 1, fp) != 1)
444 FILE *fp_orig = fopen((
const char *)ctx->observe_save_file->s,
"r");
461 strcpy(
new, (
const char *)ctx->observe_save_file->s);
463 fp_new = fopen(
new,
"w+");
469 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
470 &s_addr_info, &raw_packet, &oscore_info))
473 observe_key = coap_persist_observe_add_lkd(ctx, e_proto,
479 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
480 s_addr_info, raw_packet, oscore_info))
493 if (fflush(fp_new) == EOF)
498 if (rename(
new, (
const char *)ctx->observe_save_file->s) == -1) {
500 new, (
const char *)ctx->observe_save_file->s,
530 FILE *fp_orig = fopen((
const char *)session->
context->observe_save_file->s,
544 session->
context->observe_save_file->length + 5);
548 strcpy(
new, (
const char *)session->
context->observe_save_file->s);
550 fp_new = fopen(
new,
"w+");
556 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
557 &s_addr_info, &raw_packet, &oscore_info))
559 if (observe_key != a_observe_key) {
560 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
561 s_addr_info, raw_packet, oscore_info))
575 if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
576 *a_s_addr_info, a_raw_packet, a_oscore_info))
579 if (fflush(fp_new) == EOF)
585 (void)rename(
new, (
const char *)session->
context->observe_save_file->s);
610 FILE *fp_orig = fopen((
const char *)session->
context->observe_save_file->s,
626 session->
context->observe_save_file->length + 5);
630 strcpy(
new, (
const char *)session->
context->observe_save_file->s);
632 fp_new = fopen(
new,
"w+");
638 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
639 &s_addr_info, &raw_packet, &oscore_info))
641 if (observe_key != d_observe_key) {
642 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
657 if (fflush(fp_new) == EOF)
662 (void)rename(
new, (
const char *)session->
context->observe_save_file->s);
688 FILE *fp = fopen((
const char *)context->obs_cnt_save_file->s,
"r");
694 while (fgets(buf,
sizeof(buf), fp) !=
NULL) {
695 char *cp = strchr(buf,
' ');
697 uint32_t observe_num;
705 observe_num = atoi(cp);
710 observe_num = ((observe_num + context->observe_save_freq) /
711 context->observe_save_freq) *
712 context->observe_save_freq - 1;
713 resource_key.
s = (uint8_t *)buf;
714 resource_key.
length = strlen(buf);
715 r = coap_get_resource_from_uri_path_lkd(context, &resource_key);
717 coap_log_debug(
"persist: Initial observe number being updated '%s' %u\n",
733 uint32_t n_observe_num,
735 FILE *fp_orig = fopen((
const char *)context->obs_cnt_save_file->s,
"r");
746 strcpy(
new, (
const char *)context->obs_cnt_save_file->s);
748 fp_new = fopen(
new,
"w+");
753 while (fp_orig && fgets(buf,
sizeof(buf), fp_orig) !=
NULL) {
754 char *cp = strchr(buf,
' ');
755 uint32_t observe_num;
763 observe_num = atoi(cp);
764 resource_key.
s = (uint8_t *)buf;
765 resource_key.
length = strlen(buf);
767 if (fprintf(fp_new,
"%s %u\n", resource_key.
s, observe_num) < 0)
771 if (fprintf(fp_new,
"%s %u\n", resource_name->
s, n_observe_num) < 0)
773 if (fflush(fp_new) == EOF)
779 (void)rename(
new, (
const char *)context->obs_cnt_save_file->s);
801 FILE *fp_orig = fopen((
const char *)context->obs_cnt_save_file->s,
"r");
812 strcpy(
new, (
const char *)context->obs_cnt_save_file->s);
814 fp_new = fopen(
new,
"w+");
819 while (fgets(buf,
sizeof(buf), fp_orig) !=
NULL) {
820 char *cp = strchr(buf,
' ');
821 uint32_t observe_num;
829 observe_num = atoi(cp);
830 resource_key.
s = (uint8_t *)buf;
831 resource_key.
length = strlen(buf);
833 if (fprintf(fp_new,
"%s %u\n", resource_key.
s, observe_num) < 0)
837 if (fflush(fp_new) == EOF)
842 (void)rename(
new, (
const char *)context->obs_cnt_save_file->s);
863coap_op_dyn_resource_read(FILE *fp,
coap_proto_t *e_proto,
871 if (fread(e_proto,
sizeof(*e_proto), 1, fp) == 1) {
873 if (fread(&size,
sizeof(size), 1, fp) != 1)
875 if (size < 0 || size > 0x10000)
880 if (fread((*name)->s, size, 1, fp) != 1)
882 if (fread(&size,
sizeof(size), 1, fp) != 1)
884 if (size < 0 || size > 0x10000)
889 if (fread((*raw_packet)->s, size, 1, fp) != 1)
901coap_op_dyn_resource_write(FILE *fp,
coap_proto_t e_proto,
904 if (fwrite(&e_proto,
sizeof(e_proto), 1, fp) != 1)
906 if (fwrite(&name->
length,
sizeof(name->
length), 1, fp) != 1)
908 if (fwrite(name->
s, name->
length, 1, fp) != 1)
910 if (fwrite(&raw_packet->
length,
sizeof(raw_packet->
length), 1, fp) != 1)
912 if (fwrite(raw_packet->
s, raw_packet->
length, 1, fp) != 1)
927 FILE *fp_orig =
NULL;
940 fp_orig = fopen((
const char *)ctx->dyn_resource_save_file->s,
"r");
952 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
958 coap_log_debug(
"persist: dynamic resource '%s' being re-created\n", name->
s);
967 session->
proto = e_proto;
969 raw_packet->
length, request)) {
972 r = ctx->unknown_resource;
977 ctx->unknown_pdu = request;
978 ctx->unknown_session = session;
980 ctx->unknown_pdu =
NULL;
981 ctx->unknown_session =
NULL;
984 if (!r || !r->handler[request->
code-1])
1028 FILE *fp_new =
NULL;
1037 fp_orig = fopen((
const char *)context->dyn_resource_save_file->s,
"a");
1038 if (fp_orig ==
NULL)
1042 context->dyn_resource_save_file->length + 5);
1046 strcpy(
new, (
const char *)context->dyn_resource_save_file->s);
1047 strcat(
new,
".tmp");
1048 fp_new = fopen(
new,
"w+");
1054 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1070 if (!coap_op_dyn_resource_write(fp_new, session->
proto,
1071 resource_name, packet))
1074 if (fflush(fp_new) == EOF)
1079 (void)rename(
new, (
const char *)context->dyn_resource_save_file->s);
1102 FILE *fp_orig =
NULL;
1103 FILE *fp_new =
NULL;
1110 coap_op_obs_cnt_deleted(context, resource_name);
1112 fp_orig = fopen((
const char *)context->dyn_resource_save_file->s,
"r");
1113 if (fp_orig ==
NULL)
1117 context->dyn_resource_save_file->length + 5);
1121 strcpy(
new, (
const char *)context->dyn_resource_save_file->s);
1122 strcat(
new,
".tmp");
1123 fp_new = fopen(
new,
"w+");
1129 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1145 if (fflush(fp_new) == EOF)
1150 (void)rename(
new, (
const char *)context->dyn_resource_save_file->s);
1168 const char *dyn_resource_save_file,
1169 const char *observe_save_file,
1170 const char *obs_cnt_save_file,
1171 uint32_t save_freq) {
1175 ret = coap_persist_startup_lkd(context,
1176 dyn_resource_save_file,
1186 const char *dyn_resource_save_file,
1187 const char *observe_save_file,
1188 const char *obs_cnt_save_file,
1189 uint32_t save_freq) {
1191 if (dyn_resource_save_file) {
1192 context->dyn_resource_save_file =
1194 strlen(dyn_resource_save_file));
1195 if (!context->dyn_resource_save_file)
1197 coap_op_dyn_resource_load_disk(context);
1198 context->dyn_resource_added_cb = coap_op_dyn_resource_added;
1199 context->resource_deleted_cb = coap_op_resource_deleted;
1201 if (obs_cnt_save_file) {
1202 context->obs_cnt_save_file =
1204 strlen(obs_cnt_save_file));
1205 if (!context->obs_cnt_save_file)
1207 context->observe_save_freq = save_freq ? save_freq : 1;
1208 coap_op_obs_cnt_load_disk(context);
1209 context->track_observe_value_cb = coap_op_obs_cnt_track_observe;
1210 context->resource_deleted_cb = coap_op_resource_deleted;
1212 if (observe_save_file) {
1213 context->observe_save_file =
1215 strlen(observe_save_file));
1216 if (!context->observe_save_file)
1218 coap_op_observe_load_disk(context);
1219 context->observe_added_cb = coap_op_observe_added;
1220 context->observe_deleted_cb = coap_op_observe_deleted;
1230 context->dyn_resource_save_file =
NULL;
1231 context->obs_cnt_save_file =
NULL;
1232 context->observe_save_file =
NULL;
1244 coap_persist_stop_lkd(context);
1250 if (context ==
NULL)
1253 context->observe_no_clear = 1;
1254 coap_persist_cleanup(context);
1259 const char *dyn_resource_save_file,
1260 const char *observe_save_file,
1261 const char *obs_cnt_save_file,
1262 uint32_t save_freq) {
1264 (void)dyn_resource_save_file;
1265 (void)observe_save_file;
1266 (void)obs_cnt_save_file;
1273 context->observe_no_clear = 1;
struct coap_endpoint_t coap_endpoint_t
struct coap_subscription_t coap_subscription_t
struct coap_resource_t coap_resource_t
const char * coap_socket_strerror(void)
Library specific build wrapper for coap_internal.h.
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.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
void coap_ticks(coap_tick_t *t)
Returns the current value of an internal tick counter.
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
#define coap_lock_callback_ret(r, func)
Dummy for no thread-safe code.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_callback_release(func, failed)
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
coap_log_t coap_get_log_level(void)
Get the current logging level.
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
#define coap_log_warn(...)
COAP_API 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...
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...
void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t observe_num)
Sets the current observe number value.
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()...
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...
#define COAP_OBSERVE_ESTABLISH
The value COAP_OBSERVE_ESTABLISH in a GET/FETCH request option COAP_OPTION_OBSERVE indicates a new ob...
COAP_API void coap_persist_stop(coap_context_t *context)
Stop tracking persist information, leaving the current persist information in the files defined in co...
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,...
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,...
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...
COAP_API 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.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given 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.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_size)
#define CBOR_SIMPLE_VALUE
uint8_t oscore_cbor_get_next_element(const uint8_t **buffer, size_t *buf_size)
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)
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
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)
void coap_delete_pdu_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
coap_proto_t
CoAP protocol types Note: coap_layers_coap[] needs updating if extended.
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.
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.
#define COAP_OPTION_OBSERVE
@ COAP_REQUEST_CODE_FETCH
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
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...
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
int coap_observe_persist_is_supported(void)
Check whether Observe Persist is available.
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
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.
Multi-purpose address abstraction.
CoAP binary data definition with const data.
size_t length
length of binary data
const uint8_t * s
read-only binary data
CoAP binary data definition.
size_t length
length of binary data
The CoAP stack's global state is stored in a coap_context_t object.
uint32_t dynamic_cur
Current number of dynamic resources.
coap_resource_dynamic_create_t dyn_create_handler
Dynamc resource create handler.
uint32_t dynamic_max
Max number of dynamic resources or 0 is unlimited.
Iterator to run through PDU options.
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
int ifindex
the interface index
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
coap_bin_const_t actual_token
Actual token in pdu.
size_t used_size
used bytes of storage for token, options and payload
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_proto_t proto
protocol used
coap_context_t * context
session's context
CoAP string data definition with const data.
const uint8_t * s
read-only string data
size_t length
length of string
CoAP string data definition.