Merge pull request #1216 from nfi/coap-fixes

CoAP fixes and improvements
This commit is contained in:
Nicolas Tsiftes 2015-10-01 15:38:13 +02:00
commit f9ed78a327
7 changed files with 144 additions and 92 deletions

View File

@ -58,9 +58,9 @@ LIST(observers_list);
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/*- Internal API ------------------------------------------------------------*/ /*- Internal API ------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
coap_observer_t * static coap_observer_t *
coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token,
size_t token_len, const char *uri) size_t token_len, const char *uri, int uri_len)
{ {
/* Remove existing observe relationship, if any. */ /* Remove existing observe relationship, if any. */
coap_remove_observer_by_uri(addr, port, uri); 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); coap_observer_t *o = memb_alloc(&observers_memb);
if(o) { 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); uip_ipaddr_copy(&o->addr, addr);
o->port = port; o->port = port;
o->token_len = token_len; o->token_len = token_len;
@ -177,18 +182,47 @@ coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
coap_notify_observers(resource_t *resource) 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 */ /* build notification */
coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */ 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; 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 - 1);
if(url_len < COAP_OBSERVER_URL_LEN - 1 && subpath != NULL) {
strncpy(&url[url_len], subpath, COAP_OBSERVER_URL_LEN - url_len - 1);
}
/* Ensure url is null terminated because strncpy does not guarantee this */
url[COAP_OBSERVER_URL_LEN - 1] = '\0';
/* 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 */ /* iterate over observers */
url_len = strlen(url);
for(obs = (coap_observer_t *)list_head(observers_list); obs; for(obs = (coap_observer_t *)list_head(observers_list); obs;
obs = obs->next) { 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; coap_transaction_t *transaction = NULL;
/*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */
@ -209,7 +243,7 @@ coap_notify_observers(resource_t *resource)
/* prepare response */ /* prepare response */
notification->mid = transaction->mid; notification->mid = transaction->mid;
resource->get_handler(NULL, notification, resource->get_handler(request, notification,
transaction->packet + COAP_MAX_HEADER_SIZE, transaction->packet + COAP_MAX_HEADER_SIZE,
REST_MAX_CHUNK_SIZE, NULL); REST_MAX_CHUNK_SIZE, NULL);
@ -237,9 +271,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(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(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) {
if(coap_req->observe == 0) { if(coap_req->observe == 0) {
obs = coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, obs = add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
coap_req->token, coap_req->token_len, coap_req->token, coap_req->token_len,
resource->url); coap_req->uri_path, coap_req->uri_path_len);
if(obs) { if(obs) {
coap_set_header_observe(coap_res, (obs->obs_counter)++); coap_set_header_observe(coap_res, (obs->obs_counter)++);
/* /*

View File

@ -43,6 +43,8 @@
#include "er-coap-transactions.h" #include "er-coap-transactions.h"
#include "stimer.h" #include "stimer.h"
#define COAP_OBSERVER_URL_LEN 20
typedef struct coap_observable { typedef struct coap_observable {
uint32_t observe_clock; uint32_t observe_clock;
struct stimer orphan_timer; struct stimer orphan_timer;
@ -54,7 +56,7 @@ typedef struct coap_observable {
typedef struct coap_observer { typedef struct coap_observer {
struct coap_observer *next; /* for LIST */ struct coap_observer *next; /* for LIST */
const char *url; char url[COAP_OBSERVER_URL_LEN];
uip_ipaddr_t addr; uip_ipaddr_t addr;
uint16_t port; uint16_t port;
uint8_t token_len; uint8_t token_len;
@ -68,11 +70,6 @@ typedef struct coap_observer {
} coap_observer_t; } coap_observer_t;
list_t coap_get_observers(void); 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); 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_client(uip_ipaddr_t *addr, uint16_t port);
int coap_remove_observer_by_token(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); uint16_t mid);
void coap_notify_observers(resource_t *resource); 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 coap_observe_handler(resource_t *resource, void *request,
void *response); void *response);

View File

@ -124,7 +124,7 @@ well_known_core_get_handler(void *request, void *response, uint8_t *buffer,
continue; continue;
} }
end = attrib + strlen(attrib); end = attrib + strlen(attrib);
} else { } else if(resource->attributes != NULL) {
attrib = strstr(resource->attributes, filter); attrib = strstr(resource->attributes, filter);
if(attrib == NULL if(attrib == NULL
|| (attrib[strlen(filter)] != '=' || (attrib[strlen(filter)] != '='
@ -159,8 +159,8 @@ well_known_core_get_handler(void *request, void *response, uint8_t *buffer,
} }
#endif #endif
PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource, PRINTF("res: /%s (%p)\npos: s%zu, o%ld, b%zu\n", resource->url, resource,
strpos, *offset, bufpos); strpos, (long)*offset, bufpos);
if(strpos > 0) { if(strpos > 0) {
ADD_CHAR_IF_POSSIBLE(','); ADD_CHAR_IF_POSSIBLE(',');
@ -170,7 +170,7 @@ well_known_core_get_handler(void *request, void *response, uint8_t *buffer,
ADD_STRING_IF_POSSIBLE(resource->url, >=); ADD_STRING_IF_POSSIBLE(resource->url, >=);
ADD_CHAR_IF_POSSIBLE('>'); ADD_CHAR_IF_POSSIBLE('>');
if(resource->attributes[0]) { if(resource->attributes != NULL && resource->attributes[0]) {
ADD_CHAR_IF_POSSIBLE(';'); ADD_CHAR_IF_POSSIBLE(';');
ADD_STRING_IF_POSSIBLE(resource->attributes, >); ADD_STRING_IF_POSSIBLE(resource->attributes, >);
} }
@ -183,7 +183,7 @@ well_known_core_get_handler(void *request, void *response, uint8_t *buffer,
} }
if(bufpos > 0) { if(bufpos > 0) {
PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *)buffer); PRINTF("BUF %zu: %.*s\n", bufpos, (int)bufpos, (char *)buffer);
coap_set_payload(response, buffer, bufpos); coap_set_payload(response, buffer, bufpos);
coap_set_header_content_format(response, APPLICATION_LINK_FORMAT); coap_set_header_content_format(response, APPLICATION_LINK_FORMAT);

View File

@ -113,15 +113,9 @@ coap_send_transaction(coap_transaction_t *t)
(float)t->retrans_timer.timer.interval / CLOCK_SECOND); (float)t->retrans_timer.timer.interval / CLOCK_SECOND);
} }
/*FIXME PROCESS_CONTEXT_BEGIN(transaction_handler_process);
* Hack: Setting timer for responsible process.
* Maybe there is a better way, but avoid posting everything to the process.
*/
struct process *process_actual = PROCESS_CURRENT();
process_current = transaction_handler_process;
etimer_restart(&t->retrans_timer); /* interval updated above */ etimer_restart(&t->retrans_timer); /* interval updated above */
process_current = process_actual; PROCESS_CONTEXT_END(transaction_handler_process);
t = NULL; t = NULL;
} else { } else {

View File

@ -113,19 +113,21 @@ coap_set_option_header(unsigned int delta, size_t length, uint8_t *buffer)
buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length); buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length);
/* avoids code duplication without function overhead */ if(delta > 268) {
unsigned int *x = &delta; buffer[++written] = ((delta - 269) >> 8) & 0xff;
buffer[++written] = (delta - 269) & 0xff;
} else if(delta > 12) {
buffer[++written] = (delta - 13);
}
do { if(length > 268) {
if(*x > 268) { buffer[++written] = ((length - 269) >> 8) & 0xff;
buffer[++written] = (*x - 269) >> 8; buffer[++written] = (length - 269) & 0xff;
buffer[++written] = (*x - 269); } else if(length > 12) {
} else if(*x > 12) { buffer[++written] = (length - 13);
buffer[++written] = (*x - 13); }
}
} while(x != &length && (x = &length));
PRINTF("WRITTEN %u B opt header\n", 1 + written); PRINTF("WRITTEN %zu B opt header\n", 1 + written);
return ++written; return ++written;
} }
@ -148,7 +150,7 @@ coap_serialize_int_option(unsigned int number, unsigned int current_number,
if(0xFFFFFFFF & value) { if(0xFFFFFFFF & value) {
++i; ++i;
} }
PRINTF("OPTION %u (delta %u, len %u)\n", number, number - current_number, PRINTF("OPTION %u (delta %u, len %zu)\n", number, number - current_number,
i); i);
i = coap_set_option_header(number - current_number, i, buffer); i = coap_set_option_header(number - current_number, i, buffer);
@ -175,8 +177,8 @@ coap_serialize_array_option(unsigned int number, unsigned int current_number,
{ {
size_t i = 0; size_t i = 0;
PRINTF("ARRAY type %u, len %u, full [%.*s]\n", number, length, length, PRINTF("ARRAY type %u, len %zu, full [%.*s]\n", number, length,
array); (int)length, array);
if(split_char != '\0') { if(split_char != '\0') {
int j; int j;
@ -185,7 +187,7 @@ coap_serialize_array_option(unsigned int number, unsigned int current_number,
size_t temp_length; size_t temp_length;
for(j = 0; j <= length + 1; ++j) { for(j = 0; j <= length + 1; ++j) {
PRINTF("STEP %u/%u (%c)\n", j, length, array[j]); PRINTF("STEP %u/%zu (%c)\n", j, length, array[j]);
if(array[j] == split_char || j == length) { if(array[j] == split_char || j == length) {
part_end = array + j; part_end = array + j;
temp_length = part_end - part_start; temp_length = part_end - part_start;
@ -195,8 +197,8 @@ coap_serialize_array_option(unsigned int number, unsigned int current_number,
memcpy(&buffer[i], part_start, temp_length); memcpy(&buffer[i], part_start, temp_length);
i += temp_length; i += temp_length;
PRINTF("OPTION type %u, delta %u, len %u, part [%.*s]\n", number, PRINTF("OPTION type %u, delta %u, len %zu, part [%.*s]\n", number,
number - current_number, i, temp_length, part_start); number - current_number, i, (int)temp_length, part_start);
++j; /* skip the splitter */ ++j; /* skip the splitter */
current_number = number; current_number = number;
@ -208,7 +210,7 @@ coap_serialize_array_option(unsigned int number, unsigned int current_number,
memcpy(&buffer[i], array, length); memcpy(&buffer[i], array, length);
i += length; i += length;
PRINTF("OPTION type %u, delta %u, len %u\n", number, PRINTF("OPTION type %u, delta %u, len %zu\n", number,
number - current_number, length); number - current_number, length);
} }
@ -332,7 +334,7 @@ coap_serialize_message(void *packet, uint8_t *buffer)
/* empty packet, dont need to do more stuff */ /* empty packet, dont need to do more stuff */
if(!coap_pkt->code) { if(!coap_pkt->code) {
PRINTF("-Done serializing empty message at %p-\n", option); PRINTF("-Done serializing empty message at %p-\n", coap_pkt->buffer);
return 4; return 4;
} }
@ -368,6 +370,7 @@ coap_serialize_message(void *packet, uint8_t *buffer)
"Location-Path"); "Location-Path");
COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/', COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/',
"Uri-Path"); "Uri-Path");
PRINTF("Serialize content format: %d\n", coap_pkt->content_format);
COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format,
"Content-Format"); "Content-Format");
COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age");
@ -403,8 +406,9 @@ coap_serialize_message(void *packet, uint8_t *buffer)
} }
PRINTF("-Done %u B (header len %u, payload len %u)-\n", PRINTF("-Done %u B (header len %u, payload len %u)-\n",
coap_pkt->payload_len + option - buffer, option - buffer, (unsigned int)(coap_pkt->payload_len + option - buffer),
coap_pkt->payload_len); (unsigned int)(option - buffer),
(unsigned int)coap_pkt->payload_len);
PRINTF("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n", PRINTF("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n",
coap_pkt->buffer[0], coap_pkt->buffer[0],
@ -500,25 +504,31 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
option_length = current_option[0] & 0x0F; option_length = current_option[0] & 0x0F;
++current_option; ++current_option;
/* avoids code duplication without function overhead */ if(option_delta == 13) {
unsigned int *x = &option_delta; option_delta += current_option[0];
++current_option;
} else if(option_delta == 14) {
option_delta += 255;
option_delta += current_option[0] << 8;
++current_option;
option_delta += current_option[0];
++current_option;
}
do { if(option_length == 13) {
if(*x == 13) { option_length += current_option[0];
*x += current_option[0]; ++current_option;
++current_option; } else if(option_length == 14) {
} else if(*x == 14) { option_length += 255;
*x += 255; option_length += current_option[0] << 8;
*x += current_option[0] << 8; ++current_option;
++current_option; option_length += current_option[0];
*x += current_option[0]; ++current_option;
++current_option; }
}
} while(x != &option_length && (x = &option_length));
option_number += option_delta; option_number += option_delta;
PRINTF("OPTION %u (delta %u, len %u): ", option_number, option_delta, PRINTF("OPTION %u (delta %u, len %zu): ", option_number, option_delta,
option_length); option_length);
SET_OPTION(coap_pkt, option_number); SET_OPTION(coap_pkt, option_number);
@ -532,7 +542,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
case COAP_OPTION_MAX_AGE: case COAP_OPTION_MAX_AGE:
coap_pkt->max_age = coap_parse_int_option(current_option, coap_pkt->max_age = coap_parse_int_option(current_option,
option_length); option_length);
PRINTF("Max-Age [%lu]\n", coap_pkt->max_age); PRINTF("Max-Age [%lu]\n", (unsigned long)coap_pkt->max_age);
break; break;
case COAP_OPTION_ETAG: case COAP_OPTION_ETAG:
coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length); coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length);
@ -569,7 +579,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_pkt->proxy_uri = (char *)current_option; coap_pkt->proxy_uri = (char *)current_option;
coap_pkt->proxy_uri_len = option_length; coap_pkt->proxy_uri_len = option_length;
#endif #endif
PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", (int)coap_pkt->proxy_uri_len,
coap_pkt->proxy_uri); coap_pkt->proxy_uri);
coap_error_message = "This is a constrained server (Contiki)"; coap_error_message = "This is a constrained server (Contiki)";
return PROXYING_NOT_SUPPORTED_5_05; return PROXYING_NOT_SUPPORTED_5_05;
@ -580,7 +590,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_pkt->proxy_scheme_len = option_length; coap_pkt->proxy_scheme_len = option_length;
#endif #endif
PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n",
coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme); (int)coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme);
coap_error_message = "This is a constrained server (Contiki)"; coap_error_message = "This is a constrained server (Contiki)";
return PROXYING_NOT_SUPPORTED_5_05; return PROXYING_NOT_SUPPORTED_5_05;
break; break;
@ -588,7 +598,8 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
case COAP_OPTION_URI_HOST: case COAP_OPTION_URI_HOST:
coap_pkt->uri_host = (char *)current_option; coap_pkt->uri_host = (char *)current_option;
coap_pkt->uri_host_len = option_length; coap_pkt->uri_host_len = option_length;
PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); PRINTF("Uri-Host [%.*s]\n", (int)coap_pkt->uri_host_len,
coap_pkt->uri_host);
break; break;
case COAP_OPTION_URI_PORT: case COAP_OPTION_URI_PORT:
coap_pkt->uri_port = coap_parse_int_option(current_option, coap_pkt->uri_port = coap_parse_int_option(current_option,
@ -600,14 +611,14 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_merge_multi_option((char **)&(coap_pkt->uri_path), coap_merge_multi_option((char **)&(coap_pkt->uri_path),
&(coap_pkt->uri_path_len), current_option, &(coap_pkt->uri_path_len), current_option,
option_length, '/'); option_length, '/');
PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->uri_path); PRINTF("Uri-Path [%.*s]\n", (int)coap_pkt->uri_path_len, coap_pkt->uri_path);
break; break;
case COAP_OPTION_URI_QUERY: case COAP_OPTION_URI_QUERY:
/* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */
coap_merge_multi_option((char **)&(coap_pkt->uri_query), coap_merge_multi_option((char **)&(coap_pkt->uri_query),
&(coap_pkt->uri_query_len), current_option, &(coap_pkt->uri_query_len), current_option,
option_length, '&'); option_length, '&');
PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, PRINTF("Uri-Query [%.*s]\n", (int)coap_pkt->uri_query_len,
coap_pkt->uri_query); coap_pkt->uri_query);
break; break;
@ -616,7 +627,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_merge_multi_option((char **)&(coap_pkt->location_path), coap_merge_multi_option((char **)&(coap_pkt->location_path),
&(coap_pkt->location_path_len), current_option, &(coap_pkt->location_path_len), current_option,
option_length, '/'); option_length, '/');
PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, PRINTF("Location-Path [%.*s]\n", (int)coap_pkt->location_path_len,
coap_pkt->location_path); coap_pkt->location_path);
break; break;
case COAP_OPTION_LOCATION_QUERY: case COAP_OPTION_LOCATION_QUERY:
@ -624,14 +635,14 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_merge_multi_option((char **)&(coap_pkt->location_query), coap_merge_multi_option((char **)&(coap_pkt->location_query),
&(coap_pkt->location_query_len), current_option, &(coap_pkt->location_query_len), current_option,
option_length, '&'); option_length, '&');
PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, PRINTF("Location-Query [%.*s]\n", (int)coap_pkt->location_query_len,
coap_pkt->location_query); coap_pkt->location_query);
break; break;
case COAP_OPTION_OBSERVE: case COAP_OPTION_OBSERVE:
coap_pkt->observe = coap_parse_int_option(current_option, coap_pkt->observe = coap_parse_int_option(current_option,
option_length); option_length);
PRINTF("Observe [%lu]\n", coap_pkt->observe); PRINTF("Observe [%lu]\n", (unsigned long)coap_pkt->observe);
break; break;
case COAP_OPTION_BLOCK2: case COAP_OPTION_BLOCK2:
coap_pkt->block2_num = coap_parse_int_option(current_option, coap_pkt->block2_num = coap_parse_int_option(current_option,
@ -641,7 +652,8 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F) coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)
<< (coap_pkt->block2_num & 0x07); << (coap_pkt->block2_num & 0x07);
coap_pkt->block2_num >>= 4; coap_pkt->block2_num >>= 4;
PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, PRINTF("Block2 [%lu%s (%u B/blk)]\n",
(unsigned long)coap_pkt->block2_num,
coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size);
break; break;
case COAP_OPTION_BLOCK1: case COAP_OPTION_BLOCK1:
@ -652,16 +664,17 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F) coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F)
<< (coap_pkt->block1_num & 0x07); << (coap_pkt->block1_num & 0x07);
coap_pkt->block1_num >>= 4; coap_pkt->block1_num >>= 4;
PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, PRINTF("Block1 [%lu%s (%u B/blk)]\n",
(unsigned long)coap_pkt->block1_num,
coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size); coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size);
break; break;
case COAP_OPTION_SIZE2: case COAP_OPTION_SIZE2:
coap_pkt->size2 = coap_parse_int_option(current_option, option_length); coap_pkt->size2 = coap_parse_int_option(current_option, option_length);
PRINTF("Size2 [%lu]\n", coap_pkt->size2); PRINTF("Size2 [%lu]\n", (unsigned long)coap_pkt->size2);
break; break;
case COAP_OPTION_SIZE1: case COAP_OPTION_SIZE1:
coap_pkt->size1 = coap_parse_int_option(current_option, option_length); coap_pkt->size1 = coap_parse_int_option(current_option, option_length);
PRINTF("Size1 [%lu]\n", coap_pkt->size1); PRINTF("Size1 [%lu]\n", (unsigned long)coap_pkt->size1);
break; break;
default: default:
PRINTF("unknown (%u)\n", option_number); PRINTF("unknown (%u)\n", option_number);
@ -744,7 +757,7 @@ coap_set_header_content_format(void *packet, unsigned int format)
{ {
coap_packet_t *const coap_pkt = (coap_packet_t *)packet; coap_packet_t *const coap_pkt = (coap_packet_t *)packet;
coap_pkt->content_format = (coap_content_format_t)format; coap_pkt->content_format = format;
SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT); SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT);
return 1; return 1;
} }
@ -765,7 +778,7 @@ coap_set_header_accept(void *packet, unsigned int accept)
{ {
coap_packet_t *const coap_pkt = (coap_packet_t *)packet; coap_packet_t *const coap_pkt = (coap_packet_t *)packet;
coap_pkt->accept = (coap_content_format_t)accept; coap_pkt->accept = accept;
SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT);
return 1; return 1;
} }

View File

@ -93,7 +93,7 @@ typedef struct {
uint8_t options[COAP_OPTION_SIZE1 / OPTION_MAP_SIZE + 1]; /* bitmap to check if option is set */ uint8_t options[COAP_OPTION_SIZE1 / OPTION_MAP_SIZE + 1]; /* bitmap to check if option is set */
coap_content_format_t content_format; /* parse options once and store; allows setting options in random order */ uint16_t content_format; /* parse options once and store; allows setting options in random order */
uint32_t max_age; uint32_t max_age;
uint8_t etag_len; uint8_t etag_len;
uint8_t etag[COAP_ETAG_LEN]; uint8_t etag[COAP_ETAG_LEN];
@ -111,7 +111,7 @@ typedef struct {
size_t uri_path_len; size_t uri_path_len;
const char *uri_path; const char *uri_path;
int32_t observe; int32_t observe;
coap_content_format_t accept; uint16_t accept;
uint8_t if_match_len; uint8_t if_match_len;
uint8_t if_match[COAP_ETAG_LEN]; uint8_t if_match[COAP_ETAG_LEN];
uint32_t block2_num; uint32_t block2_num;
@ -135,13 +135,13 @@ typedef struct {
/* option format serialization */ /* option format serialization */
#define COAP_SERIALIZE_INT_OPTION(number, field, text) \ #define COAP_SERIALIZE_INT_OPTION(number, field, text) \
if(IS_OPTION(coap_pkt, number)) { \ if(IS_OPTION(coap_pkt, number)) { \
PRINTF(text " [%u]\n", coap_pkt->field); \ PRINTF(text " [%u]\n", (unsigned int)coap_pkt->field); \
option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \ option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \
current_number = number; \ current_number = number; \
} }
#define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \ #define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \
if(IS_OPTION(coap_pkt, number)) { \ if(IS_OPTION(coap_pkt, number)) { \
PRINTF(text " %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->field##_len, \ PRINTF(text " %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", (unsigned int)coap_pkt->field##_len, \
coap_pkt->field[0], \ coap_pkt->field[0], \
coap_pkt->field[1], \ coap_pkt->field[1], \
coap_pkt->field[2], \ coap_pkt->field[2], \
@ -156,18 +156,18 @@ typedef struct {
} }
#define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \ #define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \
if(IS_OPTION(coap_pkt, number)) { \ if(IS_OPTION(coap_pkt, number)) { \
PRINTF(text " [%.*s]\n", coap_pkt->field##_len, coap_pkt->field); \ PRINTF(text " [%.*s]\n", (int)coap_pkt->field##_len, coap_pkt->field); \
option += coap_serialize_array_option(number, current_number, option, (uint8_t *)coap_pkt->field, coap_pkt->field##_len, splitter); \ option += coap_serialize_array_option(number, current_number, option, (uint8_t *)coap_pkt->field, coap_pkt->field##_len, splitter); \
current_number = number; \ current_number = number; \
} }
#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \ #define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \
if(IS_OPTION(coap_pkt, number)) \ if(IS_OPTION(coap_pkt, number)) \
{ \ { \
PRINTF(text " [%lu%s (%u B/blk)]\n", coap_pkt->field##_num, coap_pkt->field##_more ? "+" : "", coap_pkt->field##_size); \ PRINTF(text " [%lu%s (%u B/blk)]\n", (unsigned long)coap_pkt->field##_num, coap_pkt->field##_more ? "+" : "", coap_pkt->field##_size); \
uint32_t block = coap_pkt->field##_num << 4; \ uint32_t block = coap_pkt->field##_num << 4; \
if(coap_pkt->field##_more) { block |= 0x8; } \ if(coap_pkt->field##_more) { block |= 0x8; } \
block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \ block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \
PRINTF(text " encoded: 0x%lX\n", block); \ PRINTF(text " encoded: 0x%lX\n", (unsigned long)block); \
option += coap_serialize_int_option(number, current_number, option, block); \ option += coap_serialize_int_option(number, current_number, option, block); \
current_number = number; \ current_number = number; \
} }

View File

@ -70,6 +70,15 @@ LIST(restful_periodic_services);
void void
rest_init_engine(void) rest_init_engine(void)
{ {
/* avoid initializing twice */
static uint8_t initialized = 0;
if(initialized) {
PRINTF("REST engine process already running - double initialization?\n");
return;
}
initialized = 1;
list_init(restful_services); list_init(restful_services);
REST.set_service_callback(rest_invoke_restful_service); REST.set_service_callback(rest_invoke_restful_service);
@ -124,15 +133,19 @@ rest_invoke_restful_service(void *request, void *response, uint8_t *buffer,
resource_t *resource = NULL; resource_t *resource = NULL;
const char *url = NULL; 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); for(resource = (resource_t *)list_head(restful_services);
resource; resource = resource->next) { resource; resource = resource->next) {
/* if the web service handles that kind of requests and urls matches */ /* if the web service handles that kind of requests and urls matches */
if((REST.get_url(request, &url) == strlen(resource->url) res_url_len = strlen(resource->url);
|| (REST.get_url(request, &url) > strlen(resource->url) if((url_len == res_url_len
&& (resource->flags & HAS_SUB_RESOURCES))) || (url_len > res_url_len
&& strncmp(resource->url, url, strlen(resource->url)) == 0) { && (resource->flags & HAS_SUB_RESOURCES)
&& url[res_url_len] == '/'))
&& strncmp(resource->url, url, res_url_len) == 0) {
found = 1; found = 1;
rest_resource_flags_t method = REST.get_method_type(request); rest_resource_flags_t method = REST.get_method_type(request);