mirror of
https://github.com/obgm/libcoap.git
synced 2025-10-14 02:19:34 +08:00
coap_resource.c: Make dynamic resource handling thread safe
Let libcoap do the necessary multi-thread locking during resource generation, lookup and deletion. Supported using a new handler set up by coap_register_dynamic_resource_handler().
This commit is contained in:
@@ -249,6 +249,7 @@ release_resource_data(coap_session_t *session COAP_UNUSED,
|
||||
if (!transient_value)
|
||||
return;
|
||||
|
||||
assert(transient_value->ref_cnt);
|
||||
if (--transient_value->ref_cnt > 0)
|
||||
return;
|
||||
coap_delete_binary(transient_value->value);
|
||||
@@ -722,16 +723,11 @@ hnd_reverse_proxy_uri(coap_resource_t *resource,
|
||||
#endif /* COAP_PROXY_SUPPORT */
|
||||
|
||||
typedef struct dynamic_resource_t {
|
||||
coap_string_t *uri_path;
|
||||
transient_value_t *value;
|
||||
coap_resource_t *resource;
|
||||
int created;
|
||||
uint16_t media_type;
|
||||
} dynamic_resource_t;
|
||||
|
||||
static int dynamic_count = 0;
|
||||
static dynamic_resource_t *dynamic_entry = NULL;
|
||||
|
||||
/*
|
||||
* Regular DELETE handler - used by resources created by the
|
||||
* Unknown Resource PUT handler
|
||||
@@ -740,37 +736,10 @@ static dynamic_resource_t *dynamic_entry = NULL;
|
||||
static void
|
||||
hnd_delete(coap_resource_t *resource,
|
||||
coap_session_t *session COAP_UNUSED,
|
||||
const coap_pdu_t *request,
|
||||
const coap_pdu_t *request COAP_UNUSED,
|
||||
const coap_string_t *query COAP_UNUSED,
|
||||
coap_pdu_t *response) {
|
||||
int i;
|
||||
coap_string_t *uri_path;
|
||||
|
||||
/* get the uri_path */
|
||||
uri_path = coap_get_uri_path(request);
|
||||
if (!uri_path) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < dynamic_count; i++) {
|
||||
if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
|
||||
/* Dynamic entry no longer required - delete it */
|
||||
release_resource_data(session, dynamic_entry[i].value);
|
||||
coap_delete_string(dynamic_entry[i].uri_path);
|
||||
if (dynamic_count-i > 1) {
|
||||
memmove(&dynamic_entry[i],
|
||||
&dynamic_entry[i+1],
|
||||
(dynamic_count-i-1) * sizeof(dynamic_entry[0]));
|
||||
}
|
||||
dynamic_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dynamic resource no longer required - delete it */
|
||||
coap_delete_resource(NULL, resource);
|
||||
coap_delete_string(uri_path);
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
|
||||
}
|
||||
|
||||
@@ -785,34 +754,15 @@ hnd_get(coap_resource_t *resource,
|
||||
const coap_pdu_t *request,
|
||||
const coap_string_t *query,
|
||||
coap_pdu_t *response) {
|
||||
coap_str_const_t *uri_path;
|
||||
int i;
|
||||
dynamic_resource_t *resource_entry = NULL;
|
||||
coap_binary_t body;
|
||||
/*
|
||||
* request will be NULL if an Observe triggered request, so the uri_path,
|
||||
* if needed, must be abstracted from the resource.
|
||||
* The uri_path string is a const pointer
|
||||
*/
|
||||
|
||||
uri_path = coap_resource_get_uri_path(resource);
|
||||
if (!uri_path) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
resource_entry = coap_resource_get_userdata(resource);
|
||||
if (!resource_entry) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < dynamic_count; i++) {
|
||||
if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == dynamic_count) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
resource_entry = &dynamic_entry[i];
|
||||
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
|
||||
body = reference_resource_data(resource_entry->value);
|
||||
coap_add_data_large_response(resource, session, request, response,
|
||||
@@ -833,81 +783,36 @@ hnd_put_post(coap_resource_t *resource,
|
||||
const coap_pdu_t *request,
|
||||
const coap_string_t *query COAP_UNUSED,
|
||||
coap_pdu_t *response) {
|
||||
coap_string_t *uri_path;
|
||||
int i;
|
||||
size_t size;
|
||||
const uint8_t *data;
|
||||
size_t offset;
|
||||
size_t total;
|
||||
dynamic_resource_t *resource_entry = NULL;
|
||||
unsigned char buf[6]; /* space to hold encoded/decoded uints */
|
||||
coap_opt_iterator_t opt_iter;
|
||||
coap_opt_t *option;
|
||||
coap_binary_t *data_so_far;
|
||||
transient_value_t *transient_value;
|
||||
|
||||
/* get the uri_path */
|
||||
uri_path = coap_get_uri_path(request);
|
||||
if (!uri_path) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the correct dynamic block for this request
|
||||
*/
|
||||
for (i = 0; i < dynamic_count; i++) {
|
||||
if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == dynamic_count) {
|
||||
if (dynamic_count >= support_dynamic) {
|
||||
/* Should have been caught hnd_put_post_unknown() */
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_ACCEPTABLE);
|
||||
coap_delete_string(uri_path);
|
||||
return;
|
||||
}
|
||||
dynamic_count++;
|
||||
dynamic_entry = realloc(dynamic_entry,
|
||||
dynamic_count * sizeof(dynamic_entry[0]));
|
||||
if (dynamic_entry) {
|
||||
dynamic_entry[i].uri_path = uri_path;
|
||||
dynamic_entry[i].value = NULL;
|
||||
dynamic_entry[i].resource = resource;
|
||||
dynamic_entry[i].created = 1;
|
||||
if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
|
||||
&opt_iter)) != NULL) {
|
||||
dynamic_entry[i].media_type =
|
||||
coap_decode_var_bytes(coap_opt_value(option),
|
||||
coap_opt_length(option));
|
||||
} else {
|
||||
dynamic_entry[i].media_type = COAP_MEDIATYPE_TEXT_PLAIN;
|
||||
}
|
||||
/* Store media type of new resource in ct. We can use buf here
|
||||
* as coap_add_attr() will copy the passed string. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf((char *)buf, sizeof(buf), "%d", dynamic_entry[i].media_type);
|
||||
/* ensure that buf is always zero-terminated */
|
||||
assert(buf[sizeof(buf) - 1] == '\0');
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
coap_add_attr(resource,
|
||||
coap_make_str_const("ct"),
|
||||
coap_make_str_const((char *)buf),
|
||||
0);
|
||||
} else {
|
||||
dynamic_count--;
|
||||
resource_entry = coap_resource_get_userdata(resource);
|
||||
if (!resource_entry) {
|
||||
resource_entry = malloc(sizeof(dynamic_resource_t));
|
||||
if (!resource_entry) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
|
||||
coap_delete_string(uri_path);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Need to do this as coap_get_uri_path() created it */
|
||||
coap_delete_string(uri_path);
|
||||
memset(resource_entry, 0, sizeof(dynamic_resource_t));
|
||||
resource_entry->created = 1;
|
||||
if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
|
||||
&opt_iter)) != NULL) {
|
||||
resource_entry->media_type =
|
||||
coap_decode_var_bytes(coap_opt_value(option),
|
||||
coap_opt_length(option));
|
||||
} else {
|
||||
resource_entry->media_type = COAP_MEDIATYPE_TEXT_PLAIN;
|
||||
}
|
||||
coap_resource_set_userdata(resource, resource_entry);
|
||||
}
|
||||
|
||||
resource_entry = &dynamic_entry[i];
|
||||
|
||||
if (coap_get_data_large(request, &size, &data, &offset, &total) &&
|
||||
size != total) {
|
||||
coap_binary_t *old_data_in_cache;
|
||||
@@ -1023,7 +928,7 @@ hnd_put_post(coap_resource_t *resource,
|
||||
}
|
||||
} else {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
|
||||
coap_resource_notify_observers(resource_entry->resource, NULL);
|
||||
coap_resource_notify_observers(resource, NULL);
|
||||
}
|
||||
|
||||
if (echo_back) {
|
||||
@@ -1044,29 +949,19 @@ fail:
|
||||
}
|
||||
|
||||
/*
|
||||
* Unknown Resource PUT handler
|
||||
* Dynamic Resource PUT / POST handler
|
||||
* Create the appropriate resource and pass it back.
|
||||
*/
|
||||
|
||||
static void
|
||||
hnd_put_post_unknown(coap_resource_t *resource COAP_UNUSED,
|
||||
coap_session_t *session,
|
||||
const coap_pdu_t *request,
|
||||
const coap_string_t *query,
|
||||
coap_pdu_t *response) {
|
||||
static coap_resource_t *
|
||||
dyn_create_handler(coap_session_t *session, const coap_pdu_t *request) {
|
||||
coap_resource_t *r;
|
||||
coap_string_t *uri_path;
|
||||
|
||||
/* check if creating a new resource is allowed */
|
||||
if (dynamic_count >= support_dynamic) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_ACCEPTABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the uri_path - will get used by coap_resource_init() */
|
||||
uri_path = coap_get_uri_path(request);
|
||||
if (!uri_path) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1075,6 +970,9 @@ hnd_put_post_unknown(coap_resource_t *resource COAP_UNUSED,
|
||||
*/
|
||||
r = coap_resource_init((coap_str_const_t *)uri_path,
|
||||
COAP_RESOURCE_FLAGS_RELEASE_URI | resource_flags);
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Dynamic\""), 0);
|
||||
coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_post);
|
||||
coap_register_request_handler(r, COAP_REQUEST_POST, hnd_put_post);
|
||||
@@ -1084,9 +982,7 @@ hnd_put_post_unknown(coap_resource_t *resource COAP_UNUSED,
|
||||
coap_resource_set_get_observable(r, 1);
|
||||
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get);
|
||||
coap_add_resource(coap_session_get_context(session), r);
|
||||
|
||||
/* Do the PUT/POST for this first call */
|
||||
hnd_put_post(r, session, request, query, response);
|
||||
return r;
|
||||
}
|
||||
|
||||
#if COAP_PROXY_SUPPORT
|
||||
@@ -1160,6 +1056,15 @@ proxy_nack_handler(coap_session_t *session COAP_UNUSED,
|
||||
|
||||
#endif /* COAP_PROXY_SUPPORT */
|
||||
|
||||
static void
|
||||
resource_data_delete(void *ptr) {
|
||||
dynamic_resource_t *resource_entry = (dynamic_resource_t *)ptr;
|
||||
if (resource_entry->value) {
|
||||
release_resource_data(NULL, resource_entry->value);
|
||||
}
|
||||
free(resource_entry);
|
||||
}
|
||||
|
||||
static void
|
||||
init_resources(coap_context_t *ctx) {
|
||||
coap_resource_t *r;
|
||||
@@ -1200,11 +1105,8 @@ init_resources(coap_context_t *ctx) {
|
||||
time_resource = r;
|
||||
|
||||
if (support_dynamic > 0) {
|
||||
/* Create a resource to handle PUTs to unknown URIs */
|
||||
r = coap_resource_unknown_init2(hnd_put_post_unknown, 0);
|
||||
/* Add in handling POST as well */
|
||||
coap_register_handler(r, COAP_REQUEST_POST, hnd_put_post_unknown);
|
||||
coap_add_resource(ctx, r);
|
||||
coap_register_dynamic_resource_handler(ctx, dyn_create_handler,
|
||||
support_dynamic);
|
||||
}
|
||||
|
||||
if (coap_async_is_supported()) {
|
||||
@@ -1239,6 +1141,7 @@ init_resources(coap_context_t *ctx) {
|
||||
coap_register_nack_handler(ctx, proxy_nack_handler);
|
||||
}
|
||||
#endif /* COAP_PROXY_SUPPORT */
|
||||
coap_resource_release_userdata_handler(ctx, resource_data_delete);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -2916,11 +2819,6 @@ finish:
|
||||
if (valid_pki_snis.count)
|
||||
free(valid_pki_snis.pki_sni_list);
|
||||
|
||||
for (i = 0; i < (size_t)dynamic_count; i++) {
|
||||
coap_delete_string(dynamic_entry[i].uri_path);
|
||||
release_resource_data(NULL, dynamic_entry[i].value);
|
||||
}
|
||||
free(dynamic_entry);
|
||||
release_resource_data(NULL, example_data_value);
|
||||
#if COAP_PROXY_SUPPORT
|
||||
free(reverse_proxy.entry);
|
||||
|
@@ -106,6 +106,16 @@ typedef void (*coap_pong_handler_t)(coap_session_t *session,
|
||||
const coap_pdu_t *received,
|
||||
const coap_mid_t mid);
|
||||
|
||||
/**
|
||||
* Definition of resource dynamic creation handler function
|
||||
*
|
||||
* @param session The CoAP session.
|
||||
* @param request The request PDU.
|
||||
*
|
||||
* @return A pointer to the new resource or @c NULL on error.
|
||||
*/
|
||||
typedef coap_resource_t *(*coap_resource_dynamic_create_t)(coap_session_t *session,
|
||||
const coap_pdu_t *request);
|
||||
/**
|
||||
* Registers a new message handler that is called whenever a response is
|
||||
* received.
|
||||
@@ -148,6 +158,24 @@ void coap_register_ping_handler(coap_context_t *context,
|
||||
void coap_register_pong_handler(coap_context_t *context,
|
||||
coap_pong_handler_t handler);
|
||||
|
||||
/**
|
||||
* Sets up a handler for calling when an unknown resource is requested.
|
||||
* The @p create_handler is expected to create the required resource to handle
|
||||
* the request which is then used to call the appropriate method handler.
|
||||
*
|
||||
* Doing this stops multiple threads asking for the same unknown resource and
|
||||
* means that a resource unknown handler does not need to be thread safe.
|
||||
*
|
||||
* @param context The context to add this support to.
|
||||
* @param create_handler Called to create a new resource.
|
||||
* @param dynamic_max Maximum number of currently created dynamic resources. If
|
||||
* 0, unlimited.
|
||||
*
|
||||
*/
|
||||
void coap_register_dynamic_resource_handler(coap_context_t *context,
|
||||
coap_resource_dynamic_create_t create_handler,
|
||||
uint32_t dynamic_max);
|
||||
|
||||
/**
|
||||
* Registers the option number @p number with the given context object @p context.
|
||||
*
|
||||
|
@@ -215,6 +215,9 @@ struct coap_context_t {
|
||||
uint8_t testing_cids; /**< Change client's source port every testing_cids */
|
||||
#endif /* COAP_CLIENT_SUPPORT */
|
||||
uint32_t block_mode; /**< Zero or more COAP_BLOCK_ or'd options */
|
||||
coap_resource_dynamic_create_t dyn_create_handler; /**< Dynamc resource create handler */
|
||||
uint32_t dynamic_cur; /* Current number of dynamic resources */
|
||||
uint32_t dynamic_max; /* Max number of dynamic resources or 0 is unlimited */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -60,7 +60,9 @@ struct coap_resource_t {
|
||||
unsigned int is_proxy_uri:1; /**< resource created for proxy URI handler */
|
||||
unsigned int is_reverse_proxy:1; /**< resource created for reverse proxy URI handler */
|
||||
unsigned int list_being_traversed:1; /**< resource subscriber list being traversed */
|
||||
unsigned int is_dynamic:1; /**< create unknown resource dynamically */
|
||||
|
||||
uint32_t ref; /**< Resource reference count */
|
||||
/**
|
||||
* Used to store handlers for the seven coap methods @c GET, @c POST, @c PUT,
|
||||
* @c DELETE, @c FETCH, @c PATCH and @c IPATCH.
|
||||
@@ -147,6 +149,26 @@ int coap_delete_resource_lkd(coap_context_t *context, coap_resource_t *resource)
|
||||
*/
|
||||
void coap_delete_all_resources(coap_context_t *context);
|
||||
|
||||
/**
|
||||
* Increment reference counter on a resource.
|
||||
*
|
||||
* Note: This function must be called in the locked state.
|
||||
*
|
||||
* @param resource The CoAP resource.
|
||||
*/
|
||||
void coap_resource_reference_lkd(coap_resource_t *resource);
|
||||
|
||||
/**
|
||||
* Decrement reference counter on a resource.
|
||||
* Note that the resource storage may be deleted as a result and should not be
|
||||
* used after this call.
|
||||
*
|
||||
* Note: This function must be called in the locked state.
|
||||
*
|
||||
* @param resource The CoAP resource.
|
||||
*/
|
||||
void coap_resource_release_lkd(coap_resource_t *resource);
|
||||
|
||||
#define RESOURCES_ADD(r, obj) \
|
||||
HASH_ADD(hh, (r), uri_path->s[0], (obj)->uri_path->length, (obj))
|
||||
|
||||
|
@@ -224,6 +224,7 @@ global:
|
||||
coap_query_into_optlist;
|
||||
coap_realloc_type;
|
||||
coap_register_async;
|
||||
coap_register_dynamic_resource_handler;
|
||||
coap_register_event_handler;
|
||||
coap_register_handler;
|
||||
coap_register_nack_handler;
|
||||
|
@@ -222,6 +222,7 @@ coap_q_block_is_supported
|
||||
coap_query_into_optlist
|
||||
coap_realloc_type
|
||||
coap_register_async
|
||||
coap_register_dynamic_resource_handler
|
||||
coap_register_event_handler
|
||||
coap_register_handler
|
||||
coap_register_nack_handler
|
||||
|
@@ -16,7 +16,8 @@ coap_register_response_handler,
|
||||
coap_register_nack_handler,
|
||||
coap_register_ping_handler,
|
||||
coap_register_pong_handler,
|
||||
coap_register_event_handler
|
||||
coap_register_event_handler,
|
||||
coap_register_dynamic_resource_handler
|
||||
- Work with CoAP handlers
|
||||
|
||||
SYNOPSIS
|
||||
@@ -41,6 +42,10 @@ coap_pong_handler_t _handler_)*;
|
||||
*void coap_register_event_handler(coap_context_t *_context_,
|
||||
coap_event_handler_t _handler_)*;
|
||||
|
||||
*void coap_register_dynamic_resource_handler(coap_context_t *_context_,
|
||||
coap_resource_dynamic_create_t _create_handler_,
|
||||
uint32_t _dynamic_max_)*;
|
||||
|
||||
For specific (D)TLS library support, link with
|
||||
*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
|
||||
*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*,
|
||||
@@ -122,7 +127,8 @@ _incoming_pdu_'s data must not be used if calling
|
||||
taken.
|
||||
|
||||
*NOTE:* A request callback handler can be called with a generic resource (i.e.
|
||||
set up using *coap_resource_unknown_init2*(3)), so
|
||||
set up using *coap_resource_unknown_init2*(3)), or by using
|
||||
*coap_register_dynamic_resource_handler*(3), so
|
||||
*coap_resource_get_uri_path*(3) can be used to determine the URI in this case.
|
||||
|
||||
*Function: coap_register_response_handler()*
|
||||
@@ -396,6 +402,47 @@ typedef enum {
|
||||
closing down, not all the information may be there in the _session_ parameter
|
||||
passed to the application event handler.
|
||||
|
||||
*Function: coap_register_dynamic_resource_handler()*
|
||||
|
||||
The *coap_register_dynamic_resource_handler*() is a server side function that
|
||||
registers _create_handler_ that is invoked whenever a request comes in for a resource
|
||||
that is not defined and the request type is PUT or POST.
|
||||
|
||||
*NOTE:* This handler takes precedence over any handlers set up by
|
||||
*coap_resource_unknown_init2*(3) or *coap_resource_proxy_uri_init2*(3).
|
||||
|
||||
It is the responsibility of this handler to create and register all the
|
||||
requirements the new resource, returning the address of the newly created
|
||||
resource. Following the creation of the resource, libcoap will then invoke
|
||||
the appropriate method request handler (if defined).
|
||||
|
||||
The number of concurrent dynamically allocated resources is limited to
|
||||
_dynamic_max_, or unlimited if _dynamic_max_ is zero. If a new request comes in
|
||||
and all the available dynamic resources are used up, then a 4.06 response
|
||||
is returned.
|
||||
|
||||
The dynamic resource handler function prototype is defined as:
|
||||
[source, c]
|
||||
----
|
||||
/**
|
||||
* Definition of resource dynamic creation handler function
|
||||
*
|
||||
* @param session The CoAP session.
|
||||
* @param request The request PDU.
|
||||
*
|
||||
* @return A pointer to the new resource or @c NULL on error.
|
||||
*/
|
||||
typedef coap_resource_t *(*coap_resource_dynamic_create_t)(coap_session_t *session,
|
||||
const coap_pdu_t *request);
|
||||
----
|
||||
|
||||
In _create_handler_, data from _request_ can be abstracted as described in
|
||||
*coap_pdu_access*(3) for analysis and then resource creation.
|
||||
|
||||
*NOTE:* If the returned value is NULL, then a 4.06 packet will get sent back to the
|
||||
client by libcoap.
|
||||
>>>>>>> 10fc1b89 (coap_resource.c: Make dynamic resource handling thread safe)
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
*GET Resource Callback Handler*
|
||||
|
@@ -231,6 +231,11 @@ more of the COAP_RESOURCE_FLAGS MCAST definitions.
|
||||
*NOTE:* There can only be one reverse-proxy or unknown resource handler per
|
||||
context - attaching a new one overrides the previous definition.
|
||||
|
||||
*NOTE:* If resources are created in the request handlers accociated with this
|
||||
resource, as multiple threads can be running in the same handler either lock
|
||||
protection needs to be provided in the handler, or consider using
|
||||
*coap_register_dynamic_resource_handler*(3) instead for multi-thread environments.
|
||||
|
||||
*Function: coap_resource_proxy_uri_init()*
|
||||
|
||||
The *coap_resource_proxy_uri_init*() function returns a newly created
|
||||
@@ -491,7 +496,150 @@ init_resources(coap_context_t *ctx) {
|
||||
}
|
||||
----
|
||||
|
||||
*Dynamic Resources Set Up*
|
||||
*Dynamic Resources Set Up using coap_register_dynamic_resource_handler()*
|
||||
|
||||
[source, c]
|
||||
----
|
||||
#include <coap@LIBCOAP_API_VERSION@/coap.h>
|
||||
|
||||
/* Regular DELETE handler - used by resources created by the
|
||||
* Dynamic Resource PUT/POST handler */
|
||||
|
||||
static void
|
||||
hnd_delete(coap_resource_t *resource, coap_session_t *session,
|
||||
const coap_pdu_t *request, const coap_string_t *query,
|
||||
coap_pdu_t *response) {
|
||||
/* Remove (void) definition if variable is used */
|
||||
(void)session;
|
||||
(void)request;
|
||||
(void)query;
|
||||
(void)response;
|
||||
|
||||
/* .. code .. */
|
||||
|
||||
/* Dynamic resource no longer required - delete it */
|
||||
coap_delete_resource(NULL, resource);
|
||||
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
|
||||
}
|
||||
|
||||
/* Regular GET handler - used by resources created by the
|
||||
* Dynamic Resource PUT/POST handler */
|
||||
|
||||
static void
|
||||
hnd_get(coap_resource_t *resource, coap_session_t *session,
|
||||
const coap_pdu_t *request, const coap_string_t *query,
|
||||
coap_pdu_t *response) {
|
||||
coap_str_const_t *get_uri_path;
|
||||
|
||||
/* Remove (void) definition if variable is used */
|
||||
(void)resource;
|
||||
(void)session;
|
||||
(void)request;
|
||||
(void)query;
|
||||
|
||||
/*
|
||||
* Get the specific resource being requested to determine what the response is
|
||||
* The uri_path string is a const pointer
|
||||
*/
|
||||
|
||||
get_uri_path = coap_resource_get_uri_path(resource);
|
||||
|
||||
/* .. code .. */
|
||||
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
|
||||
}
|
||||
|
||||
/* Regular PUT handler - used by resources created by the
|
||||
* Dynamic Resource PUT/POST handler */
|
||||
|
||||
static void
|
||||
hnd_put_post(coap_resource_t *resource, coap_session_t *session,
|
||||
const coap_pdu_t *request, const coap_string_t *query,
|
||||
coap_pdu_t *response) {
|
||||
/* Remove (void) definition if variable is used */
|
||||
(void)resource;
|
||||
(void)session;
|
||||
(void)query;
|
||||
|
||||
coap_string_t *put_uri_path;
|
||||
size_t length;
|
||||
const uint8_t *data;
|
||||
size_t offset;
|
||||
size_t total;
|
||||
int new_resource = 0;
|
||||
|
||||
/* get the uri_path */
|
||||
put_uri_path = coap_get_uri_path(request);
|
||||
if (!put_uri_path) {
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
coap_get_data_large(request, &length, &data, &offset, &total);
|
||||
|
||||
/* .. code .. */
|
||||
|
||||
/* Need to do this as coap_get_uri_path() created it */
|
||||
coap_delete_string(put_uri_path);
|
||||
|
||||
if (length + offset < total)
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
|
||||
else if (new_resource)
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
|
||||
else
|
||||
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dynamic Resource PUT / POST handler
|
||||
* Create the appropriate resource and pass it back.
|
||||
*/
|
||||
|
||||
static coap_resource_t *
|
||||
dyn_create_handler(coap_session_t *session, const coap_pdu_t *request) {
|
||||
coap_resource_t *r;
|
||||
coap_string_t *uri_path;
|
||||
|
||||
/* get the uri_path - will get used by coap_resource_init() */
|
||||
uri_path = coap_get_uri_path(request);
|
||||
if (!uri_path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a resource to handle the new URI
|
||||
* uri_path will get deleted when the resource is removed.
|
||||
* It may be that he resource information is held in the POST data.
|
||||
*/
|
||||
r = coap_resource_init((coap_str_const_t *)uri_path,
|
||||
COAP_RESOURCE_FLAGS_RELEASE_URI | COAP_RESOURCE_FLAGS_NOTIFY_NON);
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Dynamic\""), 0);
|
||||
coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_post);
|
||||
coap_register_request_handler(r, COAP_REQUEST_POST, hnd_put_post);
|
||||
coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete);
|
||||
coap_register_request_handler(r, COAP_REQUEST_FETCH, hnd_get);
|
||||
/* We possibly want to Observe the GETs */
|
||||
coap_resource_set_get_observable(r, 1);
|
||||
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get);
|
||||
coap_add_resource(coap_session_get_context(session), r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Initialize single Dynamic Resource PUT / POST handler */
|
||||
|
||||
static void
|
||||
init_resources(coap_context_t *ctx) {
|
||||
|
||||
coap_register_dynamic_resource_handler(ctx, dyn_create_handler, 20);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
*Dynamic Resources Set Up using coap_resource_unknown_init2()*
|
||||
|
||||
[source, c]
|
||||
----
|
||||
|
@@ -3605,6 +3605,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu
|
||||
/* Cannot handle critical option */
|
||||
pdu->crit_opt = 0;
|
||||
resp = 402;
|
||||
resource = NULL;
|
||||
goto fail_response;
|
||||
}
|
||||
is_proxy_uri = 0;
|
||||
@@ -3614,6 +3615,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu
|
||||
}
|
||||
resource = NULL;
|
||||
}
|
||||
assert(resource == NULL);
|
||||
|
||||
if (!skip_hop_limit_check) {
|
||||
opt = coap_check_option(pdu, COAP_OPTION_HOP_LIMIT, &opt_iter);
|
||||
@@ -3726,6 +3728,28 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu
|
||||
uri_path->s);
|
||||
resp = 202;
|
||||
goto fail_response;
|
||||
} else if ((context->dyn_create_handler != NULL) &&
|
||||
(pdu->code == COAP_REQUEST_CODE_PUT || pdu->code == COAP_REQUEST_CODE_POST)) {
|
||||
/* Above test must be the same as in coap_op_dyn_resource_load_disk() */
|
||||
if (context->dynamic_cur < context->dynamic_max || context->dynamic_max == 0) {
|
||||
#if COAP_WITH_OBSERVE_PERSIST
|
||||
/* If we are maintaining Observe persist */
|
||||
context->unknown_pdu = pdu;
|
||||
context->unknown_session = session;
|
||||
#endif /* COAP_WITH_OBSERVE_PERSIST */
|
||||
coap_lock_callback_ret(resource, context->dyn_create_handler(session, pdu));
|
||||
#if COAP_WITH_OBSERVE_PERSIST
|
||||
/* If we are maintaining Observe persist */
|
||||
context->unknown_pdu = NULL;
|
||||
context->unknown_session = NULL;
|
||||
#endif /* COAP_WITH_OBSERVE_PERSIST */
|
||||
}
|
||||
if (!resource) {
|
||||
resp = 406;
|
||||
goto fail_response;
|
||||
}
|
||||
context->dynamic_cur++;
|
||||
resource->is_dynamic = 1;
|
||||
} else { /* request for any another resource, return 4.04 */
|
||||
|
||||
coap_log_debug("request for unknown resource '%*.*s', return 4.04\n",
|
||||
@@ -3736,6 +3760,8 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu
|
||||
|
||||
}
|
||||
|
||||
coap_resource_reference_lkd(resource);
|
||||
|
||||
#if COAP_OSCORE_SUPPORT
|
||||
if ((resource->flags & COAP_RESOURCE_FLAGS_OSCORE_ONLY) && !session->oscore_encryption) {
|
||||
coap_log_debug("request for OSCORE only resource '%*.*s', return 4.04\n",
|
||||
@@ -3920,7 +3946,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu
|
||||
resource->uri_path->s);
|
||||
coap_lock_callback_release(h(resource, session, pdu, query, response),
|
||||
/* context is being freed off */
|
||||
coap_delete_string(query); goto finish);
|
||||
goto finish);
|
||||
}
|
||||
|
||||
/* Check validity of response code */
|
||||
@@ -4072,6 +4098,8 @@ drop_it_no_debug:
|
||||
#endif /* COAP_Q_BLOCK_SUPPORT */
|
||||
|
||||
finish:
|
||||
if (resource)
|
||||
coap_resource_release_lkd(resource);
|
||||
coap_delete_string(uri_path);
|
||||
return;
|
||||
|
||||
@@ -4082,6 +4110,8 @@ fail_response:
|
||||
&opt_filter);
|
||||
if (response)
|
||||
goto skip_handler;
|
||||
if (resource)
|
||||
coap_resource_release_lkd(resource);
|
||||
coap_delete_string(uri_path);
|
||||
}
|
||||
#endif /* COAP_SERVER_SUPPORT */
|
||||
@@ -5087,6 +5117,7 @@ coap_startup(void) {
|
||||
(const uint8_t *)".well-known/core"
|
||||
};
|
||||
memset(&resource_uri_wellknown, 0, sizeof(resource_uri_wellknown));
|
||||
resource_uri_wellknown.ref = 1;
|
||||
resource_uri_wellknown.handler[COAP_REQUEST_GET-1] = hnd_get_wellknown_lkd;
|
||||
resource_uri_wellknown.flags = COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT;
|
||||
resource_uri_wellknown.uri_path = &well_known;
|
||||
@@ -5158,6 +5189,15 @@ coap_register_pong_handler(coap_context_t *context,
|
||||
context->pong_handler = handler;
|
||||
}
|
||||
|
||||
void
|
||||
coap_register_dynamic_resource_handler(coap_context_t *context,
|
||||
coap_resource_dynamic_create_t dyn_create_handler,
|
||||
uint32_t dynamic_max) {
|
||||
context->dyn_create_handler = dyn_create_handler;
|
||||
context->dynamic_max = dynamic_max;
|
||||
return;
|
||||
}
|
||||
|
||||
COAP_API void
|
||||
coap_register_option(coap_context_t *ctx, uint16_t type) {
|
||||
coap_lock_lock(return);
|
||||
|
@@ -265,6 +265,7 @@ coap_resource_init(coap_str_const_t *uri_path, int flags) {
|
||||
r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t));
|
||||
if (r) {
|
||||
memset(r, 0, sizeof(coap_resource_t));
|
||||
r->ref = 1;
|
||||
|
||||
if (!(flags & COAP_RESOURCE_FLAGS_RELEASE_URI)) {
|
||||
/* Need to take a copy if caller is not providing a release request */
|
||||
@@ -299,6 +300,7 @@ coap_resource_unknown_init2(coap_method_handler_t put_handler, int flags) {
|
||||
r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t));
|
||||
if (r) {
|
||||
memset(r, 0, sizeof(coap_resource_t));
|
||||
r->ref = 1;
|
||||
r->is_unknown = 1;
|
||||
/* Something unlikely to be used, but it shows up in the logs */
|
||||
r->uri_path = coap_new_str_const(coap_unknown_resource_uri, sizeof(coap_unknown_resource_uri)-1);
|
||||
@@ -329,6 +331,7 @@ coap_resource_proxy_uri_init2(coap_method_handler_t handler,
|
||||
if (r) {
|
||||
size_t i;
|
||||
memset(r, 0, sizeof(coap_resource_t));
|
||||
r->ref = 1;
|
||||
r->is_proxy_uri = 1;
|
||||
/* Something unlikely to be used, but it shows up in the logs */
|
||||
r->uri_path = coap_new_str_const(coap_proxy_resource_uri, sizeof(coap_proxy_resource_uri)-1);
|
||||
@@ -381,6 +384,7 @@ coap_resource_reverse_proxy_init(coap_method_handler_t handler, int flags) {
|
||||
r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t));
|
||||
if (r) {
|
||||
memset(r, 0, sizeof(coap_resource_t));
|
||||
r->ref = 1;
|
||||
r->is_unknown = 1;
|
||||
r->is_reverse_proxy = 1;
|
||||
/* Something unlikely to be used, but it shows up in the logs */
|
||||
@@ -513,6 +517,17 @@ coap_free_resource(coap_resource_t *resource, coap_deleting_resource_t deleting)
|
||||
LL_FOREACH_SAFE(resource->subscribers, obs, otmp) {
|
||||
coap_delete_observer_internal(resource, obs->session, obs);
|
||||
}
|
||||
coap_resource_release_lkd(resource);
|
||||
}
|
||||
|
||||
void
|
||||
coap_resource_release_lkd(coap_resource_t *resource) {
|
||||
|
||||
assert(resource->ref);
|
||||
resource->ref--;
|
||||
if (resource->ref)
|
||||
return;
|
||||
|
||||
if (resource->proxy_name_count && resource->proxy_name_list) {
|
||||
size_t i;
|
||||
|
||||
@@ -580,13 +595,9 @@ coap_delete_resource(coap_context_t *context, coap_resource_t *resource) {
|
||||
return 0;
|
||||
|
||||
context = resource->context;
|
||||
if (context) {
|
||||
coap_lock_lock(return 0);
|
||||
ret = coap_delete_resource_lkd(context, resource);
|
||||
coap_lock_unlock();
|
||||
} else {
|
||||
ret = coap_delete_resource_lkd(context, resource);
|
||||
}
|
||||
coap_lock_lock(return 0);
|
||||
ret = coap_delete_resource_lkd(context, resource);
|
||||
coap_lock_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -595,13 +606,12 @@ coap_delete_resource(coap_context_t *context, coap_resource_t *resource) {
|
||||
*/
|
||||
int
|
||||
coap_delete_resource_lkd(coap_context_t *context, coap_resource_t *resource) {
|
||||
(void)context;
|
||||
|
||||
if (!resource)
|
||||
return 0;
|
||||
|
||||
context = resource->context;
|
||||
if (context) {
|
||||
coap_lock_check_locked();
|
||||
}
|
||||
coap_lock_check_locked();
|
||||
|
||||
if (resource->is_unknown) {
|
||||
if (context && context->unknown_resource == resource) {
|
||||
@@ -615,6 +625,12 @@ coap_delete_resource_lkd(coap_context_t *context, coap_resource_t *resource) {
|
||||
/* remove resource from list */
|
||||
RESOURCES_DELETE(context->resources, resource);
|
||||
}
|
||||
if (resource->is_dynamic) {
|
||||
if (context) {
|
||||
assert(context->dynamic_cur);
|
||||
context->dynamic_cur--;
|
||||
}
|
||||
}
|
||||
|
||||
/* and free its allocated memory */
|
||||
coap_free_resource(resource, COAP_DELETING_RESOURCE);
|
||||
@@ -1119,6 +1135,8 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r,
|
||||
return;
|
||||
r->list_being_traversed = 1;
|
||||
|
||||
coap_resource_reference_lkd(r);
|
||||
|
||||
r->partiallydirty = 0;
|
||||
|
||||
LL_FOREACH_SAFE(r->subscribers, obs, otmp) {
|
||||
@@ -1234,6 +1252,7 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r,
|
||||
coap_session_release_lkd(obs_session);
|
||||
coap_pdu_release_lkd(obs_pdu);
|
||||
r->list_being_traversed = 0;
|
||||
coap_resource_release_lkd(r);
|
||||
return);
|
||||
|
||||
/* Check validity of response code */
|
||||
@@ -1246,6 +1265,7 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r,
|
||||
coap_session_release_lkd(obs_session);
|
||||
coap_pdu_release_lkd(obs_pdu);
|
||||
r->list_being_traversed = 0;
|
||||
coap_resource_release_lkd(r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1335,6 +1355,7 @@ cleanup:
|
||||
coap_session_release_lkd(obs_session);
|
||||
coap_pdu_release_lkd(obs_pdu);
|
||||
}
|
||||
coap_resource_release_lkd(r);
|
||||
r->list_being_traversed = 0;
|
||||
}
|
||||
r->dirty = 0;
|
||||
@@ -1501,4 +1522,8 @@ coap_handle_failed_notify(coap_context_t *context,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
coap_resource_reference_lkd(coap_resource_t *resource) {
|
||||
resource->ref++;
|
||||
}
|
||||
#endif /* ! COAP_SERVER_SUPPORT */
|
||||
|
@@ -714,7 +714,8 @@ coap_op_obs_cnt_load_disk(coap_context_t *context) {
|
||||
resource_key.length = strlen(buf);
|
||||
r = coap_get_resource_from_uri_path_lkd(context, &resource_key);
|
||||
if (r) {
|
||||
coap_log_debug("persist: Initial observe number being updated\n");
|
||||
coap_log_debug("persist: Initial observe number being updated '%s' %u\n",
|
||||
buf, observe_num);
|
||||
coap_persist_set_observe_num(r, observe_num);
|
||||
}
|
||||
}
|
||||
@@ -933,7 +934,7 @@ coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
|
||||
coap_pdu_t *response = NULL;
|
||||
coap_string_t *query = NULL;
|
||||
|
||||
if (!ctx->unknown_resource)
|
||||
if (!ctx->unknown_resource && !ctx->dyn_create_handler)
|
||||
return;
|
||||
|
||||
fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
|
||||
@@ -954,7 +955,7 @@ coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
|
||||
if (!r) {
|
||||
/* Create the new resource using the application logic */
|
||||
|
||||
coap_log_debug("persist: dynamic resource being re-created\n");
|
||||
coap_log_debug("persist: dynamic resource '%s' being re-created\n", name->s);
|
||||
/*
|
||||
* Need max space incase PDU is updated with updated token,
|
||||
* huge size etc.
|
||||
@@ -968,24 +969,38 @@ coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
|
||||
raw_packet->length, request)) {
|
||||
goto fail;
|
||||
}
|
||||
if (!ctx->unknown_resource->handler[request->code-1])
|
||||
goto fail;
|
||||
r = ctx->unknown_resource;
|
||||
if ((ctx->dyn_create_handler != NULL) &&
|
||||
(request->code == COAP_REQUEST_CODE_PUT || request->code == COAP_REQUEST_CODE_POST)) {
|
||||
/* Above test must be the same as in handle_request() */
|
||||
if (ctx->dynamic_cur < ctx->dynamic_max || ctx->dynamic_max == 0) {
|
||||
ctx->unknown_pdu = request;
|
||||
ctx->unknown_session = session;
|
||||
coap_lock_callback_ret(r, ctx->dyn_create_handler(session, request));
|
||||
ctx->unknown_pdu = NULL;
|
||||
ctx->unknown_session = NULL;
|
||||
}
|
||||
}
|
||||
if (!r || !r->handler[request->code-1])
|
||||
goto next;
|
||||
|
||||
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 */
|
||||
coap_lock_callback_release(ctx->unknown_resource->handler[request->code-1](ctx->unknown_resource,
|
||||
session, request,
|
||||
query, response),
|
||||
coap_lock_callback_release(r->handler[request->code-1](r,
|
||||
session, request,
|
||||
query, response),
|
||||
/* context is being freed off */
|
||||
goto fail);
|
||||
coap_delete_string(query);
|
||||
query = NULL;
|
||||
coap_delete_pdu_lkd(request);
|
||||
request = NULL;
|
||||
coap_delete_pdu_lkd(response);
|
||||
response = NULL;
|
||||
next:
|
||||
coap_delete_pdu_lkd(request);
|
||||
request = NULL;
|
||||
}
|
||||
coap_delete_string(name);
|
||||
coap_delete_binary(raw_packet);
|
||||
|
Reference in New Issue
Block a user