libcoap  4.3.0
resource.c
Go to the documentation of this file.
1 /* resource.c -- generic resource handling
2  *
3  * Copyright (C) 2010--2021 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * This file is part of the CoAP library libcoap. Please see
8  * README for terms of use.
9  */
10 
11 #include "coap3/coap_internal.h"
12 
13 #include <stdio.h>
14 #include <errno.h>
15 
16 #ifdef COAP_EPOLL_SUPPORT
17 #include <sys/epoll.h>
18 #include <sys/timerfd.h>
19 #endif /* COAP_EPOLL_SUPPORT */
20 
21 #if defined(WITH_LWIP)
22 /* mem.h is only needed for the string free calls for
23  * COAP_ATTR_FLAGS_RELEASE_NAME / COAP_ATTR_FLAGS_RELEASE_VALUE /
24  * COAP_RESOURCE_FLAGS_RELEASE_URI. not sure what those lines should actually
25  * do on lwip. */
26 
27 #include <lwip/memp.h>
28 
29 #define COAP_MALLOC_TYPE(Type) \
30  ((coap_##Type##_t *)memp_malloc(MEMP_COAP_##Type))
31 #define COAP_FREE_TYPE(Type, Object) memp_free(MEMP_COAP_##Type, Object)
32 
33 #elif defined(WITH_CONTIKI)
34 #include "memb.h"
35 
36 #define COAP_MALLOC_TYPE(Type) \
37  ((coap_##Type##_t *)memb_alloc(&(Type##_storage)))
38 #define COAP_FREE_TYPE(Type, Object) memb_free(&(Type##_storage), (Object))
39 
40 MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS);
41 
42 void
43 coap_resources_init() {
44  memb_init(&subscription_storage);
45 }
46 
48 coap_malloc_subscription() {
49  return memb_alloc(&subscription_storage);
50 }
51 
53 coap_free_subscription(coap_subscription_t *subscription) {
54  memb_free(&subscription_storage, subscription);
55 }
56 
57 #else
58 #define COAP_MALLOC_TYPE(Type) \
59  ((coap_##Type##_t *)coap_malloc(sizeof(coap_##Type##_t)))
60 #define COAP_FREE_TYPE(Type, Object) coap_free(Object)
61 #endif
62 
63 #define COAP_PRINT_STATUS_MAX (~COAP_PRINT_STATUS_MASK)
64 
65 #ifndef min
66 #define min(a,b) ((a) < (b) ? (a) : (b))
67 #endif
68 
69 /* Helper functions for conditional output of character sequences into
70  * a given buffer. The first Offset characters are skipped.
71  */
72 
77 #define PRINT_WITH_OFFSET(Buf,Offset,Char) \
78  if ((Offset) == 0) { \
79  (*(Buf)++) = (Char); \
80  } else { \
81  (Offset)--; \
82  } \
83 
87 #define PRINT_COND_WITH_OFFSET(Buf,Bufend,Offset,Char,Result) { \
88  if ((Buf) < (Bufend)) { \
89  PRINT_WITH_OFFSET(Buf,Offset,Char); \
90  } \
91  (Result)++; \
92  }
93 
99 #define COPY_COND_WITH_OFFSET(Buf,Bufend,Offset,Str,Length,Result) { \
100  size_t i; \
101  for (i = 0; i < (Length); i++) { \
102  PRINT_COND_WITH_OFFSET((Buf), (Bufend), (Offset), (Str)[i], (Result)); \
103  } \
104  }
105 
106 static int
107 match(const coap_str_const_t *text, const coap_str_const_t *pattern, int match_prefix,
108  int match_substring
109 ) {
110  assert(text); assert(pattern);
111 
112  if (text->length < pattern->length)
113  return 0;
114 
115  if (match_substring) {
116  const uint8_t *next_token = text->s;
117  size_t remaining_length = text->length;
118  while (remaining_length) {
119  size_t token_length;
120  const uint8_t *token = next_token;
121  next_token = (unsigned char *)memchr(token, ' ', remaining_length);
122 
123  if (next_token) {
124  token_length = next_token - token;
125  remaining_length -= (token_length + 1);
126  next_token++;
127  } else {
128  token_length = remaining_length;
129  remaining_length = 0;
130  }
131 
132  if ((match_prefix || pattern->length == token_length) &&
133  memcmp(token, pattern->s, pattern->length) == 0)
134  return 1;
135  }
136  return 0;
137  }
138 
139  return (match_prefix || pattern->length == text->length) &&
140  memcmp(text->s, pattern->s, pattern->length) == 0;
141 }
142 
164 #if defined(__GNUC__) && defined(WITHOUT_QUERY_FILTER)
166 coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen,
167  size_t offset,
168  coap_opt_t *query_filter COAP_UNUSED) {
169 #else /* not a GCC */
171 coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen,
172  size_t offset, coap_opt_t *query_filter) {
173 #endif /* GCC */
174  size_t output_length = 0;
175  unsigned char *p = buf;
176  const uint8_t *bufend = buf + *buflen;
177  size_t left, written = 0;
178  coap_print_status_t result;
179  const size_t old_offset = offset;
180  int subsequent_resource = 0;
181 #ifndef WITHOUT_QUERY_FILTER
182  coap_str_const_t resource_param = { 0, NULL }, query_pattern = { 0, NULL };
183  int flags = 0; /* MATCH_SUBSTRING, MATCH_PREFIX, MATCH_URI */
184 #define MATCH_URI 0x01
185 #define MATCH_PREFIX 0x02
186 #define MATCH_SUBSTRING 0x04
187  static const coap_str_const_t _rt_attributes[] = {
188  {2, (const uint8_t *)"rt"},
189  {2, (const uint8_t *)"if"},
190  {3, (const uint8_t *)"rel"},
191  {0, NULL}};
192 #endif /* WITHOUT_QUERY_FILTER */
193 
194 #ifndef WITHOUT_QUERY_FILTER
195  /* split query filter, if any */
196  if (query_filter) {
197  resource_param.s = coap_opt_value(query_filter);
198  while (resource_param.length < coap_opt_length(query_filter)
199  && resource_param.s[resource_param.length] != '=')
200  resource_param.length++;
201 
202  if (resource_param.length < coap_opt_length(query_filter)) {
203  const coap_str_const_t *rt_attributes;
204  if (resource_param.length == 4 &&
205  memcmp(resource_param.s, "href", 4) == 0)
206  flags |= MATCH_URI;
207 
208  for (rt_attributes = _rt_attributes; rt_attributes->s; rt_attributes++) {
209  if (resource_param.length == rt_attributes->length &&
210  memcmp(resource_param.s, rt_attributes->s, rt_attributes->length) == 0) {
211  flags |= MATCH_SUBSTRING;
212  break;
213  }
214  }
215 
216  /* rest is query-pattern */
217  query_pattern.s =
218  coap_opt_value(query_filter) + resource_param.length + 1;
219 
220  assert((resource_param.length + 1) <= coap_opt_length(query_filter));
221  query_pattern.length =
222  coap_opt_length(query_filter) - (resource_param.length + 1);
223 
224  if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) {
225  query_pattern.s++;
226  query_pattern.length--;
227  }
228 
229  if (query_pattern.length &&
230  query_pattern.s[query_pattern.length-1] == '*') {
231  query_pattern.length--;
232  flags |= MATCH_PREFIX;
233  }
234  }
235  }
236 #endif /* WITHOUT_QUERY_FILTER */
237 
238  RESOURCES_ITER(context->resources, r) {
239 
240 #ifndef WITHOUT_QUERY_FILTER
241  if (resource_param.length) { /* there is a query filter */
242 
243  if (flags & MATCH_URI) { /* match resource URI */
244  if (!match(r->uri_path, &query_pattern, (flags & MATCH_PREFIX) != 0,
245  (flags & MATCH_SUBSTRING) != 0))
246  continue;
247  } else { /* match attribute */
248  coap_attr_t *attr;
249  coap_str_const_t unquoted_val;
250  attr = coap_find_attr(r, &resource_param);
251  if (!attr || !attr->value) continue;
252  unquoted_val = *attr->value;
253  if (attr->value->s[0] == '"') { /* if attribute has a quoted value, remove double quotes */
254  unquoted_val.length -= 2;
255  unquoted_val.s += 1;
256  }
257  if (!(match(&unquoted_val, &query_pattern,
258  (flags & MATCH_PREFIX) != 0,
259  (flags & MATCH_SUBSTRING) != 0)))
260  continue;
261  }
262  }
263 #endif /* WITHOUT_QUERY_FILTER */
264 
265  if (!subsequent_resource) { /* this is the first resource */
266  subsequent_resource = 1;
267  } else {
268  PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written);
269  }
270 
271  left = bufend - p; /* calculate available space */
272  result = coap_print_link(r, p, &left, &offset);
273 
274  if (result & COAP_PRINT_STATUS_ERROR) {
275  break;
276  }
277 
278  /* coap_print_link() returns the number of characters that
279  * where actually written to p. Now advance to its end. */
280  p += COAP_PRINT_OUTPUT_LENGTH(result);
281  written += left;
282  }
283 
284  *buflen = written;
285  output_length = p - buf;
286 
287  if (output_length > COAP_PRINT_STATUS_MAX) {
289  }
290 
291  result = (coap_print_status_t)output_length;
292 
293  if (result + old_offset - offset < *buflen) {
294  result |= COAP_PRINT_STATUS_TRUNC;
295  }
296  return result;
297 }
298 
299 static coap_str_const_t null_path_value = {0, (const uint8_t*)""};
301 
303 coap_resource_init(coap_str_const_t *uri_path, int flags) {
304  coap_resource_t *r;
305 
307  if (r) {
308  memset(r, 0, sizeof(coap_resource_t));
309 
310  if (!(flags & COAP_RESOURCE_FLAGS_RELEASE_URI)) {
311  /* Need to take a copy if caller is not providing a release request */
312  if (uri_path)
313  uri_path = coap_new_str_const(uri_path->s, uri_path->length);
314  else
316  }
317  else if (!uri_path) {
318  /* Do not expecte this, but ... */
320  }
321 
322  if (uri_path)
323  r->uri_path = uri_path;
324 
325  r->flags = flags;
326  } else {
327  coap_log(LOG_DEBUG, "coap_resource_init: no memory left\n");
328  }
329 
330  return r;
331 }
332 
333 static const uint8_t coap_unknown_resource_uri[] =
334  "- Unknown -";
335 
338  coap_resource_t *r;
339 
341  if (r) {
342  memset(r, 0, sizeof(coap_resource_t));
343  r->is_unknown = 1;
344  /* Something unlikely to be used, but it shows up in the logs */
346  coap_register_handler(r, COAP_REQUEST_PUT, put_handler);
347  } else {
348  coap_log(LOG_DEBUG, "coap_resource_unknown_init: no memory left\n");
349  }
350 
351  return r;
352 }
353 
354 static const uint8_t coap_proxy_resource_uri[] =
355  "- Proxy URI -";
356 
359  size_t host_name_count, const char *host_name_list[]) {
360  coap_resource_t *r;
361 
362  if (host_name_count == 0) {
364  "coap_resource_proxy_uri_init: Must have one or more host names defined\n");
365  return NULL;
366  }
368  if (r) {
369  size_t i;
370  memset(r, 0, sizeof(coap_resource_t));
371  r->is_proxy_uri = 1;
372  /* Something unlikely to be used, but it shows up in the logs */
374  /* Preset all the handlers */
375  for (i = 0; i < (sizeof(r->handler) / sizeof(r->handler[0])); i++) {
376  r->handler[i] = handler;
377  }
378  if (host_name_count) {
379  r->proxy_name_list = coap_malloc(host_name_count *
380  sizeof(coap_str_const_t*));
381  if (r->proxy_name_list) {
382  for (i = 0; i < host_name_count; i++) {
383  r->proxy_name_list[i] =
384  coap_new_str_const((const uint8_t*)host_name_list[i],
385  strlen(host_name_list[i]));
386  if (!r->proxy_name_list[i]) {
388  "coap_resource_proxy_uri_init: unable to add host name\n");
389  if (i == 0) {
391  r->proxy_name_list = NULL;
392  }
393  break;
394  }
395  }
396  r->proxy_name_count = i;
397  }
398  }
399  } else {
400  coap_log(LOG_DEBUG, "coap_resource_proxy_uri_init: no memory left\n");
401  }
402 
403  return r;
404 }
405 
406 coap_attr_t *
408  coap_str_const_t *name,
409  coap_str_const_t *val,
410  int flags) {
411  coap_attr_t *attr;
412 
413  if (!resource || !name)
414  return NULL;
415 
417 
418  if (attr) {
419  if (!(flags & COAP_ATTR_FLAGS_RELEASE_NAME)) {
420  /* Need to take a copy if caller is not providing a release request */
421  name = coap_new_str_const(name->s, name->length);
422  }
423  attr->name = name;
424  if (val) {
425  if (!(flags & COAP_ATTR_FLAGS_RELEASE_VALUE)) {
426  /* Need to take a copy if caller is not providing a release request */
427  val = coap_new_str_const(val->s, val->length);
428  }
429  }
430  attr->value = val;
431 
432  attr->flags = flags;
433 
434  /* add attribute to resource list */
435  LL_PREPEND(resource->link_attr, attr);
436  } else {
437  coap_log(LOG_DEBUG, "coap_add_attr: no memory left\n");
438  }
439 
440  return attr;
441 }
442 
443 coap_attr_t *
445  coap_str_const_t *name) {
446  coap_attr_t *attr;
447 
448  if (!resource || !name)
449  return NULL;
450 
451  LL_FOREACH(resource->link_attr, attr) {
452  if (attr->name->length == name->length &&
453  memcmp(attr->name->s, name->s, name->length) == 0)
454  return attr;
455  }
456 
457  return NULL;
458 }
459 
462  if (attr)
463  return attr->value;
464  return NULL;
465 }
466 
467 void
469  if (!attr)
470  return;
472  if (attr->value) {
474  }
475 
476 #ifdef WITH_LWIP
477  memp_free(MEMP_COAP_RESOURCEATTR, attr);
478 #endif
479 #ifndef WITH_LWIP
481 #endif
482 }
483 
488 
489 static void coap_notify_observers(coap_context_t *context, coap_resource_t *r,
490  coap_deleting_resource_t deleting);
491 
492 static void
494  coap_attr_t *attr, *tmp;
495  coap_subscription_t *obs, *otmp;
496 
497  assert(resource);
498 
499  coap_resource_notify_observers(resource, NULL);
501 
502  if (resource->context->release_userdata && resource->user_data)
503  resource->context->release_userdata(resource->user_data);
504 
505  /* delete registered attributes */
506  LL_FOREACH_SAFE(resource->link_attr, attr, tmp) coap_delete_attr(attr);
507 
508  /* Either the application provided or libcoap copied - need to delete it */
509  coap_delete_str_const(resource->uri_path);
510 
511  /* free all elements from resource->subscribers */
512  LL_FOREACH_SAFE( resource->subscribers, obs, otmp ) {
514  coap_delete_pdu(obs->pdu);
516  COAP_FREE_TYPE( subscription, obs );
517  }
518  if (resource->proxy_name_count && resource->proxy_name_list) {
519  size_t i;
520 
521  for (i = 0; i < resource->proxy_name_count; i++) {
523  }
524  coap_free(resource->proxy_name_list);
525  }
526 
527 #ifdef WITH_LWIP
528  memp_free(MEMP_COAP_RESOURCE, resource);
529 #endif
530 #ifndef WITH_LWIP
531  coap_free_type(COAP_RESOURCE, resource);
532 #endif /* WITH_CONTIKI */
533 }
534 
535 void
537  if (resource->is_unknown) {
538  if (context->unknown_resource)
540  context->unknown_resource = resource;
541  }
542  else if (resource->is_proxy_uri) {
543  if (context->proxy_uri_resource)
545  context->proxy_uri_resource = resource;
546  }
547  else {
549  resource->uri_path);
550 
551  if (r) {
553  "coap_add_resource: Duplicate uri_path '%*.*s', old resource deleted\n",
554  (int)resource->uri_path->length, (int)resource->uri_path->length,
555  resource->uri_path->s);
556  coap_delete_resource(context, r);
557  }
558  RESOURCES_ADD(context->resources, resource);
559  }
560  assert(resource->context == NULL);
561  resource->context = context;
562 }
563 
564 int
566  if (!context || !resource)
567  return 0;
568 
569  if (resource->is_unknown && (context->unknown_resource == resource)) {
571  context->unknown_resource = NULL;
572  return 1;
573  }
574  if (resource->is_proxy_uri && (context->proxy_uri_resource == resource)) {
576  context->proxy_uri_resource = NULL;
577  return 1;
578  }
579 
580  /* remove resource from list */
581  RESOURCES_DELETE(context->resources, resource);
582 
583  /* and free its allocated memory */
584  coap_free_resource(resource);
585 
586  return 1;
587 }
588 
589 void
591  coap_resource_t *res;
592  coap_resource_t *rtmp;
593 
594  /* Cannot call RESOURCES_ITER because coap_free_resource() releases
595  * the allocated storage. */
596 
597  HASH_ITER(hh, context->resources, res, rtmp) {
598  HASH_DELETE(hh, context->resources, res);
599  coap_free_resource(res);
600  }
601 
602  context->resources = NULL;
603 
604  if (context->unknown_resource) {
606  context->unknown_resource = NULL;
607  }
608  if (context->proxy_uri_resource) {
610  context->proxy_uri_resource = NULL;
611  }
612 }
613 
616  coap_resource_t *result;
617 
618  RESOURCES_FIND(context->resources, uri_path, result);
619 
620  return result;
621 }
622 
625  unsigned char *buf, size_t *len, size_t *offset) {
626  unsigned char *p = buf;
627  const uint8_t *bufend = buf + *len;
628  coap_attr_t *attr;
629  coap_print_status_t result = 0;
630  size_t output_length = 0;
631  const size_t old_offset = *offset;
632 
633  *len = 0;
634  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '<', *len);
635  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '/', *len);
636 
637  COPY_COND_WITH_OFFSET(p, bufend, *offset,
638  resource->uri_path->s, resource->uri_path->length, *len);
639 
640  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len);
641 
642  LL_FOREACH(resource->link_attr, attr) {
643 
644  PRINT_COND_WITH_OFFSET(p, bufend, *offset, ';', *len);
645 
646  COPY_COND_WITH_OFFSET(p, bufend, *offset,
647  attr->name->s, attr->name->length, *len);
648 
649  if (attr->value && attr->value->s) {
650  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '=', *len);
651 
652  COPY_COND_WITH_OFFSET(p, bufend, *offset,
653  attr->value->s, attr->value->length, *len);
654  }
655 
656  }
657  if (resource->observable) {
658  COPY_COND_WITH_OFFSET(p, bufend, *offset, ";obs", 4, *len);
659  }
660 
661  output_length = p - buf;
662 
663  if (output_length > COAP_PRINT_STATUS_MAX) {
665  }
666 
667  result = (coap_print_status_t)output_length;
668 
669  if (result + old_offset - *offset < *len) {
670  result |= COAP_PRINT_STATUS_TRUNC;
671  }
672 
673  return result;
674 }
675 
676 void
678  coap_request_t method,
679  coap_method_handler_t handler) {
680  assert(resource);
681  assert(method > 0 && (size_t)(method-1) < sizeof(resource->handler)/sizeof(coap_method_handler_t));
682  resource->handler[method-1] = handler;
683 }
684 
687  const coap_binary_t *token) {
689 
690  assert(resource);
691  assert(session);
692 
693  LL_FOREACH(resource->subscribers, s) {
694  if (s->session == session
695  && (!token || (token->length == s->pdu->token_length
696  && memcmp(token->s, s->pdu->token, token->length) == 0)))
697  return s;
698  }
699 
700  return NULL;
701 }
702 
703 static coap_subscription_t *
705  const coap_cache_key_t *cache_key) {
707 
708  assert(resource);
709  assert(session);
710 
711  LL_FOREACH(resource->subscribers, s) {
712  if (s->session == session
713  && (memcmp(cache_key, &s->cache_key, sizeof(s->cache_key)) == 0))
714  return s;
715  }
716 
717  return NULL;
718 }
719 
722  coap_session_t *session,
723  const coap_binary_t *token,
724  const coap_pdu_t *request) {
726  coap_cache_key_t *cache_key = NULL;
727  size_t len;
728  const uint8_t *data;
729 /* https://tools.ietf.org/html/rfc7641#section-3.6 */
730 static const uint16_t cache_ignore_options[] = { COAP_OPTION_ETAG };
731 
732  assert( session );
733 
734  /* Check if there is already a subscription for this peer. */
735  s = coap_find_observer(resource, session, token);
736  if (!s) {
737  /*
738  * Cannot allow a duplicate to be created for the same query as application
739  * may not be cleaning up duplicates. If duplicate found, then original
740  * observer is deleted and a new one created with the new token
741  */
742  cache_key = coap_cache_derive_key_w_ignore(session, request,
744  cache_ignore_options,
745  sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
746  s = coap_find_observer_cache_key(resource, session, cache_key);
747  if (s) {
748  /* Delete old entry with old token */
749  coap_binary_t tmp_token = { s->pdu->token_length, s->pdu->token };
750  coap_delete_observer(resource, session, &tmp_token);
751  s = NULL;
752  }
753  }
754 
755  /* We are done if subscription was found. */
756  if (s) {
757  return s;
758  }
759 
760  /* Create a new subscription */
761  s = COAP_MALLOC_TYPE(subscription);
762 
763  if (!s) {
764  coap_delete_cache_key(cache_key);
765  return NULL;
766  }
767 
769  s->pdu = coap_pdu_duplicate(request, session, request->token_length,
770  request->token, NULL);
771  if (s->pdu == NULL) {
772  coap_delete_cache_key(cache_key);
773  COAP_FREE_TYPE(subscription, s);
774  return NULL;
775  }
776  if (coap_get_data(request, &len, &data)) {
777  coap_add_data(s->pdu, len, data);
778  }
779  if (cache_key == NULL) {
780  cache_key = coap_cache_derive_key_w_ignore(session, request,
782  cache_ignore_options,
783  sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
784  if (cache_key == NULL) {
785  coap_delete_pdu(s->pdu);
786  coap_delete_cache_key(cache_key);
787  COAP_FREE_TYPE(subscription, s);
788  return NULL;
789  }
790  }
791  s->cache_key = cache_key;
792  s->session = coap_session_reference(session);
793 
794  /* add subscriber to resource */
795  LL_PREPEND(resource->subscribers, s);
796 
797  coap_log(LOG_DEBUG, "create new subscription\n");
798 
799  return s;
800 }
801 
802 void
804  const coap_binary_t *token) {
806 
807  RESOURCES_ITER(context->resources, r) {
808  s = coap_find_observer(r, session, token);
809  if (s) {
810  s->fail_cnt = 0;
811  }
812  }
813 }
814 
815 int
817  const coap_binary_t *token) {
819 
820  s = coap_find_observer(resource, session, token);
821 
822  if ( s && coap_get_log_level() >= LOG_DEBUG ) {
823  char outbuf[2 * 8 + 1] = "";
824  unsigned int i;
825  for ( i = 0; i < s->pdu->token_length; i++ )
826  snprintf( &outbuf[2 * i], 3, "%02x", s->pdu->token[i] );
827  coap_log(LOG_DEBUG, "removed observer with token '%s'\n", outbuf);
828  }
829 
830  if (resource->subscribers && s) {
831  LL_DELETE(resource->subscribers, s);
832  coap_session_release( session );
833  coap_delete_pdu(s->pdu);
835  COAP_FREE_TYPE(subscription,s);
836  }
837 
838  return s != NULL;
839 }
840 
841 void
843  RESOURCES_ITER(context->resources, resource) {
844  coap_subscription_t *s, *tmp;
845  LL_FOREACH_SAFE(resource->subscribers, s, tmp) {
846  if (s->session == session) {
847  LL_DELETE(resource->subscribers, s);
848  coap_session_release(session);
849  coap_delete_pdu(s->pdu);
851  COAP_FREE_TYPE(subscription, s);
852  }
853  }
854  }
855 }
856 
857 static void
859  coap_deleting_resource_t deleting) {
861  coap_subscription_t *obs;
862  coap_binary_t token;
863  coap_pdu_t *response;
864  uint8_t buf[4];
865  coap_string_t *query;
866  coap_block_t block;
867 
868  if (r->observable && (r->dirty || r->partiallydirty)) {
869  r->partiallydirty = 0;
870 
871  LL_FOREACH(r->subscribers, obs) {
872  if (r->dirty == 0 && obs->dirty == 0) {
873  /*
874  * running this resource due to partiallydirty, but this observation's
875  * notification was already enqueued
876  */
877  context->observe_pending = 1;
878  continue;
879  }
880  if (obs->session->con_active >= COAP_DEFAULT_NSTART &&
882  (obs->non_cnt >= COAP_OBS_MAX_NON))) {
883  r->partiallydirty = 1;
884  obs->dirty = 1;
885  context->observe_pending = 1;
886  continue;
887  }
888 
890  obs->dirty = 0;
891  /* initialize response */
893  if (!response) {
894  obs->dirty = 1;
895  r->partiallydirty = 1;
896  context->observe_pending = 1;
898  "coap_check_notify: pdu init failed, resource stays "
899  "partially dirty\n");
900  continue;
901  }
902 
903  if (!coap_add_token(response, obs->pdu->token_length, obs->pdu->token)) {
904  obs->dirty = 1;
905  r->partiallydirty = 1;
906  context->observe_pending = 1;
908  "coap_check_notify: cannot add token, resource stays "
909  "partially dirty\n");
910  coap_delete_pdu(response);
911  continue;
912  }
913 
914  token.length = obs->pdu->token_length;
915  token.s = obs->pdu->token;
916 
917  obs->pdu->mid = response->mid = coap_new_message_id(obs->session);
918  if ((r->flags & COAP_RESOURCE_FLAGS_NOTIFY_CON) == 0 &&
920  obs->non_cnt < COAP_OBS_MAX_NON)) {
921  response->type = COAP_MESSAGE_NON;
922  } else {
923  response->type = COAP_MESSAGE_CON;
924  }
925  switch (deleting) {
927  /* fill with observer-specific data */
929  coap_encode_var_safe(buf, sizeof (buf),
930  r->observe),
931  buf);
932  if (coap_get_block(obs->pdu, COAP_OPTION_BLOCK2, &block)) {
933  /* Will get updated later (e.g. M bit) if appropriate */
935  coap_encode_var_safe(buf, sizeof(buf),
936  ((0 << 4) |
937  (0 << 3) |
938  block.szx)),
939  buf);
940  }
941 
942  h = r->handler[obs->pdu->code - 1];
943  assert(h); /* we do not allow subscriptions if no
944  * GET/FETCH handler is defined */
945  query = coap_get_query(obs->pdu);
946  h(r, obs->session, obs->pdu, query, response);
947  /* Check if lg_xmit generated and update PDU code if so */
948  coap_check_code_lg_xmit(obs->session, response, r, query);
949  coap_delete_string(query);
950  if (COAP_RESPONSE_CLASS(response->code) != 2) {
952  }
953  if (COAP_RESPONSE_CLASS(response->code) > 2) {
954  coap_delete_observer(r, obs->session, &token);
955  }
956  break;
958  default:
959  response->type = COAP_MESSAGE_NON;
960  response->code = COAP_RESPONSE_CODE(404);
961  break;
962  }
963 
964  if (response->type == COAP_MESSAGE_CON ||
966  obs->non_cnt = 0;
967  } else {
968  obs->non_cnt++;
969  }
970 
971  mid = coap_send_internal( obs->session, response );
972 
973  if (COAP_INVALID_MID == mid) {
975  "coap_check_notify: sending failed, resource stays "
976  "partially dirty\n");
977  obs->dirty = 1;
978  r->partiallydirty = 1;
979  context->observe_pending = 1;
980  }
981 
982  }
983  }
984  r->dirty = 0;
985 }
986 
987 int
989  return coap_resource_notify_observers(r, query);
990 }
991 
992 int
994  const coap_string_t *query COAP_UNUSED) {
995  if (!r->observable)
996  return 0;
997  if ( !r->subscribers )
998  return 0;
999  r->dirty = 1;
1000 
1001  /* Increment value for next Observe use. Observe value must be < 2^24 */
1002  r->observe = (r->observe + 1) & 0xFFFFFF;
1003 
1004  assert(r->context);
1005  r->context->observe_pending = 1;
1006 #ifdef COAP_EPOLL_SUPPORT
1007  if (r->context->eptimerfd != -1) {
1008  /* Need to immediately trigger any epoll_wait() */
1009  struct itimerspec new_value;
1010  int ret;
1011 
1012  memset(&new_value, 0, sizeof(new_value));
1013  new_value.it_value.tv_nsec = 1; /* small that is not zero */
1014  ret = timerfd_settime(r->context->eptimerfd, 0, &new_value, NULL);
1015  if (ret == -1) {
1016  coap_log(LOG_ERR,
1017  "%s: timerfd_settime failed: %s (%d)\n",
1018  "coap_resource_notify_observers",
1019  coap_socket_strerror(), errno);
1020  }
1021  }
1022 #endif /* COAP_EPOLL_SUPPORT */
1023  return 1;
1024 }
1025 
1026 void
1028  resource->flags = (resource->flags &
1031 }
1032 
1033 void
1035  resource->user_data = data;
1036 }
1037 
1038 void *
1040  return resource->user_data;
1041 }
1042 
1043 void
1046  context->release_userdata = callback;
1047 }
1048 
1049 void
1051  resource->observable = mode ? 1 : 0;
1052 }
1053 
1056  if (resource)
1057  return resource->uri_path;
1058  return NULL;
1059 }
1060 
1061 void
1063 
1064  if (context->observe_pending) {
1065  context->observe_pending = 0;
1066  RESOURCES_ITER(context->resources, r) {
1068  }
1069  }
1070 }
1071 
1082 static void
1084  coap_resource_t *resource,
1085  coap_session_t *session,
1086  const coap_binary_t *token) {
1087  coap_subscription_t *obs, *otmp;
1088 
1089  LL_FOREACH_SAFE(resource->subscribers, obs, otmp) {
1090  if ( obs->session == session &&
1091  token->length == obs->pdu->token_length &&
1092  memcmp(token->s, obs->pdu->token, token->length) == 0) {
1093 
1094  /* count failed notifies and remove when
1095  * COAP_MAX_FAILED_NOTIFY is reached */
1096  if (obs->fail_cnt < COAP_OBS_MAX_FAIL)
1097  obs->fail_cnt++;
1098  else {
1099  LL_DELETE(resource->subscribers, obs);
1100  obs->fail_cnt = 0;
1101 
1102  if (LOG_DEBUG <= coap_get_log_level()) {
1103 #ifndef INET6_ADDRSTRLEN
1104 #define INET6_ADDRSTRLEN 40
1105 #endif
1106  unsigned char addr[INET6_ADDRSTRLEN+8];
1107 
1109  addr, INET6_ADDRSTRLEN+8))
1110  coap_log(LOG_DEBUG, "** removed observer %s\n", addr);
1111  }
1112  coap_cancel_all_messages(context, obs->session,
1113  obs->pdu->token, obs->pdu->token_length);
1114  coap_session_release( obs->session );
1115  coap_delete_pdu(obs->pdu);
1117  COAP_FREE_TYPE(subscription, obs);
1118  }
1119  break; /* break loop if observer was found */
1120  }
1121  }
1122 }
1123 
1124 void
1126  coap_session_t *session,
1127  const coap_binary_t *token) {
1128 
1129  RESOURCES_ITER(context->resources, r) {
1130  coap_remove_failed_observers(context, r, session, token);
1131  }
1132 }
Pulls together all the internal only header files.
const char * coap_socket_strerror(void)
Definition: coap_io.c:1502
void coap_check_code_lg_xmit(coap_session_t *session, coap_pdu_t *response, coap_resource_t *resource, coap_string_t *query)
The function checks that the code in a newly formed lg_xmit created by coap_add_data_large_response()...
Definition: block.c:1948
int coap_get_block(const coap_pdu_t *pdu, coap_option_num_t number, coap_block_t *block)
Initializes block from pdu.
Definition: block.c:37
void coap_delete_cache_key(coap_cache_key_t *cache_key)
Delete the cache-key.
Definition: coap_cache.c:138
coap_cache_key_t * coap_cache_derive_key_w_ignore(const coap_session_t *session, const coap_pdu_t *pdu, coap_cache_session_based_t session_based, const uint16_t *cache_ignore_options, size_t cache_ignore_count)
Calculates a cache-key for the given CoAP PDU.
Definition: coap_cache.c:68
@ COAP_CACHE_IS_SESSION_BASED
Definition: coap_cache.h:37
#define COAP_DEFAULT_NSTART
The number of simultaneous outstanding interactions that a client maintains to a given server.
Definition: coap_session.h:427
coap_print_status_t coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, coap_opt_t *query_filter)
Prints the names of all known resources to buf.
Definition: resource.c:171
#define RESOURCES_ADD(r, obj)
void coap_delete_all_resources(coap_context_t *context)
Deletes all resources from given context and frees their storage.
Definition: resource.c:590
void coap_delete_attr(coap_attr_t *attr)
Deletes an attribute.
Definition: resource.c:468
#define RESOURCES_FIND(r, k, res)
#define RESOURCES_DELETE(r, obj)
#define RESOURCES_ITER(r, tmp)
coap_resource_t * coap_resource_proxy_uri_init(coap_method_handler_t handler, size_t host_name_count, const char *host_name_list[])
Creates a new resource object for handling proxy URIs.
Definition: resource.c:358
#define COAP_RESOURCE_FLAGS_NOTIFY_NON
Notifications will be sent non-confirmable by default.
Definition: resource.h:59
#define COAP_ATTR_FLAGS_RELEASE_VALUE
Definition: resource.h:49
coap_print_status_t coap_print_link(const coap_resource_t *resource, unsigned char *buf, size_t *len, size_t *offset)
Writes a description of this resource in link-format to given text buffer.
Definition: resource.c:624
#define COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS
Notifications will always be sent non-confirmable.
Definition: resource.h:75
#define COAP_ATTR_FLAGS_RELEASE_NAME
Definition: resource.h:48
void coap_resource_set_mode(coap_resource_t *resource, int mode)
Sets the notification message type of resource resource to given mode.
Definition: resource.c:1027
coap_str_const_t * coap_resource_get_uri_path(coap_resource_t *resource)
Get the uri_path from a resource.
Definition: resource.c:1055
coap_str_const_t * coap_attr_get_value(coap_attr_t *attr)
Returns attribute's value.
Definition: resource.c:461
#define COAP_PRINT_STATUS_TRUNC
Definition: resource.h:329
void coap_resource_release_userdata_handler(coap_context_t *context, coap_resource_release_userdata_handler_t callback)
Defines the context wide callback to use to when the resource is deleted to release the data held in ...
Definition: resource.c:1044
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.
Definition: resource.c:615
#define COAP_RESOURCE_FLAGS_NOTIFY_CON
Notifications will be sent confirmable.
Definition: resource.h:65
void coap_register_handler(coap_resource_t *resource, coap_request_t method, coap_method_handler_t handler)
Registers the specified handler as message handler for the request type method.
Definition: resource.c:677
coap_resource_t * coap_resource_unknown_init(coap_method_handler_t put_handler)
Creates a new resource object for the unknown resource handler with support for PUT.
Definition: resource.c:337
coap_attr_t * coap_find_attr(coap_resource_t *resource, coap_str_const_t *name)
Returns resource's coap_attr_t object with given name if found, NULL otherwise.
Definition: resource.c:444
unsigned int coap_print_status_t
Status word to encode the result of conditional print or copy operations such as coap_print_link().
Definition: resource.h:324
void(* coap_method_handler_t)(coap_resource_t *, coap_session_t *, const coap_pdu_t *, const coap_string_t *, coap_pdu_t *)
Definition of message handler function.
Definition: resource.h:42
coap_resource_t * coap_resource_init(coap_str_const_t *uri_path, int flags)
Creates a new resource object and initializes the link field to the string uri_path.
Definition: resource.c:303
void(* coap_resource_release_userdata_handler_t)(void *user_data)
Definition of release resource user_data callback function.
Definition: resource.h:212
void coap_add_resource(coap_context_t *context, coap_resource_t *resource)
Registers the given resource for context.
Definition: resource.c:536
void coap_resource_set_userdata(coap_resource_t *resource, void *data)
Sets the user_data.
Definition: resource.c:1034
coap_attr_t * coap_add_attr(coap_resource_t *resource, coap_str_const_t *name, coap_str_const_t *val, int flags)
Registers a new attribute with the given resource.
Definition: resource.c:407
#define COAP_PRINT_STATUS_ERROR
Definition: resource.h:328
#define COAP_PRINT_OUTPUT_LENGTH(v)
Definition: resource.h:327
int coap_delete_resource(coap_context_t *context, coap_resource_t *resource)
Deletes a resource identified by resource.
Definition: resource.c:565
void * coap_resource_get_userdata(coap_resource_t *resource)
Gets the user_data.
Definition: resource.c:1039
#define COAP_RESOURCE_FLAGS_RELEASE_URI
The URI passed to coap_resource_init() is free'd by coap_delete_resource().
Definition: resource.h:52
coap_mid_t coap_send_internal(coap_session_t *session, coap_pdu_t *pdu)
Sends a CoAP message to given peer.
Definition: net.c:1154
void coap_cancel_all_messages(coap_context_t *context, coap_session_t *session, const uint8_t *token, size_t token_length)
Cancels all outstanding messages for session session that have the specified token.
Definition: net.c:2016
uint16_t coap_new_message_id(coap_session_t *session)
Returns a new message id and updates session->tx_mid accordingly.
unsigned int coap_encode_var_safe(uint8_t *buf, size_t length, unsigned int val)
Encodes multiple-length byte sequences.
Definition: encode.c:40
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:63
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:173
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:152
@ LOG_ERR
Error.
Definition: coap_debug.h:55
@ LOG_WARNING
Warning.
Definition: coap_debug.h:56
@ LOG_DEBUG
Debug.
Definition: coap_debug.h:59
void coap_resource_set_get_observable(coap_resource_t *resource, int mode)
Set whether a resource is observable.
Definition: resource.c:1050
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:211
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:248
int coap_remove_option(coap_pdu_t *pdu, coap_option_num_t number)
Removes (first) option of given number from the pdu.
Definition: pdu.c:314
coap_pdu_t * coap_pdu_duplicate(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options)
Duplicate an existing PDU.
Definition: pdu.c:155
#define COAP_OPTION_BLOCK2
Definition: pdu.h:124
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: pdu.c:142
int coap_mid_t
coap_mid_t is used to store the CoAP Message ID of a CoAP PDU.
Definition: pdu.h:231
coap_request_t
CoAP PDU Request methods.
Definition: pdu.h:66
#define COAP_RESPONSE_CODE(N)
Definition: pdu.h:140
#define COAP_RESPONSE_CLASS(C)
Definition: pdu.h:143
int coap_add_token(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds token of length len to pdu.
Definition: pdu.c:258
size_t coap_add_option(coap_pdu_t *pdu, coap_option_num_t number, size_t len, const uint8_t *data)
Adds option of given number to pdu that is passed as first parameter.
Definition: pdu.c:543
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:654
#define COAP_INVALID_MID
Indicates an invalid message id.
Definition: pdu.h:234
#define COAP_OPTION_ETAG
Definition: pdu.h:109
#define COAP_OPTION_OBSERVE
Definition: pdu.h:111
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: pdu.c:87
int coap_add_data(coap_pdu_t *pdu, size_t len, const uint8_t *data)
Adds given data to the pdu that is passed as first parameter.
Definition: pdu.c:624
@ COAP_REQUEST_PUT
Definition: pdu.h:69
@ COAP_MESSAGE_NON
Definition: pdu.h:58
@ COAP_MESSAGE_CON
Definition: pdu.h:57
size_t coap_session_max_pdu_size(const coap_session_t *session)
Get maximum acceptable PDU size.
Definition: coap_session.c:244
coap_session_t * coap_session_reference(coap_session_t *session)
Increment reference counter on a session.
Definition: coap_session.c:70
void coap_session_release(coap_session_t *session)
Decrement reference counter on a session.
Definition: coap_session.c:76
void coap_delete_str_const(coap_str_const_t *s)
Deletes the given const string and releases any memory allocated.
Definition: str.c:53
coap_str_const_t * coap_new_str_const(const uint8_t *data, size_t size)
Returns a new const string object with at least size+1 bytes storage allocated, and the provided data...
Definition: str.c:44
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition: str.c:40
int coap_delete_observer(coap_resource_t *resource, coap_session_t *session, const coap_binary_t *token)
Removes any subscription for observer from resource and releases the allocated storage.
Definition: resource.c:816
coap_subscription_t * coap_add_observer(coap_resource_t *resource, coap_session_t *session, const coap_binary_t *token, const coap_pdu_t *request)
Adds the specified peer as observer for resource.
Definition: resource.c:721
coap_subscription_t * coap_find_observer(coap_resource_t *resource, coap_session_t *session, const coap_binary_t *token)
Returns a subscription object for given peer.
Definition: resource.c:686
void coap_delete_observers(coap_context_t *context, coap_session_t *session)
Removes any subscription for session and releases the allocated storage.
Definition: resource.c:842
void coap_check_notify(coap_context_t *context)
Checks all known resources to see if they are dirty and then notifies subscribed observers.
Definition: resource.c:1062
void coap_handle_failed_notify(coap_context_t *context, coap_session_t *session, const coap_binary_t *token)
Handles a failed observe notify.
Definition: resource.c:1125
#define COAP_OBS_MAX_NON
Number of notifications that may be sent non-confirmable before a confirmable message is sent to dete...
void coap_subscription_init(coap_subscription_t *s)
Definition: subscribe.c:15
#define COAP_OBS_MAX_FAIL
Number of confirmable notifications that may fail (i.e.
void coap_touch_observer(coap_context_t *context, coap_session_t *session, const coap_binary_t *token)
Flags that data is ready to be sent to observers.
Definition: resource.c:803
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: uri.c:556
#define COAP_UNUSED
Definition: libcoap.h:55
#define COAP_STATIC_INLINE
Definition: libcoap.h:40
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_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:98
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:105
@ COAP_RESOURCE
Definition: mem.h:41
@ COAP_RESOURCEATTR
Definition: mem.h:42
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...
Definition: option.h:26
#define MATCH_URI
static const uint8_t coap_unknown_resource_uri[]
Definition: resource.c:333
static const uint8_t coap_proxy_resource_uri[]
Definition: resource.c:354
static void coap_free_resource(coap_resource_t *resource)
Definition: resource.c:493
#define PRINT_COND_WITH_OFFSET(Buf, Bufend, Offset, Char, Result)
Adds Char to Buf if Offset is zero and Buf is less than Bufend.
Definition: resource.c:87
static coap_str_const_t null_path_value
Definition: resource.c:299
static coap_subscription_t * coap_find_observer_cache_key(coap_resource_t *resource, coap_session_t *session, const coap_cache_key_t *cache_key)
Definition: resource.c:704
int coap_resource_set_dirty(coap_resource_t *r, const coap_string_t *query)
Definition: resource.c:988
int coap_resource_notify_observers(coap_resource_t *r, const coap_string_t *query COAP_UNUSED)
Definition: resource.c:993
static int match(const coap_str_const_t *text, const coap_str_const_t *pattern, int match_prefix, int match_substring)
Definition: resource.c:107
#define MATCH_SUBSTRING
coap_deleting_resource_t
Definition: resource.c:484
@ COAP_DELETING_RESOURCE
Definition: resource.c:485
@ COAP_NOT_DELETING_RESOURCE
Definition: resource.c:486
static void coap_remove_failed_observers(coap_context_t *context, coap_resource_t *resource, coap_session_t *session, const coap_binary_t *token)
Checks the failure counter for (peer, token) and removes peer from the list of observers for the give...
Definition: resource.c:1083
#define COAP_PRINT_STATUS_MAX
Definition: resource.c:63
#define COAP_MALLOC_TYPE(Type)
Definition: resource.c:58
static coap_str_const_t * null_path
Definition: resource.c:300
#define COAP_FREE_TYPE(Type, Object)
Definition: resource.c:60
static void coap_notify_observers(coap_context_t *context, coap_resource_t *r, coap_deleting_resource_t deleting)
Definition: resource.c:858
#define MATCH_PREFIX
#define COPY_COND_WITH_OFFSET(Buf, Bufend, Offset, Str, Length, Result)
Copies at most Length characters of Str to Buf.
Definition: resource.c:99
#define INET6_ADDRSTRLEN
coap_address_t remote
remote address and port
Definition: coap_io.h:51
Abstraction of attribute associated with a resource.
coap_str_const_t * value
Value of the attribute (can be NULL)
coap_str_const_t * name
Name of the attribute.
CoAP binary data definition.
Definition: str.h:50
size_t length
length of binary data
Definition: str.h:51
uint8_t * s
binary data
Definition: str.h:52
Structure of Block options.
Definition: block.h:35
unsigned int szx
block size
Definition: block.h:38
The CoAP stack's global state is stored in a coap_context_t object.
coap_resource_t * resources
hash table or list of known resources
coap_resource_release_userdata_handler_t release_userdata
function to release user_data when resource is deleted
uint8_t observe_pending
Observe response pending.
coap_resource_t * proxy_uri_resource
can be used for handling proxy URI resources
coap_resource_t * unknown_resource
can be used for handling unknown resources
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
uint8_t * token
first byte of token, if any, or options
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
uint8_t token_length
length of Token
coap_mid_t mid
message id, if any, in regular host byte order
coap_pdu_type_t type
message type
Abstraction of resource that can be attached to coap_context_t.
unsigned int dirty
set to 1 if resource has changed
unsigned int partiallydirty
set to 1 if some subscribers have not yet been notified of the last change
coap_subscription_t * subscribers
list of observers for this resource
void * user_data
This pointer is under user control.
coap_str_const_t ** proxy_name_list
Array valid names this host is known by (proxy support)
coap_str_const_t * uri_path
Request URI Path for this resource.
unsigned int observe
The next value for the Observe option.
coap_context_t * context
Pointer back to the context that 'owns' this resource.
coap_method_handler_t handler[7]
Used to store handlers for the seven coap methods GET, POST, PUT, DELETE, FETCH, PATCH and IPATCH.
unsigned int is_proxy_uri
resource created for proxy URI handler
unsigned int is_unknown
resource created for unknown handler
coap_attr_t * link_attr
attributes to be included with the link format
unsigned int observable
can be observed
size_t proxy_name_count
Count of valid names this host is known by (proxy support)
int flags
zero or more COAP_RESOURCE_FLAGS_* or'd together
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_addr_tuple_t addr_info
key: remote/local address info
uint8_t con_active
Active CON request sent.
CoAP string data definition with const data.
Definition: str.h:40
const uint8_t * s
read-only string data
Definition: str.h:42
size_t length
length of string
Definition: str.h:41
CoAP string data definition.
Definition: str.h:32
Subscriber information.
unsigned int fail_cnt
up to 3 confirmable notifies can fail
unsigned int non_cnt
up to 15 non-confirmable notifies allowed
coap_cache_key_t * cache_key
struct coap_session_t * session
subscriber session
unsigned int dirty
set if the notification temporarily could not be sent (in that case, the resource's partially dirty f...
coap_pdu_t * pdu
cache_key to identify requester