From 386d708b56992879c1be0bd0066a6dc07e268380 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Wed, 23 Apr 2014 10:13:10 +0200 Subject: [PATCH] Added function for easy block1 usage. Fixed blocksize calculation when REST_MAX_CHUNK_SIZE != 2^x. Added example for block1 + separate + block2. --- apps/er-coap/Makefile.er-coap | 2 +- apps/er-coap/er-coap-block1.c | 119 ++++++++++++++++++ apps/er-coap/er-coap-block1.h | 47 +++++++ apps/er-coap/er-coap-constants.h | 5 + apps/er-coap/er-coap-engine.c | 33 ++++- apps/er-coap/er-coap-res-well-known-core.c | 82 +++++------- apps/er-coap/er-coap-separate.c | 9 +- apps/er-coap/er-coap-separate.h | 4 +- apps/er-coap/er-coap.c | 12 +- apps/er-coap/er-coap.h | 11 ++ examples/er-rest-example/er-example-server.c | 4 +- examples/er-rest-example/project-conf.h | 2 +- .../er-rest-example/resources/res-b1-sep-b2.c | 111 ++++++++++++++++ .../resources/res-plugtest-query.c | 3 +- 14 files changed, 377 insertions(+), 67 deletions(-) create mode 100644 apps/er-coap/er-coap-block1.c create mode 100644 apps/er-coap/er-coap-block1.h create mode 100644 examples/er-rest-example/resources/res-b1-sep-b2.c diff --git a/apps/er-coap/Makefile.er-coap b/apps/er-coap/Makefile.er-coap index 8d467793b..096b10e2e 100755 --- a/apps/er-coap/Makefile.er-coap +++ b/apps/er-coap/Makefile.er-coap @@ -1,4 +1,4 @@ -er-coap_src = er-coap.c er-coap-engine.c er-coap-transactions.c er-coap-observe.c er-coap-separate.c er-coap-res-well-known-core.c +er-coap_src = er-coap.c er-coap-engine.c er-coap-transactions.c er-coap-observe.c er-coap-separate.c er-coap-res-well-known-core.c er-coap-block1.c # Erbium will implement the REST Engine CFLAGS += -DREST=coap_rest_implementation diff --git a/apps/er-coap/er-coap-block1.c b/apps/er-coap/er-coap-block1.c new file mode 100644 index 000000000..2f895b5fa --- /dev/null +++ b/apps/er-coap/er-coap-block1.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * CoAP module for block 1 handling + * \author + * Lars Schmertmann + */ + +#include +#include + +#include "er-coap.h" +#include "er-coap-block1.h" + +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +/*----------------------------------------------------------------------------*/ + +/** + * \brief Block 1 support within a coap-ressource + * + * This function will help you to use block 1. If target is null + * error handling and response configuration is active. On return + * value 0, the last block was recived, while on return value 1 + * more blocks will follow. With target, len and maxlen this + * function will assemble the blocks. + * + * You can find an example in: + * examples/er-rest-example/resources/res-b1-sep-b2.c + * + * \param request Request pointer from the handler + * \param response Response pointer from the handler + * \param target Pointer to the buffer where the request payload can be assembled + * \param len Pointer to the variable, where the function stores the actual length + * \param max_len Length of the "target"-Buffer + * + * \return 0 if initialisation was successful + * -1 if initialisation failed + */ +int +coap_block1_handler(void *request, void *response, uint8_t *target, size_t *len, size_t max_len) +{ + const uint8_t *payload = 0; + int pay_len = REST.get_request_payload(request, &payload); + + if(!pay_len || !payload) { + erbium_status_code = REST.status.BAD_REQUEST; + coap_error_message = "NoPayload"; + return -1; + } + + coap_packet_t *packet = (coap_packet_t *)request; + + if(packet->block1_offset + pay_len > max_len) { + erbium_status_code = REST.status.REQUEST_ENTITY_TOO_LARGE; + coap_error_message = "Message to big"; + return -1; + } + + if(target && len) { + memcpy(target + packet->block1_offset, payload, pay_len); + *len = packet->block1_offset + pay_len; + } + + if(IS_OPTION(packet, COAP_OPTION_BLOCK1)) { + PRINTF("Blockwise: block 1 request: Num: %u, More: %u, Size: %u, Offset: %u\n", + packet->block1_num, + packet->block1_more, + packet->block1_size, + packet->block1_offset); + + coap_set_header_block1(response, packet->block1_num, packet->block1_more, packet->block1_size); + if(packet->block1_more) { + coap_set_status_code(response, CONTINUE_2_31); + return 1; + } + } + + return 0; +} diff --git a/apps/er-coap/er-coap-block1.h b/apps/er-coap/er-coap-block1.h new file mode 100644 index 000000000..a6b1de5ab --- /dev/null +++ b/apps/er-coap/er-coap-block1.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * CoAP module for block 1 handling + * \author + * Lars Schmertmann + */ + +#ifndef COAP_BLOCK1_H_ +#define COAP_BLOCK1_H_ + +#include +#include + +int coap_block1_handler(void *request, void *response, uint8_t *target, size_t *len, size_t max_len); + +#endif /* COAP_BLOCK1_H_ */ diff --git a/apps/er-coap/er-coap-constants.h b/apps/er-coap/er-coap-constants.h index 8017b03d5..4ed0b8212 100644 --- a/apps/er-coap/er-coap-constants.h +++ b/apps/er-coap/er-coap-constants.h @@ -39,7 +39,11 @@ #ifndef ER_COAP_CONSTANTS_H_ #define ER_COAP_CONSTANTS_H_ +#ifdef WITH_DTLS +#define COAP_DEFAULT_PORT 5684 +#else #define COAP_DEFAULT_PORT 5683 +#endif #define COAP_DEFAULT_MAX_AGE 60 #define COAP_RESPONSE_TIMEOUT 3 @@ -85,6 +89,7 @@ typedef enum { VALID_2_03 = 67, /* NOT_MODIFIED */ CHANGED_2_04 = 68, /* CHANGED */ CONTENT_2_05 = 69, /* OK */ + CONTINUE_2_31 = 95, /* CONTINUE */ BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */ UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */ diff --git a/apps/er-coap/er-coap-engine.c b/apps/er-coap/er-coap-engine.c index c8b0c82ed..b45a3c3f4 100644 --- a/apps/er-coap/er-coap-engine.c +++ b/apps/er-coap/er-coap-engine.c @@ -40,6 +40,9 @@ #include #include #include "er-coap-engine.h" +#ifdef WITH_DTLS +#include "er-dtls.h" +#endif #define DEBUG 0 #if DEBUG @@ -83,8 +86,18 @@ coap_receive(void) PRINTF(":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen()); +#ifdef WITH_DTLS + CoapData_t coapdata = { 0, NULL, 0 }; + dtls_parse_message(uip_appdata, uip_datalen(), &coapdata); + if(!coapdata.valid) { + return NO_ERROR; + } + erbium_status_code = + coap_parse_message(message, coapdata.data, coapdata.data_len); +#else erbium_status_code = coap_parse_message(message, uip_appdata, uip_datalen()); +#endif if(erbium_status_code == NO_ERROR) { @@ -117,8 +130,7 @@ coap_receive(void) coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); /* mirror token */ - } - if(message->token_len) { + } if(message->token_len) { coap_set_token(response, message->token, message->token_len); /* get offset for blockwise transfers */ } @@ -195,17 +207,17 @@ coap_receive(void) } else if(new_offset != 0) { PRINTF ("Blockwise: no block option for blockwise resource, using block size %u\n", - REST_MAX_CHUNK_SIZE); + COAP_MAX_BLOCK_SIZE); coap_set_header_block2(response, 0, new_offset != -1, - REST_MAX_CHUNK_SIZE); + COAP_MAX_BLOCK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, - REST_MAX_CHUNK_SIZE)); + COAP_MAX_BLOCK_SIZE)); } /* blockwise transfer handling */ } /* no errors/hooks */ /* successful service callback */ - /* serialize response */ + /* serialize response */ } if(erbium_status_code == NO_ERROR) { if((transaction->packet_len = coap_serialize_message(response, @@ -317,14 +329,23 @@ coap_get_rest_method(void *packet) /* the discover resource is automatically included for CoAP */ extern resource_t res_well_known_core; +#ifdef WITH_DTLS +extern resource_t res_dtls; +#endif /*---------------------------------------------------------------------------*/ PROCESS_THREAD(coap_engine, ev, data) { PROCESS_BEGIN(); +#ifdef WITH_DTLS + aes_init(); +#endif PRINTF("Starting %s receiver...\n", coap_rest_implementation.name); rest_activate_resource(&res_well_known_core, ".well-known/core"); +#ifdef WITH_DTLS + rest_activate_resource(&res_dtls, "dtls"); +#endif coap_register_as_transaction_handler(); coap_init_connection(SERVER_LISTEN_PORT); diff --git a/apps/er-coap/er-coap-res-well-known-core.c b/apps/er-coap/er-coap-res-well-known-core.c index 69e6e7a97..e684017cd 100644 --- a/apps/er-coap/er-coap-res-well-known-core.c +++ b/apps/er-coap/er-coap-res-well-known-core.c @@ -51,6 +51,28 @@ #define PRINTLLADDR(addr) #endif +#define ADD_CHAR_IF_POSSIBLE(char) \ + if(strpos >= *offset && bufpos < preferred_size) { \ + buffer[bufpos++] = char; \ + } \ + ++strpos + +#define ADD_STRING_IF_POSSIBLE(string, op) \ + tmplen = strlen(string); \ + if(strpos + tmplen > *offset) { \ + bufpos += snprintf((char *)buffer + bufpos, \ + preferred_size - bufpos + 1, \ + "%s", \ + string \ + + (*offset - (int32_t)strpos > 0 ? \ + *offset - (int32_t)strpos : 0)); \ + if(bufpos op preferred_size) { \ + PRINTF("res: BREAK at %s (%p)\n", string, resource); \ + break; \ + } \ + } \ + strpos += tmplen + /*---------------------------------------------------------------------------*/ /*- Resource Handlers -------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -141,62 +163,16 @@ well_known_core_get_handler(void *request, void *response, uint8_t *buffer, strpos, *offset, bufpos); if(strpos > 0) { - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = ','; - } - ++strpos; + ADD_CHAR_IF_POSSIBLE(','); } - - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = '<'; - } - ++strpos; - - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = '/'; - } - ++strpos; - - tmplen = strlen(resource->url); - if(strpos + tmplen > *offset) { - bufpos += snprintf((char *)buffer + bufpos, - preferred_size - bufpos + 1, - "%s", - resource->url + - ((*offset - (int32_t)strpos > - 0) ? (*offset - (int32_t)strpos) : 0)); - /* native requires these casts */ - if(bufpos >= preferred_size) { - PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); - break; - } - } - strpos += tmplen; - - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = '>'; - } - ++strpos; + ADD_CHAR_IF_POSSIBLE('<'); + ADD_CHAR_IF_POSSIBLE('/'); + ADD_STRING_IF_POSSIBLE(resource->url, >=); + ADD_CHAR_IF_POSSIBLE('>'); if(resource->attributes[0]) { - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = ';'; - } - ++strpos; - - tmplen = strlen(resource->attributes); - if(strpos + tmplen > *offset) { - bufpos += snprintf((char *)buffer + bufpos, - preferred_size - bufpos + 1, - resource->attributes - + (*offset - (int32_t)strpos > 0 ? - *offset - (int32_t)strpos : 0)); - if(bufpos > preferred_size) { - PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); - break; - } - } - strpos += tmplen; + ADD_CHAR_IF_POSSIBLE(';'); + ADD_STRING_IF_POSSIBLE(resource->attributes, >); } /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ diff --git a/apps/er-coap/er-coap-separate.c b/apps/er-coap/er-coap-separate.c index 7d53e5b9f..d35566d79 100644 --- a/apps/er-coap/er-coap-separate.c +++ b/apps/er-coap/er-coap-separate.c @@ -116,8 +116,11 @@ coap_separate_accept(void *request, coap_separate_t *separate_store) memcpy(separate_store->token, coap_req->token, coap_req->token_len); separate_store->token_len = coap_req->token_len; + separate_store->block1_num = coap_req->block1_num; + separate_store->block1_size = coap_req->block1_size; + separate_store->block2_num = coap_req->block2_num; - separate_store->block2_size = coap_req->block2_size; + separate_store->block2_size = coap_req->block2_size > 0 ? MIN(COAP_MAX_BLOCK_SIZE, coap_req->block2_size) : COAP_MAX_BLOCK_SIZE; /* signal the engine to skip automatic response and clear transaction by engine */ erbium_status_code = MANUAL_RESPONSE; @@ -137,5 +140,9 @@ coap_separate_resume(void *response, coap_separate_t *separate_store, coap_set_token(response, separate_store->token, separate_store->token_len); } + if(separate_store->block1_size) { + coap_set_header_block1(response, separate_store->block1_num, + 0, separate_store->block1_size); + } } /*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-separate.h b/apps/er-coap/er-coap-separate.h index 20c6dd65d..dbecf1b39 100644 --- a/apps/er-coap/er-coap-separate.h +++ b/apps/er-coap/er-coap-separate.h @@ -52,7 +52,9 @@ typedef struct coap_separate { uint8_t token_len; uint8_t token[COAP_TOKEN_LEN]; - /* separate + blockwise is untested! */ + uint32_t block1_num; + uint16_t block1_size; + uint32_t block2_num; uint16_t block2_size; } coap_separate_t; diff --git a/apps/er-coap/er-coap.c b/apps/er-coap/er-coap.c index 23fac35cb..dbcdbbb7f 100644 --- a/apps/er-coap/er-coap.c +++ b/apps/er-coap/er-coap.c @@ -329,6 +329,10 @@ coap_serialize_message(void *packet, uint8_t *buffer) coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8); coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid); + /* empty packet, dont need to do more stuff */ + if(!coap_pkt->code) { + return 4; + } /* set Token */ PRINTF("Token (len %u)", coap_pkt->token_len); option = coap_pkt->buffer + COAP_HEADER_LEN; @@ -419,7 +423,11 @@ coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uip_ipaddr_copy(&udp_conn->ripaddr, addr); udp_conn->rport = port; +#ifdef WITH_DTLS + dtls_send_message(udp_conn, data, length); +#else uip_udp_packet_send(udp_conn, data, length); +#endif PRINTF("-sent UDP datagram (%u)-\n", length); /* restore server socket to allow data from any node */ @@ -1032,8 +1040,8 @@ coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK2)) { return 0; + /* pointers may be NULL to get only specific block parameters */ } - /* pointers may be NULL to get only specific block parameters */ if(num != NULL) { *num = coap_pkt->block2_num; } @@ -1079,8 +1087,8 @@ coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK1)) { return 0; + /* pointers may be NULL to get only specific block parameters */ } - /* pointers may be NULL to get only specific block parameters */ if(num != NULL) { *num = coap_pkt->block1_num; } diff --git a/apps/er-coap/er-coap.h b/apps/er-coap/er-coap.h index 11fcbebb0..53eb39f2e 100644 --- a/apps/er-coap/er-coap.h +++ b/apps/er-coap/er-coap.h @@ -54,6 +54,17 @@ #define REST coap_rest_implementation #include "rest-engine.h" +/* REST_MAX_CHUNK_SIZE can be different from 2^x so we need to get next lower 2^x for COAP_MAX_BLOCK_SIZE */ +#ifndef COAP_MAX_BLOCK_SIZE +#define COAP_MAX_BLOCK_SIZE (REST_MAX_CHUNK_SIZE < 32 ? 16 : \ + (REST_MAX_CHUNK_SIZE < 64 ? 32 : \ + (REST_MAX_CHUNK_SIZE < 128 ? 64 : \ + (REST_MAX_CHUNK_SIZE < 256 ? 128 : \ + (REST_MAX_CHUNK_SIZE < 512 ? 256 : \ + (REST_MAX_CHUNK_SIZE < 1024 ? 512 : \ + (REST_MAX_CHUNK_SIZE < 2048 ? 1024 : 2048))))))) +#endif /* COAP_MAX_BLOCK_SIZE */ + /* direct access into the buffer */ #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) #if UIP_CONF_IPV6 diff --git a/examples/er-rest-example/er-example-server.c b/examples/er-rest-example/er-example-server.c index 9c3ad1714..ad922000a 100644 --- a/examples/er-rest-example/er-example-server.c +++ b/examples/er-rest-example/er-example-server.c @@ -70,7 +70,8 @@ extern resource_t res_separate, res_push, res_event, - res_sub; + res_sub, + res_b1_sep_b2; #if PLATFORM_HAS_LEDS extern resource_t res_leds, res_toggle; #endif @@ -116,6 +117,7 @@ PROCESS_THREAD(er_example_server, ev, data) rest_activate_resource(&res_push, "test/push"); /* rest_activate_resource(&res_event, "sensors/button"); */ /* rest_activate_resource(&res_sub, "test/sub"); */ +/* rest_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); */ #if PLATFORM_HAS_LEDS /* rest_activate_resource(&res_leds, "actuators/leds"); */ rest_activate_resource(&res_toggle, "actuators/toggle"); diff --git a/examples/er-rest-example/project-conf.h b/examples/er-rest-example/project-conf.h index 0ae70731e..040dc5525 100644 --- a/examples/er-rest-example/project-conf.h +++ b/examples/er-rest-example/project-conf.h @@ -65,7 +65,7 @@ /* Increase rpl-border-router IP-buffer when using more than 64. */ #undef REST_MAX_CHUNK_SIZE -#define REST_MAX_CHUNK_SIZE 64 +#define REST_MAX_CHUNK_SIZE 48 /* Estimate your header size, especially when using Proxy-Uri. */ /* diff --git a/examples/er-rest-example/resources/res-b1-sep-b2.c b/examples/er-rest-example/resources/res-b1-sep-b2.c new file mode 100644 index 000000000..be4d8f943 --- /dev/null +++ b/examples/er-rest-example/resources/res-b1-sep-b2.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Lars Schmertmann + */ + +#include +#include "rest-engine.h" +#include "er-coap-block1.h" +#include "er-coap-separate.h" +#include "er-coap-transactions.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +SEPARATE_RESOURCE(res_b1_sep_b2, "title=\"Block1 + Separate + Block2 demo\"", NULL, res_post_handler, NULL, NULL, NULL); + +#define MAX_DATA_LEN 256 + +static uint8_t big_msg[MAX_DATA_LEN]; +static size_t big_msg_len = 0; +static coap_separate_t request_metadata; + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Example allows only one request on time. There are no checks for multiply access !!! */ + if(*offset == 0) { + /* Incoming Data */ + if(coap_block1_handler(request, response, big_msg, &big_msg_len, MAX_DATA_LEN)) { + /* More Blocks will follow. Example waits for + * the last block and stores data into big_msg. + */ + return; + } + /* Last block was received. */ + coap_separate_accept(request, &request_metadata); + + /* Need Time for calculation now */ + uint32_t i; + for(i = 0; i <= 4096; i++) { + printf("\r% 4u\r", i); + } + printf("\n"); + + /* Send first block */ + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(request_metadata.mid, &request_metadata.addr, request_metadata.port))) { + coap_packet_t resp[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(resp, &request_metadata, CONTENT_2_05); + + /* Set payload and block info */ + coap_set_payload(resp, big_msg, big_msg_len > request_metadata.block2_size ? request_metadata.block2_size : big_msg_len); + if(big_msg_len > request_metadata.block2_size) { + coap_set_header_block2(resp, 0, 1, request_metadata.block2_size); + } + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(resp, transaction->packet); + coap_send_transaction(transaction); + } + } else { + /* request for more blocks */ + if(*offset >= big_msg_len) { + coap_set_status_code(response, BAD_OPTION_4_02); + coap_set_payload(response, "BlockOutOfScope", 15); + return; + } + + memcpy(buffer, big_msg + *offset, 32); + if(big_msg_len - *offset < preferred_size) { + preferred_size = big_msg_len - *offset; + *offset = -1; + } else { + *offset += preferred_size; + } + coap_set_payload(response, buffer, preferred_size); + } +} diff --git a/examples/er-rest-example/resources/res-plugtest-query.c b/examples/er-rest-example/resources/res-plugtest-query.c index f0633854a..538646c6e 100644 --- a/examples/er-rest-example/resources/res-plugtest-query.c +++ b/examples/er-rest-example/resources/res-plugtest-query.c @@ -62,7 +62,8 @@ res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferr if((len = REST.get_query(request, &query))) { PRINTF("Query: %.*s\n", len, query); - } /* Code 2.05 CONTENT is default. */ + /* Code 2.05 CONTENT is default. */ + } REST.set_header_content_type(response, REST.type.TEXT_PLAIN); REST.set_response_payload(