From 1b0cdee9eca4037371fe67128be9a659873253da Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Wed, 6 May 2015 18:14:29 +0200 Subject: [PATCH] Fixed observe to handle subresources and to always create a fake request for notify GETs --- apps/er-coap/er-coap-observe.c | 54 +++++++++++++++++++++++++++------- apps/er-coap/er-coap-observe.h | 10 +++---- apps/rest-engine/rest-engine.c | 2 +- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/apps/er-coap/er-coap-observe.c b/apps/er-coap/er-coap-observe.c index 710671bff..ef533cf70 100644 --- a/apps/er-coap/er-coap-observe.c +++ b/apps/er-coap/er-coap-observe.c @@ -58,9 +58,9 @@ LIST(observers_list); /*---------------------------------------------------------------------------*/ /*- Internal API ------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -coap_observer_t * -coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, - size_t token_len, const char *uri) +static coap_observer_t * +add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, + size_t token_len, const char *uri, int uri_len) { /* Remove existing observe relationship, if any. */ coap_remove_observer_by_uri(addr, port, uri); @@ -68,7 +68,12 @@ coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, coap_observer_t *o = memb_alloc(&observers_memb); if(o) { - o->url = uri; + int max = sizeof(o->url) - 1; + if(max > uri_len) { + max = uri_len; + } + memcpy(o->url, uri, max); + o->url[max] = 0; uip_ipaddr_copy(&o->addr, addr); o->port = port; o->token_len = token_len; @@ -177,18 +182,45 @@ coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid) /*---------------------------------------------------------------------------*/ void coap_notify_observers(resource_t *resource) +{ + coap_notify_observers_sub(resource, NULL); +} +void +coap_notify_observers_sub(resource_t *resource, const char *subpath) { /* build notification */ coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */ - coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0); + coap_packet_t request[1]; /* this way the packet can be treated as pointer as usual */ coap_observer_t *obs = NULL; + int url_len, obs_url_len; + char url[COAP_OBSERVER_URL_LEN]; - PRINTF("Observe: Notification from %s\n", resource->url); + url_len = strlen(resource->url); + strncpy(url, resource->url, COAP_OBSERVER_URL_LEN); + if(strlen(url) < COAP_OBSERVER_URL_LEN && subpath != NULL) { + strncpy(&url[url_len], subpath, COAP_OBSERVER_URL_LEN - url_len); + } + /* url now contains the notify URL that needs to match the observer */ + PRINTF("Observe: Notification from %s\n", url); + + coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0); + /* create a "fake" request for the URI */ + coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0); + coap_set_header_uri_path(request, url); /* iterate over observers */ + url_len = strlen(url); for(obs = (coap_observer_t *)list_head(observers_list); obs; obs = obs->next) { - if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */ + obs_url_len = strlen(obs->url); + + /* Do a match based on the parent/sub-resource match so that it is + possible to do parent-node observe */ + if((obs_url_len == url_len + || (obs_url_len > url_len + && (resource->flags & HAS_SUB_RESOURCES) + && obs->url[url_len] == '/')) + && strncmp(url, obs->url, url_len) == 0) { coap_transaction_t *transaction = NULL; /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ @@ -209,7 +241,7 @@ coap_notify_observers(resource_t *resource) /* prepare response */ notification->mid = transaction->mid; - resource->get_handler(NULL, notification, + resource->get_handler(request, notification, transaction->packet + COAP_MAX_HEADER_SIZE, REST_MAX_CHUNK_SIZE, NULL); @@ -237,9 +269,9 @@ coap_observe_handler(resource_t *resource, void *request, void *response) if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */ if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) { if(coap_req->observe == 0) { - obs = coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, - coap_req->token, coap_req->token_len, - resource->url); + obs = add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, + coap_req->token, coap_req->token_len, + coap_req->uri_path, coap_req->uri_path_len); if(obs) { coap_set_header_observe(coap_res, (obs->obs_counter)++); /* diff --git a/apps/er-coap/er-coap-observe.h b/apps/er-coap/er-coap-observe.h index 6d0498bb6..4e9644bf0 100644 --- a/apps/er-coap/er-coap-observe.h +++ b/apps/er-coap/er-coap-observe.h @@ -43,6 +43,8 @@ #include "er-coap-transactions.h" #include "stimer.h" +#define COAP_OBSERVER_URL_LEN 20 + typedef struct coap_observable { uint32_t observe_clock; struct stimer orphan_timer; @@ -54,7 +56,7 @@ typedef struct coap_observable { typedef struct coap_observer { struct coap_observer *next; /* for LIST */ - const char *url; + char url[COAP_OBSERVER_URL_LEN]; uip_ipaddr_t addr; uint16_t port; uint8_t token_len; @@ -68,11 +70,6 @@ typedef struct coap_observer { } coap_observer_t; list_t coap_get_observers(void); - -coap_observer_t *coap_add_observer(uip_ipaddr_t *addr, uint16_t port, - const uint8_t *token, size_t token_len, - const char *url); - void coap_remove_observer(coap_observer_t *o); int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port); int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, @@ -83,6 +80,7 @@ int coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid); void coap_notify_observers(resource_t *resource); +void coap_notify_observers_sub(resource_t *resource, const char *subpath); void coap_observe_handler(resource_t *resource, void *request, void *response); diff --git a/apps/rest-engine/rest-engine.c b/apps/rest-engine/rest-engine.c index 038acb025..f74d2a9a9 100644 --- a/apps/rest-engine/rest-engine.c +++ b/apps/rest-engine/rest-engine.c @@ -126,11 +126,11 @@ rest_invoke_restful_service(void *request, void *response, uint8_t *buffer, const char *url = NULL; int url_len, res_url_len; + url_len = REST.get_url(request, &url); for(resource = (resource_t *)list_head(restful_services); resource; resource = resource->next) { /* if the web service handles that kind of requests and urls matches */ - url_len = REST.get_url(request, &url); res_url_len = strlen(resource->url); if((url_len == res_url_len || (url_len > res_url_len