diff --git a/apps/er-coap/er-coap-conf.h b/apps/er-coap/er-coap-conf.h old mode 100755 new mode 100644 index eeb08b6ff..77d9c2048 --- a/apps/er-coap/er-coap-conf.h +++ b/apps/er-coap/er-coap-conf.h @@ -1,74 +1,74 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Collection of default configuration values. - * \author - * Matthias Kovatsch - */ - -#ifndef ER_COAP_CONF_H_ -#define ER_COAP_CONF_H_ - -/* Features that can be disabled to achieve smaller memory footprint */ -#define COAP_LINK_FORMAT_FILTERING 0 -#define COAP_PROXY_OPTION_PROCESSING 0 - -/* Listening port for the CoAP REST Engine */ -#ifndef COAP_SERVER_PORT -#define COAP_SERVER_PORT COAP_DEFAULT_PORT -#endif - -/* The number of concurrent messages that can be stored for retransmission in the transaction layer. */ -#ifndef COAP_MAX_OPEN_TRANSACTIONS -#define COAP_MAX_OPEN_TRANSACTIONS 4 -#endif /* COAP_MAX_OPEN_TRANSACTIONS */ - -/* Maximum number of failed request attempts before action */ -#ifndef COAP_MAX_ATTEMPTS -#define COAP_MAX_ATTEMPTS 4 -#endif /* COAP_MAX_ATTEMPTS */ - -/* Conservative size limit, as not all options have to be set at the same time. Check when Proxy-Uri option is used */ -#ifndef COAP_MAX_HEADER_SIZE /* Hdr CoF If-Match Obs Blo strings */ -#define COAP_MAX_HEADER_SIZE (4 + COAP_TOKEN_LEN + 3 + 1+COAP_ETAG_LEN + 4 + 4 + 30) /* 65 */ -#endif /* COAP_MAX_HEADER_SIZE */ - -/* Number of observer slots (each takes abot xxx bytes) */ -#ifndef COAP_MAX_OBSERVERS -#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS-1 -#endif /* COAP_MAX_OBSERVERS */ - -/* Interval in seconds in which NON notifies are changed to CON notifies to check client. */ -#define COAP_OBSERVE_REFRESH_INTERVAL 60 - -#endif /* ER_COAP_CONF_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Collection of default configuration values. + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_CONF_H_ +#define ER_COAP_CONF_H_ + +/* Features that can be disabled to achieve smaller memory footprint */ +#define COAP_LINK_FORMAT_FILTERING 0 +#define COAP_PROXY_OPTION_PROCESSING 0 + +/* Listening port for the CoAP REST Engine */ +#ifndef COAP_SERVER_PORT +#define COAP_SERVER_PORT COAP_DEFAULT_PORT +#endif + +/* The number of concurrent messages that can be stored for retransmission in the transaction layer. */ +#ifndef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 4 +#endif /* COAP_MAX_OPEN_TRANSACTIONS */ + +/* Maximum number of failed request attempts before action */ +#ifndef COAP_MAX_ATTEMPTS +#define COAP_MAX_ATTEMPTS 4 +#endif /* COAP_MAX_ATTEMPTS */ + +/* Conservative size limit, as not all options have to be set at the same time. Check when Proxy-Uri option is used */ +#ifndef COAP_MAX_HEADER_SIZE /* Hdr CoF If-Match Obs Blo strings */ +#define COAP_MAX_HEADER_SIZE (4 + COAP_TOKEN_LEN + 3 + 1 + COAP_ETAG_LEN + 4 + 4 + 30) /* 65 */ +#endif /* COAP_MAX_HEADER_SIZE */ + +/* Number of observer slots (each takes abot xxx bytes) */ +#ifndef COAP_MAX_OBSERVERS +#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS - 1 +#endif /* COAP_MAX_OBSERVERS */ + +/* Interval in seconds in which NON notifies are changed to CON notifies to check client. */ +#define COAP_OBSERVE_REFRESH_INTERVAL 60 + +#endif /* ER_COAP_CONF_H_ */ diff --git a/apps/er-coap/er-coap-constants.h b/apps/er-coap/er-coap-constants.h old mode 100755 new mode 100644 index 747af999a..8017b03d5 --- a/apps/er-coap/er-coap-constants.h +++ b/apps/er-coap/er-coap-constants.h @@ -1,165 +1,165 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Collection of constants specified in the CoAP standard. - * \author - * Matthias Kovatsch - */ - -#ifndef ER_COAP_CONSTANTS_H_ -#define ER_COAP_CONSTANTS_H_ - -#define COAP_DEFAULT_PORT 5683 - -#define COAP_DEFAULT_MAX_AGE 60 -#define COAP_RESPONSE_TIMEOUT 3 -#define COAP_RESPONSE_RANDOM_FACTOR 1.5 -#define COAP_MAX_RETRANSMIT 4 - -#define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */ -#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ -#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ - -#define COAP_HEADER_VERSION_MASK 0xC0 -#define COAP_HEADER_VERSION_POSITION 6 -#define COAP_HEADER_TYPE_MASK 0x30 -#define COAP_HEADER_TYPE_POSITION 4 -#define COAP_HEADER_TOKEN_LEN_MASK 0x0F -#define COAP_HEADER_TOKEN_LEN_POSITION 0 - -#define COAP_HEADER_OPTION_DELTA_MASK 0xF0 -#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F - -/* CoAP message types */ -typedef enum { - COAP_TYPE_CON, /* confirmables */ - COAP_TYPE_NON, /* non-confirmables */ - COAP_TYPE_ACK, /* acknowledgements */ - COAP_TYPE_RST /* reset */ -} coap_message_type_t; - -/* CoAP request method codes */ -typedef enum { - COAP_GET = 1, - COAP_POST, - COAP_PUT, - COAP_DELETE -} coap_method_t; - -/* CoAP response codes */ -typedef enum { - NO_ERROR = 0, - - CREATED_2_01 = 65, /* CREATED */ - DELETED_2_02 = 66, /* DELETED */ - VALID_2_03 = 67, /* NOT_MODIFIED */ - CHANGED_2_04 = 68, /* CHANGED */ - CONTENT_2_05 = 69, /* OK */ - - BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */ - UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */ - BAD_OPTION_4_02 = 130, /* BAD_OPTION */ - FORBIDDEN_4_03 = 131, /* FORBIDDEN */ - NOT_FOUND_4_04 = 132, /* NOT_FOUND */ - METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */ - NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */ - PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */ - REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */ - UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */ - - INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */ - NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */ - BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */ - SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */ - GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */ - PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */ - - /* Erbium errors */ - MEMORY_ALLOCATION_ERROR = 192, - PACKET_SERIALIZATION_ERROR, - - /* Erbium hooks */ - MANUAL_RESPONSE, - PING_RESPONSE -} coap_status_t; - -/* CoAP header option numbers */ -typedef enum { - COAP_OPTION_IF_MATCH = 1, /* 0-8 B */ - COAP_OPTION_URI_HOST = 3, /* 1-255 B */ - COAP_OPTION_ETAG = 4, /* 1-8 B */ - COAP_OPTION_IF_NONE_MATCH = 5, /* 0 B */ - COAP_OPTION_OBSERVE = 6, /* 0-3 B */ - COAP_OPTION_URI_PORT = 7, /* 0-2 B */ - COAP_OPTION_LOCATION_PATH = 8, /* 0-255 B */ - COAP_OPTION_URI_PATH = 11, /* 0-255 B */ - COAP_OPTION_CONTENT_FORMAT = 12, /* 0-2 B */ - COAP_OPTION_MAX_AGE = 14, /* 0-4 B */ - COAP_OPTION_URI_QUERY = 15, /* 0-255 B */ - COAP_OPTION_ACCEPT = 17, /* 0-2 B */ - COAP_OPTION_LOCATION_QUERY = 20, /* 0-255 B */ - COAP_OPTION_BLOCK2 = 23, /* 1-3 B */ - COAP_OPTION_BLOCK1 = 27, /* 1-3 B */ - COAP_OPTION_SIZE2 = 28, /* 0-4 B */ - COAP_OPTION_PROXY_URI = 35, /* 1-1034 B */ - COAP_OPTION_PROXY_SCHEME = 39, /* 1-255 B */ - COAP_OPTION_SIZE1 = 60, /* 0-4 B */ -} coap_option_t; - -/* CoAP Content-Formats */ -typedef enum { - TEXT_PLAIN = 0, - TEXT_XML = 1, - TEXT_CSV = 2, - TEXT_HTML = 3, - IMAGE_GIF = 21, - IMAGE_JPEG = 22, - IMAGE_PNG = 23, - IMAGE_TIFF = 24, - AUDIO_RAW = 25, - VIDEO_RAW = 26, - APPLICATION_LINK_FORMAT = 40, - APPLICATION_XML = 41, - APPLICATION_OCTET_STREAM = 42, - APPLICATION_RDF_XML = 43, - APPLICATION_SOAP_XML = 44, - APPLICATION_ATOM_XML = 45, - APPLICATION_XMPP_XML = 46, - APPLICATION_EXI = 47, - APPLICATION_FASTINFOSET = 48, - APPLICATION_SOAP_FASTINFOSET = 49, - APPLICATION_JSON = 50, - APPLICATION_X_OBIX_BINARY = 51 -} coap_content_format_t; - -#endif /* ER_COAP_CONSTANTS_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Collection of constants specified in the CoAP standard. + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_CONSTANTS_H_ +#define ER_COAP_CONSTANTS_H_ + +#define COAP_DEFAULT_PORT 5683 + +#define COAP_DEFAULT_MAX_AGE 60 +#define COAP_RESPONSE_TIMEOUT 3 +#define COAP_RESPONSE_RANDOM_FACTOR 1.5 +#define COAP_MAX_RETRANSMIT 4 + +#define COAP_HEADER_LEN 4 /* | version:0x03 type:0x0C tkl:0xF0 | code | mid:0x00FF | mid:0xFF00 | */ +#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ +#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ + +#define COAP_HEADER_VERSION_MASK 0xC0 +#define COAP_HEADER_VERSION_POSITION 6 +#define COAP_HEADER_TYPE_MASK 0x30 +#define COAP_HEADER_TYPE_POSITION 4 +#define COAP_HEADER_TOKEN_LEN_MASK 0x0F +#define COAP_HEADER_TOKEN_LEN_POSITION 0 + +#define COAP_HEADER_OPTION_DELTA_MASK 0xF0 +#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F + +/* CoAP message types */ +typedef enum { + COAP_TYPE_CON, /* confirmables */ + COAP_TYPE_NON, /* non-confirmables */ + COAP_TYPE_ACK, /* acknowledgements */ + COAP_TYPE_RST /* reset */ +} coap_message_type_t; + +/* CoAP request method codes */ +typedef enum { + COAP_GET = 1, + COAP_POST, + COAP_PUT, + COAP_DELETE +} coap_method_t; + +/* CoAP response codes */ +typedef enum { + NO_ERROR = 0, + + CREATED_2_01 = 65, /* CREATED */ + DELETED_2_02 = 66, /* DELETED */ + VALID_2_03 = 67, /* NOT_MODIFIED */ + CHANGED_2_04 = 68, /* CHANGED */ + CONTENT_2_05 = 69, /* OK */ + + BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */ + UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */ + BAD_OPTION_4_02 = 130, /* BAD_OPTION */ + FORBIDDEN_4_03 = 131, /* FORBIDDEN */ + NOT_FOUND_4_04 = 132, /* NOT_FOUND */ + METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */ + NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */ + PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */ + REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */ + UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */ + + INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */ + NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */ + BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */ + SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */ + GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */ + PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */ + + /* Erbium errors */ + MEMORY_ALLOCATION_ERROR = 192, + PACKET_SERIALIZATION_ERROR, + + /* Erbium hooks */ + MANUAL_RESPONSE, + PING_RESPONSE +} coap_status_t; + +/* CoAP header option numbers */ +typedef enum { + COAP_OPTION_IF_MATCH = 1, /* 0-8 B */ + COAP_OPTION_URI_HOST = 3, /* 1-255 B */ + COAP_OPTION_ETAG = 4, /* 1-8 B */ + COAP_OPTION_IF_NONE_MATCH = 5, /* 0 B */ + COAP_OPTION_OBSERVE = 6, /* 0-3 B */ + COAP_OPTION_URI_PORT = 7, /* 0-2 B */ + COAP_OPTION_LOCATION_PATH = 8, /* 0-255 B */ + COAP_OPTION_URI_PATH = 11, /* 0-255 B */ + COAP_OPTION_CONTENT_FORMAT = 12, /* 0-2 B */ + COAP_OPTION_MAX_AGE = 14, /* 0-4 B */ + COAP_OPTION_URI_QUERY = 15, /* 0-255 B */ + COAP_OPTION_ACCEPT = 17, /* 0-2 B */ + COAP_OPTION_LOCATION_QUERY = 20, /* 0-255 B */ + COAP_OPTION_BLOCK2 = 23, /* 1-3 B */ + COAP_OPTION_BLOCK1 = 27, /* 1-3 B */ + COAP_OPTION_SIZE2 = 28, /* 0-4 B */ + COAP_OPTION_PROXY_URI = 35, /* 1-1034 B */ + COAP_OPTION_PROXY_SCHEME = 39, /* 1-255 B */ + COAP_OPTION_SIZE1 = 60, /* 0-4 B */ +} coap_option_t; + +/* CoAP Content-Formats */ +typedef enum { + TEXT_PLAIN = 0, + TEXT_XML = 1, + TEXT_CSV = 2, + TEXT_HTML = 3, + IMAGE_GIF = 21, + IMAGE_JPEG = 22, + IMAGE_PNG = 23, + IMAGE_TIFF = 24, + AUDIO_RAW = 25, + VIDEO_RAW = 26, + APPLICATION_LINK_FORMAT = 40, + APPLICATION_XML = 41, + APPLICATION_OCTET_STREAM = 42, + APPLICATION_RDF_XML = 43, + APPLICATION_SOAP_XML = 44, + APPLICATION_ATOM_XML = 45, + APPLICATION_XMPP_XML = 46, + APPLICATION_EXI = 47, + APPLICATION_FASTINFOSET = 48, + APPLICATION_SOAP_FASTINFOSET = 49, + APPLICATION_JSON = 50, + APPLICATION_X_OBIX_BINARY = 51 +} coap_content_format_t; + +#endif /* ER_COAP_CONSTANTS_H_ */ diff --git a/apps/er-coap/er-coap-engine.c b/apps/er-coap/er-coap-engine.c old mode 100755 new mode 100644 index 0b68c7519..c8b0c82ed --- a/apps/er-coap/er-coap-engine.c +++ b/apps/er-coap/er-coap-engine.c @@ -1,502 +1,507 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 implementation for the REST Engine. - * \author - * Matthias Kovatsch - */ - -#include -#include -#include -#include "er-coap-engine.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -PROCESS(coap_engine, "CoAP Engine"); - -/*---------------------------------------------------------------------------*/ -/*- Variables ---------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -static service_callback_t service_cbk = NULL; - -/*---------------------------------------------------------------------------*/ -/*- Internal API ------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -static int -coap_receive(void) -{ - erbium_status_code = NO_ERROR; - - PRINTF("handle_incoming_data(): received uip_datalen=%u \n", - (uint16_t) uip_datalen()); - - /* static declaration reduces stack peaks and program code size */ - static coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ - static coap_packet_t response[1]; - static coap_transaction_t *transaction = NULL; - - if(uip_newdata()) { - - PRINTF("receiving UDP datagram from: "); - PRINT6ADDR(&UIP_IP_BUF->srcipaddr); - PRINTF(":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF->srcport), - uip_datalen()); - - erbium_status_code = - coap_parse_message(message, uip_appdata, uip_datalen()); - - if(erbium_status_code == NO_ERROR) { - - /*TODO duplicates suppression, if required by application */ - - PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, - message->type, message->token_len, message->code, message->mid); - PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); - PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); - - /* handle requests */ - if(message->code >= COAP_GET && message->code <= COAP_DELETE) { - - /* use transaction buffer for response to confirmable request */ - if((transaction = - coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, - UIP_UDP_BUF->srcport))) { - uint32_t block_num = 0; - uint16_t block_size = REST_MAX_CHUNK_SIZE; - uint32_t block_offset = 0; - int32_t new_offset = 0; - - /* prepare response */ - if(message->type == COAP_TYPE_CON) { - /* reliable CON requests are answered with an ACK */ - coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, - message->mid); - } else { - /* unreliable NON requests are answered with a NON as well */ - coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, - coap_get_mid()); - } - - /* mirror token */ - if(message->token_len) { - coap_set_token(response, message->token, message->token_len); - } - - /* get offset for blockwise transfers */ - if(coap_get_header_block2 - (message, &block_num, NULL, &block_size, &block_offset)) { - PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", - block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); - block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); - new_offset = block_offset; - } - - /* invoke resource handler */ - if(service_cbk) { - - /* call REST framework and check if found and allowed */ - if(service_cbk - (message, response, transaction->packet + COAP_MAX_HEADER_SIZE, - block_size, &new_offset)) { - - if(erbium_status_code == NO_ERROR) { - - //TODO coap_handle_blockwise(request, response, start_offset, end_offset); - - /* resource is unaware of Block1 */ - if(IS_OPTION(message, COAP_OPTION_BLOCK1) - && response->code < BAD_REQUEST_4_00 - && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { - PRINTF("Block1 NOT IMPLEMENTED\n"); - - erbium_status_code = NOT_IMPLEMENTED_5_01; - coap_error_message = "NoBlock1Support"; - - /* client requested Block2 transfer */ - } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) { - - /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ - if(new_offset == block_offset) { - PRINTF - ("Blockwise: unaware resource with payload length %u/%u\n", - response->payload_len, block_size); - if(block_offset >= response->payload_len) { - PRINTF - ("handle_incoming_data(): block_offset >= response->payload_len\n"); - - response->code = BAD_OPTION_4_02; - coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ - } else { - coap_set_header_block2(response, block_num, - response->payload_len - - block_offset > block_size, - block_size); - coap_set_payload(response, - response->payload + block_offset, - MIN(response->payload_len - - block_offset, block_size)); - } /* if(valid offset) */ - - /* resource provides chunk-wise data */ - } else { - PRINTF("Blockwise: blockwise resource, new offset %ld\n", - new_offset); - coap_set_header_block2(response, block_num, - new_offset != -1 - || response->payload_len > - block_size, block_size); - - if(response->payload_len > block_size) { - coap_set_payload(response, response->payload, - block_size); - } - } /* if(resource aware of blockwise) */ - - /* Resource requested Block2 transfer */ - } else if(new_offset != 0) { - PRINTF - ("Blockwise: no block option for blockwise resource, using block size %u\n", - REST_MAX_CHUNK_SIZE); - - coap_set_header_block2(response, 0, new_offset != -1, - REST_MAX_CHUNK_SIZE); - coap_set_payload(response, response->payload, - MIN(response->payload_len, - REST_MAX_CHUNK_SIZE)); - } /* blockwise transfer handling */ - } /* no errors/hooks */ - } /* successful service callback */ - - /* serialize response */ - if(erbium_status_code == NO_ERROR) { - if((transaction->packet_len = coap_serialize_message(response, - transaction-> - packet)) == - 0) { - erbium_status_code = PACKET_SERIALIZATION_ERROR; - } - } - - } else { - erbium_status_code = NOT_IMPLEMENTED_5_01; - coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */ - } /* if(service callback) */ - - } else { - erbium_status_code = SERVICE_UNAVAILABLE_5_03; - coap_error_message = "NoFreeTraBuffer"; - } /* if(transaction buffer) */ - - /* handle responses */ - } else { - - if(message->type == COAP_TYPE_CON && message->code == 0) { - PRINTF("Received Ping\n"); - erbium_status_code = PING_RESPONSE; - } else if(message->type == COAP_TYPE_ACK) { - /* transactions are closed through lookup below */ - PRINTF("Received ACK\n"); - } else if(message->type == COAP_TYPE_RST) { - PRINTF("Received RST\n"); - /* cancel possible subscriptions */ - coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, - UIP_UDP_BUF->srcport, message->mid); - } - - if((transaction = coap_get_transaction_by_mid(message->mid))) { - /* free transaction memory before callback, as it may create a new transaction */ - restful_response_handler callback = transaction->callback; - void *callback_data = transaction->callback_data; - - coap_clear_transaction(transaction); - - /* check if someone registered for the response */ - if(callback) { - callback(callback_data, message); - } - } - /* if(ACKed transaction) */ - transaction = NULL; - - } /* request or response */ - } /* parsed correctly */ - - /* if(parsed correctly) */ - if(erbium_status_code == NO_ERROR) { - if(transaction) - coap_send_transaction(transaction); - } else if(erbium_status_code == MANUAL_RESPONSE) { - PRINTF("Clearing transaction for manual response"); - coap_clear_transaction(transaction); - } else { - coap_message_type_t reply_type = COAP_TYPE_ACK; - - PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message); - coap_clear_transaction(transaction); - - if(erbium_status_code == PING_RESPONSE) { - erbium_status_code = 0; - reply_type = COAP_TYPE_RST; - } else if(erbium_status_code >= 192) { - /* set to sendable error code */ - erbium_status_code = INTERNAL_SERVER_ERROR_5_00; - } - - /* reuse input buffer for error message */ - coap_init_message(message, reply_type, erbium_status_code, - message->mid); - coap_set_payload(message, coap_error_message, - strlen(coap_error_message)); - coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, - uip_appdata, coap_serialize_message(message, - uip_appdata)); - } - } - - /* if(new data) */ - return erbium_status_code; -} -/*---------------------------------------------------------------------------*/ -void -coap_init_engine(void) -{ - process_start(&coap_engine, NULL); -} -/*---------------------------------------------------------------------------*/ -void -coap_set_service_callback(service_callback_t callback) -{ - service_cbk = callback; -} -/*---------------------------------------------------------------------------*/ -rest_resource_flags_t -coap_get_rest_method(void *packet) -{ - return (rest_resource_flags_t) (1 << - (((coap_packet_t *) packet)->code - 1)); -} -/*---------------------------------------------------------------------------*/ -/*- Server Part -------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ - -/* the discover resource is automatically included for CoAP */ -extern resource_t res_well_known_core; - -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(coap_engine, ev, data) -{ - PROCESS_BEGIN(); - PRINTF("Starting %s receiver...\n", coap_rest_implementation.name); - - rest_activate_resource(&res_well_known_core, ".well-known/core"); - - coap_register_as_transaction_handler(); - coap_init_connection(SERVER_LISTEN_PORT); - - while(1) { - PROCESS_YIELD(); - - if(ev == tcpip_event) { - coap_receive(); - } else if(ev == PROCESS_EVENT_TIMER) { - /* retransmissions are handled here */ - coap_check_transactions(); - } - } /* while (1) */ - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ -/*- Client Part -------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -coap_blocking_request_callback(void *callback_data, void *response) -{ - struct request_state_t *state = (struct request_state_t *)callback_data; - - state->response = (coap_packet_t *) response; - process_poll(state->process); -} -/*---------------------------------------------------------------------------*/ -PT_THREAD(coap_blocking_request - (struct request_state_t *state, process_event_t ev, - uip_ipaddr_t * remote_ipaddr, uint16_t remote_port, - coap_packet_t * request, - blocking_response_handler request_callback)) -{ - PT_BEGIN(&state->pt); - - static uint8_t more; - static uint32_t res_block; - static uint8_t block_error; - - state->block_num = 0; - state->response = NULL; - state->process = PROCESS_CURRENT(); - - more = 0; - res_block = 0; - block_error = 0; - - do { - request->mid = coap_get_mid(); - if((state->transaction = coap_new_transaction(request->mid, remote_ipaddr, - remote_port))) { - state->transaction->callback = coap_blocking_request_callback; - state->transaction->callback_data = state; - - if(state->block_num > 0) { - coap_set_header_block2(request, state->block_num, 0, - REST_MAX_CHUNK_SIZE); - } - - state->transaction->packet_len = coap_serialize_message(request, - state-> - transaction-> - packet); - - coap_send_transaction(state->transaction); - PRINTF("Requested #%lu (MID %u)\n", state->block_num, request->mid); - - PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL); - - if(!state->response) { - PRINTF("Server not responding\n"); - PT_EXIT(&state->pt); - } - - coap_get_header_block2(state->response, &res_block, &more, NULL, NULL); - - PRINTF("Received #%lu%s (%u bytes)\n", res_block, more ? "+" : "", - state->response->payload_len); - - if(res_block == state->block_num) { - request_callback(state->response); - ++(state->block_num); - } else { - PRINTF("WRONG BLOCK %lu/%lu\n", res_block, state->block_num); - ++block_error; - } - } else { - PRINTF("Could not allocate transaction buffer"); - PT_EXIT(&state->pt); - } - } while(more && block_error < COAP_MAX_ATTEMPTS); - - PT_END(&state->pt); -} -/*---------------------------------------------------------------------------*/ -/*- REST Engine Interface ---------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -const struct rest_implementation coap_rest_implementation = { - "CoAP-18", - - coap_init_engine, - coap_set_service_callback, - - coap_get_header_uri_path, - coap_get_rest_method, - coap_set_status_code, - - coap_get_header_content_format, - coap_set_header_content_format, - coap_get_header_accept, - coap_get_header_size2, - coap_set_header_size2, - coap_get_header_max_age, - coap_set_header_max_age, - coap_set_header_etag, - coap_get_header_if_match, - coap_get_header_if_none_match, - coap_get_header_uri_host, - coap_set_header_location_path, - - coap_get_payload, - coap_set_payload, - - coap_get_header_uri_query, - coap_get_query_variable, - coap_get_post_variable, - - coap_notify_observers, - coap_observe_handler, - - { - CONTENT_2_05, - CREATED_2_01, - CHANGED_2_04, - DELETED_2_02, - VALID_2_03, - BAD_REQUEST_4_00, - UNAUTHORIZED_4_01, - BAD_OPTION_4_02, - FORBIDDEN_4_03, - NOT_FOUND_4_04, - METHOD_NOT_ALLOWED_4_05, - NOT_ACCEPTABLE_4_06, - REQUEST_ENTITY_TOO_LARGE_4_13, - UNSUPPORTED_MEDIA_TYPE_4_15, - INTERNAL_SERVER_ERROR_5_00, - NOT_IMPLEMENTED_5_01, - BAD_GATEWAY_5_02, - SERVICE_UNAVAILABLE_5_03, - GATEWAY_TIMEOUT_5_04, - PROXYING_NOT_SUPPORTED_5_05}, - - { - TEXT_PLAIN, - TEXT_XML, - TEXT_CSV, - TEXT_HTML, - IMAGE_GIF, - IMAGE_JPEG, - IMAGE_PNG, - IMAGE_TIFF, - AUDIO_RAW, - VIDEO_RAW, - APPLICATION_LINK_FORMAT, - APPLICATION_XML, - APPLICATION_OCTET_STREAM, - APPLICATION_RDF_XML, - APPLICATION_SOAP_XML, - APPLICATION_ATOM_XML, - APPLICATION_XMPP_XML, - APPLICATION_EXI, - APPLICATION_FASTINFOSET, - APPLICATION_SOAP_FASTINFOSET, - APPLICATION_JSON, - APPLICATION_X_OBIX_BINARY} -}; -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 implementation for the REST Engine. + * \author + * Matthias Kovatsch + */ + +#include +#include +#include +#include "er-coap-engine.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +PROCESS(coap_engine, "CoAP Engine"); + +/*---------------------------------------------------------------------------*/ +/*- Variables ---------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +static service_callback_t service_cbk = NULL; + +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +static int +coap_receive(void) +{ + erbium_status_code = NO_ERROR; + + PRINTF("handle_incoming_data(): received uip_datalen=%u \n", + (uint16_t)uip_datalen()); + + /* static declaration reduces stack peaks and program code size */ + static coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ + static coap_packet_t response[1]; + static coap_transaction_t *transaction = NULL; + + if(uip_newdata()) { + + PRINTF("receiving UDP datagram from: "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF->srcport), + uip_datalen()); + + erbium_status_code = + coap_parse_message(message, uip_appdata, uip_datalen()); + + if(erbium_status_code == NO_ERROR) { + + /*TODO duplicates suppression, if required by application */ + + PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, + message->type, message->token_len, message->code, message->mid); + PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); + PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); + + /* handle requests */ + if(message->code >= COAP_GET && message->code <= COAP_DELETE) { + + /* use transaction buffer for response to confirmable request */ + if((transaction = + coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, + UIP_UDP_BUF->srcport))) { + uint32_t block_num = 0; + uint16_t block_size = REST_MAX_CHUNK_SIZE; + uint32_t block_offset = 0; + int32_t new_offset = 0; + + /* prepare response */ + if(message->type == COAP_TYPE_CON) { + /* reliable CON requests are answered with an ACK */ + coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, + message->mid); + } else { + /* unreliable NON requests are answered with a NON as well */ + coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, + coap_get_mid()); + /* mirror token */ + } + if(message->token_len) { + coap_set_token(response, message->token, message->token_len); + /* get offset for blockwise transfers */ + } + if(coap_get_header_block2 + (message, &block_num, NULL, &block_size, &block_offset)) { + PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", + block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); + block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); + new_offset = block_offset; + } + + /* invoke resource handler */ + if(service_cbk) { + + /* call REST framework and check if found and allowed */ + if(service_cbk + (message, response, transaction->packet + COAP_MAX_HEADER_SIZE, + block_size, &new_offset)) { + + if(erbium_status_code == NO_ERROR) { + + /* TODO coap_handle_blockwise(request, response, start_offset, end_offset); */ + + /* resource is unaware of Block1 */ + if(IS_OPTION(message, COAP_OPTION_BLOCK1) + && response->code < BAD_REQUEST_4_00 + && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { + PRINTF("Block1 NOT IMPLEMENTED\n"); + + erbium_status_code = NOT_IMPLEMENTED_5_01; + coap_error_message = "NoBlock1Support"; + + /* client requested Block2 transfer */ + } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) { + + /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ + if(new_offset == block_offset) { + PRINTF + ("Blockwise: unaware resource with payload length %u/%u\n", + response->payload_len, block_size); + if(block_offset >= response->payload_len) { + PRINTF + ("handle_incoming_data(): block_offset >= response->payload_len\n"); + + response->code = BAD_OPTION_4_02; + coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ + } else { + coap_set_header_block2(response, block_num, + response->payload_len - + block_offset > block_size, + block_size); + coap_set_payload(response, + response->payload + block_offset, + MIN(response->payload_len - + block_offset, block_size)); + } /* if(valid offset) */ + + /* resource provides chunk-wise data */ + } else { + PRINTF("Blockwise: blockwise resource, new offset %ld\n", + new_offset); + coap_set_header_block2(response, block_num, + new_offset != -1 + || response->payload_len > + block_size, block_size); + + if(response->payload_len > block_size) { + coap_set_payload(response, response->payload, + block_size); + } + } /* if(resource aware of blockwise) */ + + /* Resource requested Block2 transfer */ + } else if(new_offset != 0) { + PRINTF + ("Blockwise: no block option for blockwise resource, using block size %u\n", + REST_MAX_CHUNK_SIZE); + + coap_set_header_block2(response, 0, new_offset != -1, + REST_MAX_CHUNK_SIZE); + coap_set_payload(response, response->payload, + MIN(response->payload_len, + REST_MAX_CHUNK_SIZE)); + } /* blockwise transfer handling */ + } /* no errors/hooks */ + /* successful service callback */ + /* serialize response */ + } + if(erbium_status_code == NO_ERROR) { + if((transaction->packet_len = coap_serialize_message(response, + transaction-> + packet)) == + 0) { + erbium_status_code = PACKET_SERIALIZATION_ERROR; + } + } + } else { + erbium_status_code = NOT_IMPLEMENTED_5_01; + coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */ + } /* if(service callback) */ + } else { + erbium_status_code = SERVICE_UNAVAILABLE_5_03; + coap_error_message = "NoFreeTraBuffer"; + } /* if(transaction buffer) */ + + /* handle responses */ + } else { + + if(message->type == COAP_TYPE_CON && message->code == 0) { + PRINTF("Received Ping\n"); + erbium_status_code = PING_RESPONSE; + } else if(message->type == COAP_TYPE_ACK) { + /* transactions are closed through lookup below */ + PRINTF("Received ACK\n"); + } else if(message->type == COAP_TYPE_RST) { + PRINTF("Received RST\n"); + /* cancel possible subscriptions */ + coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, + UIP_UDP_BUF->srcport, message->mid); + } + + if((transaction = coap_get_transaction_by_mid(message->mid))) { + /* free transaction memory before callback, as it may create a new transaction */ + restful_response_handler callback = transaction->callback; + void *callback_data = transaction->callback_data; + + coap_clear_transaction(transaction); + + /* check if someone registered for the response */ + if(callback) { + callback(callback_data, message); + } + } + /* if(ACKed transaction) */ + transaction = NULL; + } /* request or response */ + } /* parsed correctly */ + + /* if(parsed correctly) */ + if(erbium_status_code == NO_ERROR) { + if(transaction) { + coap_send_transaction(transaction); + } + } else if(erbium_status_code == MANUAL_RESPONSE) { + PRINTF("Clearing transaction for manual response"); + coap_clear_transaction(transaction); + } else { + coap_message_type_t reply_type = COAP_TYPE_ACK; + + PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message); + coap_clear_transaction(transaction); + + if(erbium_status_code == PING_RESPONSE) { + erbium_status_code = 0; + reply_type = COAP_TYPE_RST; + } else if(erbium_status_code >= 192) { + /* set to sendable error code */ + erbium_status_code = INTERNAL_SERVER_ERROR_5_00; + /* reuse input buffer for error message */ + } + coap_init_message(message, reply_type, erbium_status_code, + message->mid); + coap_set_payload(message, coap_error_message, + strlen(coap_error_message)); + coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, + uip_appdata, coap_serialize_message(message, + uip_appdata)); + } + } + + /* if(new data) */ + return erbium_status_code; +} +/*---------------------------------------------------------------------------*/ +void +coap_init_engine(void) +{ + process_start(&coap_engine, NULL); +} +/*---------------------------------------------------------------------------*/ +void +coap_set_service_callback(service_callback_t callback) +{ + service_cbk = callback; +} +/*---------------------------------------------------------------------------*/ +rest_resource_flags_t +coap_get_rest_method(void *packet) +{ + return (rest_resource_flags_t)(1 << + (((coap_packet_t *)packet)->code - 1)); +} +/*---------------------------------------------------------------------------*/ +/*- Server Part -------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +/* the discover resource is automatically included for CoAP */ +extern resource_t res_well_known_core; + +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(coap_engine, ev, data) +{ + PROCESS_BEGIN(); + PRINTF("Starting %s receiver...\n", coap_rest_implementation.name); + + rest_activate_resource(&res_well_known_core, ".well-known/core"); + + coap_register_as_transaction_handler(); + coap_init_connection(SERVER_LISTEN_PORT); + + while(1) { + PROCESS_YIELD(); + + if(ev == tcpip_event) { + coap_receive(); + } else if(ev == PROCESS_EVENT_TIMER) { + /* retransmissions are handled here */ + coap_check_transactions(); + } + } /* while (1) */ + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +/*- Client Part -------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_blocking_request_callback(void *callback_data, void *response) +{ + struct request_state_t *state = (struct request_state_t *)callback_data; + + state->response = (coap_packet_t *)response; + process_poll(state->process); +} +/*---------------------------------------------------------------------------*/ +PT_THREAD(coap_blocking_request + (struct request_state_t *state, process_event_t ev, + uip_ipaddr_t *remote_ipaddr, uint16_t remote_port, + coap_packet_t *request, + blocking_response_handler request_callback)) +{ + PT_BEGIN(&state->pt); + + static uint8_t more; + static uint32_t res_block; + static uint8_t block_error; + + state->block_num = 0; + state->response = NULL; + state->process = PROCESS_CURRENT(); + + more = 0; + res_block = 0; + block_error = 0; + + do { + request->mid = coap_get_mid(); + if((state->transaction = coap_new_transaction(request->mid, remote_ipaddr, + remote_port))) { + state->transaction->callback = coap_blocking_request_callback; + state->transaction->callback_data = state; + + if(state->block_num > 0) { + coap_set_header_block2(request, state->block_num, 0, + REST_MAX_CHUNK_SIZE); + } + state->transaction->packet_len = coap_serialize_message(request, + state-> + transaction-> + packet); + + coap_send_transaction(state->transaction); + PRINTF("Requested #%lu (MID %u)\n", state->block_num, request->mid); + + PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL); + + if(!state->response) { + PRINTF("Server not responding\n"); + PT_EXIT(&state->pt); + } + + coap_get_header_block2(state->response, &res_block, &more, NULL, NULL); + + PRINTF("Received #%lu%s (%u bytes)\n", res_block, more ? "+" : "", + state->response->payload_len); + + if(res_block == state->block_num) { + request_callback(state->response); + ++(state->block_num); + } else { + PRINTF("WRONG BLOCK %lu/%lu\n", res_block, state->block_num); + ++block_error; + } + } else { + PRINTF("Could not allocate transaction buffer"); + PT_EXIT(&state->pt); + } + } while(more && block_error < COAP_MAX_ATTEMPTS); + + PT_END(&state->pt); +} +/*---------------------------------------------------------------------------*/ +/*- REST Engine Interface ---------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +const struct rest_implementation coap_rest_implementation = { + "CoAP-18", + + coap_init_engine, + coap_set_service_callback, + + coap_get_header_uri_path, + coap_get_rest_method, + coap_set_status_code, + + coap_get_header_content_format, + coap_set_header_content_format, + coap_get_header_accept, + coap_get_header_size2, + coap_set_header_size2, + coap_get_header_max_age, + coap_set_header_max_age, + coap_set_header_etag, + coap_get_header_if_match, + coap_get_header_if_none_match, + coap_get_header_uri_host, + coap_set_header_location_path, + + coap_get_payload, + coap_set_payload, + + coap_get_header_uri_query, + coap_get_query_variable, + coap_get_post_variable, + + coap_notify_observers, + coap_observe_handler, + + { + CONTENT_2_05, + CREATED_2_01, + CHANGED_2_04, + DELETED_2_02, + VALID_2_03, + BAD_REQUEST_4_00, + UNAUTHORIZED_4_01, + BAD_OPTION_4_02, + FORBIDDEN_4_03, + NOT_FOUND_4_04, + METHOD_NOT_ALLOWED_4_05, + NOT_ACCEPTABLE_4_06, + REQUEST_ENTITY_TOO_LARGE_4_13, + UNSUPPORTED_MEDIA_TYPE_4_15, + INTERNAL_SERVER_ERROR_5_00, + NOT_IMPLEMENTED_5_01, + BAD_GATEWAY_5_02, + SERVICE_UNAVAILABLE_5_03, + GATEWAY_TIMEOUT_5_04, + PROXYING_NOT_SUPPORTED_5_05 + }, + + { + TEXT_PLAIN, + TEXT_XML, + TEXT_CSV, + TEXT_HTML, + IMAGE_GIF, + IMAGE_JPEG, + IMAGE_PNG, + IMAGE_TIFF, + AUDIO_RAW, + VIDEO_RAW, + APPLICATION_LINK_FORMAT, + APPLICATION_XML, + APPLICATION_OCTET_STREAM, + APPLICATION_RDF_XML, + APPLICATION_SOAP_XML, + APPLICATION_ATOM_XML, + APPLICATION_XMPP_XML, + APPLICATION_EXI, + APPLICATION_FASTINFOSET, + APPLICATION_SOAP_FASTINFOSET, + APPLICATION_JSON, + APPLICATION_X_OBIX_BINARY + } +}; +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-engine.h b/apps/er-coap/er-coap-engine.h old mode 100755 new mode 100644 index 0cab098ea..d77d1fa78 --- a/apps/er-coap/er-coap-engine.h +++ b/apps/er-coap/er-coap-engine.h @@ -1,85 +1,85 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 implementation for the REST Engine. - * \author - * Matthias Kovatsch - */ - -#ifndef ER_COAP_ENGINE_H_ -#define ER_COAP_ENGINE_H_ - -#include "pt.h" -#include "er-coap.h" -#include "er-coap-transactions.h" -#include "er-coap-observe.h" -#include "er-coap-separate.h" - -#define SERVER_LISTEN_PORT UIP_HTONS(COAP_SERVER_PORT) - -typedef coap_packet_t rest_request_t; -typedef coap_packet_t rest_response_t; - -void coap_init_engine(void); - -/*---------------------------------------------------------------------------*/ -/*- Client Part -------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -struct request_state_t { - struct pt pt; - struct process *process; - coap_transaction_t *transaction; - coap_packet_t *response; - uint32_t block_num; -}; - -typedef void (*blocking_response_handler) (void *response); - -PT_THREAD(coap_blocking_request - (struct request_state_t *state, process_event_t ev, - uip_ipaddr_t * remote_ipaddr, uint16_t remote_port, - coap_packet_t * request, - blocking_response_handler request_callback)); - -#define COAP_BLOCKING_REQUEST(server_addr, server_port, request, chunk_handler) \ -{ \ - static struct request_state_t request_state; \ - PT_SPAWN(process_pt, &request_state.pt, \ - coap_blocking_request(&request_state, ev, \ - server_addr, server_port, \ - request, chunk_handler) \ - ); \ -} -/*---------------------------------------------------------------------------*/ - -#endif /* ER_COAP_ENGINE_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 implementation for the REST Engine. + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_ENGINE_H_ +#define ER_COAP_ENGINE_H_ + +#include "pt.h" +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "er-coap-observe.h" +#include "er-coap-separate.h" + +#define SERVER_LISTEN_PORT UIP_HTONS(COAP_SERVER_PORT) + +typedef coap_packet_t rest_request_t; +typedef coap_packet_t rest_response_t; + +void coap_init_engine(void); + +/*---------------------------------------------------------------------------*/ +/*- Client Part -------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +struct request_state_t { + struct pt pt; + struct process *process; + coap_transaction_t *transaction; + coap_packet_t *response; + uint32_t block_num; +}; + +typedef void (*blocking_response_handler)(void *response); + +PT_THREAD(coap_blocking_request + (struct request_state_t *state, process_event_t ev, + uip_ipaddr_t *remote_ipaddr, uint16_t remote_port, + coap_packet_t *request, + blocking_response_handler request_callback)); + +#define COAP_BLOCKING_REQUEST(server_addr, server_port, request, chunk_handler) \ + { \ + static struct request_state_t request_state; \ + PT_SPAWN(process_pt, &request_state.pt, \ + coap_blocking_request(&request_state, ev, \ + server_addr, server_port, \ + request, chunk_handler) \ + ); \ + } +/*---------------------------------------------------------------------------*/ + +#endif /* ER_COAP_ENGINE_H_ */ diff --git a/apps/er-coap/er-coap-observe.c b/apps/er-coap/er-coap-observe.c old mode 100755 new mode 100644 index 6f2707e67..0f64abb53 --- a/apps/er-coap/er-coap-observe.c +++ b/apps/er-coap/er-coap-observe.c @@ -1,254 +1,265 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 observing resources (draft-ietf-core-observe-11). - * \author - * Matthias Kovatsch - */ - -#include -#include -#include "er-coap-observe.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -/*---------------------------------------------------------------------------*/ -MEMB(observers_memb, coap_observer_t, COAP_MAX_OBSERVERS); -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) -{ - /* Remove existing observe relationship, if any. */ - coap_remove_observer_by_uri(addr, port, uri); - - coap_observer_t *o = memb_alloc(&observers_memb); - - if(o) { - o->url = uri; - uip_ipaddr_copy(&o->addr, addr); - o->port = port; - o->token_len = token_len; - memcpy(o->token, token, token_len); - o->last_mid = 0; - - PRINTF("Adding observer for /%s [0x%02X%02X]\n", o->url, o->token[0], - o->token[1]); - list_add(observers_list, o); - } - - return o; -} -/*---------------------------------------------------------------------------*/ -/*- Removal -----------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -coap_remove_observer(coap_observer_t * o) -{ - PRINTF("Removing observer for /%s [0x%02X%02X]\n", o->url, o->token[0], - o->token[1]); - - memb_free(&observers_memb, o); - list_remove(observers_list, o); -} -/*---------------------------------------------------------------------------*/ -int -coap_remove_observer_by_client(uip_ipaddr_t * addr, uint16_t port) -{ - int removed = 0; - coap_observer_t *obs = NULL; - - for(obs = (coap_observer_t *) list_head(observers_list); obs; - obs = obs->next) { - PRINTF("Remove check client "); - PRINT6ADDR(addr); - PRINTF(":%u\n", port); - if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port) { - coap_remove_observer(obs); - removed++; - } - } - return removed; -} -/*---------------------------------------------------------------------------*/ -int -coap_remove_observer_by_token(uip_ipaddr_t * addr, uint16_t port, - uint8_t * token, size_t token_len) -{ - int removed = 0; - coap_observer_t *obs = NULL; - - for(obs = (coap_observer_t *) list_head(observers_list); obs; - obs = obs->next) { - PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]); - if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port - && obs->token_len == token_len - && memcmp(obs->token, token, token_len) == 0) { - coap_remove_observer(obs); - removed++; - } - } - return removed; -} -/*---------------------------------------------------------------------------*/ -int -coap_remove_observer_by_uri(uip_ipaddr_t * addr, uint16_t port, - const char *uri) -{ - int removed = 0; - coap_observer_t *obs = NULL; - - for(obs = (coap_observer_t *) list_head(observers_list); obs; - obs = obs->next) { - PRINTF("Remove check URL %p\n", uri); - if((addr == NULL - || (uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port)) - && (obs->url == uri || memcmp(obs->url, uri, strlen(obs->url)) == 0)) { - coap_remove_observer(obs); - removed++; - } - } - return removed; -} -/*---------------------------------------------------------------------------*/ -int -coap_remove_observer_by_mid(uip_ipaddr_t * addr, uint16_t port, uint16_t mid) -{ - int removed = 0; - coap_observer_t *obs = NULL; - - for(obs = (coap_observer_t *) list_head(observers_list); obs; - obs = obs->next) { - PRINTF("Remove check MID %u\n", mid); - if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port - && obs->last_mid == mid) { - coap_remove_observer(obs); - removed++; - } - } - return removed; -} -/*---------------------------------------------------------------------------*/ -/*- Notification ------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -coap_notify_observers(resource_t * resource) -{ - /* 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_observer_t *obs = NULL; - - PRINTF("Observe: Notification from %s\n", resource->url); - - /* iterate over observers */ - for(obs = (coap_observer_t *) list_head(observers_list); obs; - obs = obs->next) { - if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */ - coap_transaction_t *transaction = NULL; - - /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ - - if((transaction = - coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) { - PRINTF(" Observer "); - PRINT6ADDR(&obs->addr); - PRINTF(":%u\n", obs->port); - - /* update last MID for RST matching */ - obs->last_mid = transaction->mid; - - /* prepare response */ - notification->mid = transaction->mid; - - resource->get_handler(NULL, notification, - transaction->packet + COAP_MAX_HEADER_SIZE, - REST_MAX_CHUNK_SIZE, NULL); - - if(notification->code < BAD_REQUEST_4_00) - coap_set_header_observe(notification, (obs->obs_counter)++); - coap_set_token(notification, obs->token, obs->token_len); - - /* TODO use resource-specific COAP_OBSERVE_REFRESH_INTERVAL for CON to check client interest */ - - transaction->packet_len = - coap_serialize_message(notification, transaction->packet); - - coap_send_transaction(transaction); - } - } - } -} -/*---------------------------------------------------------------------------*/ -void -coap_observe_handler(resource_t * resource, void *request, void *response) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - coap_packet_t *const coap_res = (coap_packet_t *) response; - - static char content[16]; - - 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_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, - coap_req->token, coap_req->token_len, - resource->url)) { - coap_set_header_observe(coap_res, 0); - /* - * for demonstration purposes only. A subscription should return the same representation as a normal GET - * FIXME comment the following command for any real application - */ - coap_set_payload(coap_res, - content, - snprintf(content, sizeof(content), "Added %u/%u", - list_length(observers_list), - COAP_MAX_OBSERVERS)); - } else { - coap_res->code = SERVICE_UNAVAILABLE_5_03; - coap_set_payload(coap_res, "TooManyObservers", 16); - } /* if(added observer) */ - } else { /* if (observe) */ - - /* remove client if it is currently observe */ - coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, - UIP_UDP_BUF->srcport, coap_req->token, - coap_req->token_len); - } /* if(observe) */ - } -} -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 observing resources (draft-ietf-core-observe-11). + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "er-coap-observe.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/*---------------------------------------------------------------------------*/ +MEMB(observers_memb, coap_observer_t, COAP_MAX_OBSERVERS); +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) +{ + /* Remove existing observe relationship, if any. */ + coap_remove_observer_by_uri(addr, port, uri); + + coap_observer_t *o = memb_alloc(&observers_memb); + + if(o) { + o->url = uri; + uip_ipaddr_copy(&o->addr, addr); + o->port = port; + o->token_len = token_len; + memcpy(o->token, token, token_len); + o->last_mid = 0; + + PRINTF("Adding observer for /%s [0x%02X%02X]\n", o->url, o->token[0], + o->token[1]); + list_add(observers_list, o); + } + + return o; +} +/*---------------------------------------------------------------------------*/ +/*- Removal -----------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_remove_observer(coap_observer_t *o) +{ + PRINTF("Removing observer for /%s [0x%02X%02X]\n", o->url, o->token[0], + o->token[1]); + + memb_free(&observers_memb, o); + list_remove(observers_list, o); +} +/*---------------------------------------------------------------------------*/ +int +coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port) +{ + int removed = 0; + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + PRINTF("Remove check client "); + PRINT6ADDR(addr); + PRINTF(":%u\n", port); + if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port) { + coap_remove_observer(obs); + removed++; + } + } + return removed; +} +/*---------------------------------------------------------------------------*/ +int +coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, + uint8_t *token, size_t token_len) +{ + int removed = 0; + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]); + if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port + && obs->token_len == token_len + && memcmp(obs->token, token, token_len) == 0) { + coap_remove_observer(obs); + removed++; + } + } + return removed; +} +/*---------------------------------------------------------------------------*/ +int +coap_remove_observer_by_uri(uip_ipaddr_t *addr, uint16_t port, + const char *uri) +{ + int removed = 0; + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + PRINTF("Remove check URL %p\n", uri); + if((addr == NULL + || (uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port)) + && (obs->url == uri || memcmp(obs->url, uri, strlen(obs->url)) == 0)) { + coap_remove_observer(obs); + removed++; + } + } + return removed; +} +/*---------------------------------------------------------------------------*/ +int +coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid) +{ + int removed = 0; + coap_observer_t *obs = NULL; + + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + PRINTF("Remove check MID %u\n", mid); + if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port + && obs->last_mid == mid) { + coap_remove_observer(obs); + removed++; + } + } + return removed; +} +/*---------------------------------------------------------------------------*/ +/*- Notification ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_notify_observers(resource_t *resource) +{ + /* 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_observer_t *obs = NULL; + + PRINTF("Observe: Notification from %s\n", resource->url); + + /* iterate over observers */ + for(obs = (coap_observer_t *)list_head(observers_list); obs; + obs = obs->next) { + if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */ + coap_transaction_t *transaction = NULL; + + /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ + + if((transaction = + coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) { + PRINTF(" Observer "); + PRINT6ADDR(&obs->addr); + PRINTF(":%u\n", obs->port); + + /* update last MID for RST matching */ + obs->last_mid = transaction->mid; + + /* prepare response */ + notification->mid = transaction->mid; + + resource->get_handler(NULL, notification, + transaction->packet + COAP_MAX_HEADER_SIZE, + REST_MAX_CHUNK_SIZE, NULL); + + if(notification->code < BAD_REQUEST_4_00) { + coap_set_header_observe(notification, (obs->obs_counter)++); + } + coap_set_token(notification, obs->token, obs->token_len); + + /* TODO use resource-specific COAP_OBSERVE_REFRESH_INTERVAL for CON to check client interest */ + + transaction->packet_len = + coap_serialize_message(notification, transaction->packet); + + coap_send_transaction(transaction); + } + } + } +} +/*---------------------------------------------------------------------------*/ +void +coap_observe_handler(resource_t *resource, void *request, void *response) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + coap_packet_t *const coap_res = (coap_packet_t *)response; + + static char content[16]; + + 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_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, + coap_req->token, coap_req->token_len, + resource->url)) { + coap_set_header_observe(coap_res, 0); + /* + * for demonstration purposes only. A subscription should return the same representation as a normal GET + * FIXME comment the following command for any real application + */ + coap_set_payload(coap_res, + content, + snprintf(content, sizeof(content), "Added %u/%u", + list_length(observers_list), + COAP_MAX_OBSERVERS)); + } else { + coap_res->code = SERVICE_UNAVAILABLE_5_03; + coap_set_payload(coap_res, "TooManyObservers", 16); + } /* if(added observer) */ + } else { /* if (observe) */ + + /* remove client if it is currently observe */ + coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, + UIP_UDP_BUF->srcport, coap_req->token, + coap_req->token_len); + /* if(observe) */ + } + } +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-observe.h b/apps/er-coap/er-coap-observe.h old mode 100755 new mode 100644 index 785534839..6d0498bb6 --- a/apps/er-coap/er-coap-observe.h +++ b/apps/er-coap/er-coap-observe.h @@ -1,90 +1,90 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 observing resources (draft-ietf-core-observe-11). - * \author - * Matthias Kovatsch - */ - -#ifndef COAP_OBSERVE_H_ -#define COAP_OBSERVE_H_ - -#include "er-coap.h" -#include "er-coap-transactions.h" -#include "stimer.h" - -typedef struct coap_observable { - uint32_t observe_clock; - struct stimer orphan_timer; - list_t observers; - coap_packet_t notification; - uint8_t buffer[COAP_MAX_PACKET_SIZE + 1]; -} coap_observable_t; - -typedef struct coap_observer { - struct coap_observer *next; /* for LIST */ - - const char *url; - uip_ipaddr_t addr; - uint16_t port; - uint8_t token_len; - uint8_t token[COAP_TOKEN_LEN]; - uint16_t last_mid; - - int32_t obs_counter; - - struct etimer retrans_timer; - uint8_t retrans_counter; -} 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, - uint8_t * token, size_t token_len); -int coap_remove_observer_by_uri(uip_ipaddr_t * addr, uint16_t port, - const char *uri); -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_observe_handler(resource_t * resource, void *request, - void *response); - -#endif /* COAP_OBSERVE_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 observing resources (draft-ietf-core-observe-11). + * \author + * Matthias Kovatsch + */ + +#ifndef COAP_OBSERVE_H_ +#define COAP_OBSERVE_H_ + +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "stimer.h" + +typedef struct coap_observable { + uint32_t observe_clock; + struct stimer orphan_timer; + list_t observers; + coap_packet_t notification; + uint8_t buffer[COAP_MAX_PACKET_SIZE + 1]; +} coap_observable_t; + +typedef struct coap_observer { + struct coap_observer *next; /* for LIST */ + + const char *url; + uip_ipaddr_t addr; + uint16_t port; + uint8_t token_len; + uint8_t token[COAP_TOKEN_LEN]; + uint16_t last_mid; + + int32_t obs_counter; + + struct etimer retrans_timer; + uint8_t retrans_counter; +} 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, + uint8_t *token, size_t token_len); +int coap_remove_observer_by_uri(uip_ipaddr_t *addr, uint16_t port, + const char *uri); +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_observe_handler(resource_t *resource, void *request, + void *response); + +#endif /* COAP_OBSERVE_H_ */ diff --git a/apps/er-coap/er-coap-res-well-known-core.c b/apps/er-coap/er-coap-res-well-known-core.c old mode 100755 new mode 100644 index d405a5ae4..69e6e7a97 --- a/apps/er-coap/er-coap-res-well-known-core.c +++ b/apps/er-coap/er-coap-res-well-known-core.c @@ -1,220 +1,232 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * /.well-known/core resource implementation. - * \author - * Matthias Kovatsch - */ - -#include -#include "er-coap-engine.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -/*---------------------------------------------------------------------------*/ -/*- Resource Handlers -------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -well_known_core_get_handler(void *request, void *response, uint8_t * buffer, - uint16_t preferred_size, int32_t * offset) -{ - size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ - size_t bufpos = 0; /* position within buffer (bytes written) */ - size_t tmplen = 0; - resource_t *resource = NULL; - -#if COAP_LINK_FORMAT_FILTERING - /* For filtering. */ - const char *filter = NULL; - const char *attrib = NULL; - const char *found = NULL; - const char *end = NULL; - char *value = NULL; - char lastchar = '\0'; - int len = coap_get_header_uri_query(request, &filter); - - if(len) { - value = strchr(filter, '='); - value[0] = '\0'; - ++value; - len -= strlen(filter) + 1; - - PRINTF("Filter %s = %.*s\n", filter, len, value); - - if(strcmp(filter, "href") == 0 && value[0] == '/') { - ++value; - --len; - } - - lastchar = value[len - 1]; - value[len - 1] = '\0'; - } -#endif - - for(resource = (resource_t *) list_head(rest_get_resources()); resource; - resource = resource->next) { -#if COAP_LINK_FORMAT_FILTERING - /* Filtering */ - if(len) { - if(strcmp(filter, "href") == 0) { - attrib = strstr(resource->url, value); - if(attrib == NULL || (value[-1] == '/' && attrib != resource->url)) - continue; - end = attrib + strlen(attrib); - } else { - attrib = strstr(resource->attributes, filter); - if(attrib == NULL - || (attrib[strlen(filter)] != '=' - && attrib[strlen(filter)] != '"')) - continue; - attrib += strlen(filter) + 2; - end = strchr(attrib, '"'); - } - - PRINTF("Filter: res has attrib %s (%s)\n", attrib, value); - found = attrib; - while((found = strstr(found, value)) != NULL) { - if(found > end) { - found = NULL; - break; - } - if(lastchar == found[len - 1] || lastchar == '*') { - break; - } - ++found; - } - if(found == NULL) { - continue; - } - PRINTF("Filter: res has prefix %s\n", found); - if(lastchar != '*' - && (found[len] != '"' && found[len] != ' ' && found[len] != '\0')) - continue; - PRINTF("Filter: res has match\n"); - } -#endif - - PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource, - strpos, *offset, bufpos); - - if(strpos > 0) { - if(strpos >= *offset && bufpos < preferred_size) { - buffer[bufpos++] = ','; - } - ++strpos; - } - - 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; - - 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; - } - - /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ - if(bufpos > preferred_size && strpos - bufpos > *offset) { - PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); - break; - } - } - - if(bufpos > 0) { - PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *)buffer); - - coap_set_payload(response, buffer, bufpos); - coap_set_header_content_format(response, APPLICATION_LINK_FORMAT); - } else if(strpos > 0) { - PRINTF("well_known_core_handler(): bufpos<=0\n"); - - coap_set_status_code(response, BAD_OPTION_4_02); - coap_set_payload(response, "BlockOutOfScope", 15); - } - - if(resource == NULL) { - PRINTF("res: DONE\n"); - *offset = -1; - } else { - PRINTF("res: MORE at %s (%p)\n", resource->url, resource); - *offset += preferred_size; - } -} -/*---------------------------------------------------------------------------*/ -RESOURCE(res_well_known_core, "ct=40", well_known_core_get_handler, NULL, - NULL, NULL); -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * /.well-known/core resource implementation. + * \author + * Matthias Kovatsch + */ + +#include +#include "er-coap-engine.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/*---------------------------------------------------------------------------*/ +/*- Resource Handlers -------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +well_known_core_get_handler(void *request, void *response, uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ + size_t bufpos = 0; /* position within buffer (bytes written) */ + size_t tmplen = 0; + resource_t *resource = NULL; + +#if COAP_LINK_FORMAT_FILTERING + /* For filtering. */ + const char *filter = NULL; + const char *attrib = NULL; + const char *found = NULL; + const char *end = NULL; + char *value = NULL; + char lastchar = '\0'; + int len = coap_get_header_uri_query(request, &filter); + + if(len) { + value = strchr(filter, '='); + value[0] = '\0'; + ++value; + len -= strlen(filter) + 1; + + PRINTF("Filter %s = %.*s\n", filter, len, value); + + if(strcmp(filter, "href") == 0 && value[0] == '/') { + ++value; + --len; + } + + lastchar = value[len - 1]; + value[len - 1] = '\0'; + } +#endif + + for(resource = (resource_t *)list_head(rest_get_resources()); resource; + resource = resource->next) { +#if COAP_LINK_FORMAT_FILTERING + /* Filtering */ + if(len) { + if(strcmp(filter, "href") == 0) { + attrib = strstr(resource->url, value); + if(attrib == NULL || (value[-1] == '/' && attrib != resource->url)) { + continue; + } + end = attrib + strlen(attrib); + } else { + attrib = strstr(resource->attributes, filter); + if(attrib == NULL + || (attrib[strlen(filter)] != '=' + && attrib[strlen(filter)] != '"')) { + continue; + } + attrib += strlen(filter) + 2; + end = strchr(attrib, '"'); + } + + PRINTF("Filter: res has attrib %s (%s)\n", attrib, value); + found = attrib; + while((found = strstr(found, value)) != NULL) { + if(found > end) { + found = NULL; + break; + } + if(lastchar == found[len - 1] || lastchar == '*') { + break; + } + ++found; + } + if(found == NULL) { + continue; + } + PRINTF("Filter: res has prefix %s\n", found); + if(lastchar != '*' + && (found[len] != '"' && found[len] != ' ' && found[len] != '\0')) { + continue; + } + PRINTF("Filter: res has match\n"); + } +#endif + + PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource, + strpos, *offset, bufpos); + + if(strpos > 0) { + if(strpos >= *offset && bufpos < preferred_size) { + buffer[bufpos++] = ','; + } + ++strpos; + } + + 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; + + 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; + } + + /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ + if(bufpos > preferred_size && strpos - bufpos > *offset) { + PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); + break; + } + } + + if(bufpos > 0) { + PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *)buffer); + + coap_set_payload(response, buffer, bufpos); + coap_set_header_content_format(response, APPLICATION_LINK_FORMAT); + } else if(strpos > 0) { + PRINTF("well_known_core_handler(): bufpos<=0\n"); + + coap_set_status_code(response, BAD_OPTION_4_02); + coap_set_payload(response, "BlockOutOfScope", 15); + } + + if(resource == NULL) { + PRINTF("res: DONE\n"); + *offset = -1; + } else { + PRINTF("res: MORE at %s (%p)\n", resource->url, resource); + *offset += preferred_size; + } +} +/*---------------------------------------------------------------------------*/ +RESOURCE(res_well_known_core, "ct=40", well_known_core_get_handler, NULL, + NULL, NULL); +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-separate.c b/apps/er-coap/er-coap-separate.c old mode 100755 new mode 100644 index 7646f806b..7d53e5b9f --- a/apps/er-coap/er-coap-separate.c +++ b/apps/er-coap/er-coap-separate.c @@ -1,133 +1,141 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 separate responses. - * \author - * Matthias Kovatsch - */ - -#include -#include -#include "er-coap-separate.h" -#include "er-coap-transactions.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -/*---------------------------------------------------------------------------*/ -/*- Separate Response API ---------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -/** - * \brief Reject a request that would require a separate response with an error message - * - * When the server does not have enough resources left to store the information - * for a separate response or otherwise cannot execute the resource handler, - * this function will respond with 5.03 Service Unavailable. The client can - * then retry later. - */ -void -coap_separate_reject() -{ - // TODO: Accept string pointer for custom error message - erbium_status_code = SERVICE_UNAVAILABLE_5_03; - coap_error_message = "AlreadyInUse"; -} -/*----------------------------------------------------------------------------*/ -/** - * \brief Initiate a separate response with an empty ACK - * \param request The request to accept - * \param separate_store A pointer to the data structure that will store the - * relevant information for the response - * - * When the server does not have enough resources left to store the information - * for a separate response or otherwise cannot execute the resource handler, - * this function will respond with 5.03 Service Unavailable. The client can - * then retry later. - */ -void -coap_separate_accept(void *request, coap_separate_t * separate_store) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - coap_transaction_t *const t = coap_get_transaction_by_mid(coap_req->mid); - - PRINTF("Separate ACCEPT: /%.*s MID %u\n", coap_req->uri_path_len, - coap_req->uri_path, coap_req->mid); - if(t) { - /* send separate ACK for CON */ - if(coap_req->type == COAP_TYPE_CON) { - coap_packet_t ack[1]; - - /* ACK with empty code (0) */ - coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid); - /* serializing into IPBUF: Only overwrites header parts that are already parsed into the request struct */ - coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, - (uip_appdata), coap_serialize_message(ack, - uip_appdata)); - } - - /* store remote address */ - uip_ipaddr_copy(&separate_store->addr, &t->addr); - separate_store->port = t->port; - - /* store correct response type */ - separate_store->type = - coap_req->type == COAP_TYPE_CON ? COAP_TYPE_CON : COAP_TYPE_NON; - separate_store->mid = coap_get_mid(); /* if it was a NON, we burned one MID in the engine... */ - - memcpy(separate_store->token, coap_req->token, coap_req->token_len); - separate_store->token_len = coap_req->token_len; - - separate_store->block2_num = coap_req->block2_num; - separate_store->block2_size = coap_req->block2_size; - - /* signal the engine to skip automatic response and clear transaction by engine */ - erbium_status_code = MANUAL_RESPONSE; - - } else { - PRINTF("ERROR: Response transaction for separate request not found!\n"); - erbium_status_code = INTERNAL_SERVER_ERROR_5_00; - } -} -/*----------------------------------------------------------------------------*/ -void -coap_separate_resume(void *response, coap_separate_t * separate_store, - uint8_t code) -{ - coap_init_message(response, separate_store->type, code, - separate_store->mid); - if(separate_store->token_len) { - coap_set_token(response, separate_store->token, - separate_store->token_len); - } -} -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 separate responses. + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "er-coap-separate.h" +#include "er-coap-transactions.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/*---------------------------------------------------------------------------*/ +/*- Separate Response API ---------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * \brief Reject a request that would require a separate response with an error message + * + * When the server does not have enough resources left to store the information + * for a separate response or otherwise cannot execute the resource handler, + * this function will respond with 5.03 Service Unavailable. The client can + * then retry later. + */ +void +coap_separate_reject() +{ + /* TODO: Accept string pointer for custom error message */ + erbium_status_code = SERVICE_UNAVAILABLE_5_03; + coap_error_message = "AlreadyInUse"; +} +/*----------------------------------------------------------------------------*/ +/** + * \brief Initiate a separate response with an empty ACK + * \param request The request to accept + * \param separate_store A pointer to the data structure that will store the + * relevant information for the response + * + * When the server does not have enough resources left to store the information + * for a separate response or otherwise cannot execute the resource handler, + * this function will respond with 5.03 Service Unavailable. The client can + * then retry later. + */ +void +coap_separate_accept(void *request, coap_separate_t *separate_store) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + coap_transaction_t *const t = coap_get_transaction_by_mid(coap_req->mid); + + PRINTF("Separate ACCEPT: /%.*s MID %u\n", coap_req->uri_path_len, + coap_req->uri_path, coap_req->mid); + if(t) { + /* send separate ACK for CON */ + if(coap_req->type == COAP_TYPE_CON) { + coap_packet_t ack[1]; + + /* ACK with empty code (0) */ + coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid); + /* serializing into IPBUF: Only overwrites header parts that are already parsed into the request struct */ + coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, + (uip_appdata), coap_serialize_message(ack, + uip_appdata)); + } + + /* store remote address */ + uip_ipaddr_copy(&separate_store->addr, &t->addr); + separate_store->port = t->port; + + /* store correct response type */ + separate_store->type = + coap_req->type == COAP_TYPE_CON ? COAP_TYPE_CON : COAP_TYPE_NON; + separate_store->mid = coap_get_mid(); /* if it was a NON, we burned one MID in the engine... */ + + memcpy(separate_store->token, coap_req->token, coap_req->token_len); + separate_store->token_len = coap_req->token_len; + + separate_store->block2_num = coap_req->block2_num; + separate_store->block2_size = coap_req->block2_size; + + /* signal the engine to skip automatic response and clear transaction by engine */ + erbium_status_code = MANUAL_RESPONSE; + } else { + PRINTF("ERROR: Response transaction for separate request not found!\n"); + erbium_status_code = INTERNAL_SERVER_ERROR_5_00; + } +} +/*----------------------------------------------------------------------------*/ +void +coap_separate_resume(void *response, coap_separate_t *separate_store, + uint8_t code) +{ + coap_init_message(response, separate_store->type, code, + separate_store->mid); + if(separate_store->token_len) { + coap_set_token(response, separate_store->token, + separate_store->token_len); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-separate.h b/apps/er-coap/er-coap-separate.h old mode 100755 new mode 100644 index 0b855d1ca..20c6dd65d --- a/apps/er-coap/er-coap-separate.h +++ b/apps/er-coap/er-coap-separate.h @@ -1,68 +1,67 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 separate responses. - * \author - * Matthias Kovatsch - */ - -#ifndef COAP_SEPARATE_H_ -#define COAP_SEPARATE_H_ - -#include "er-coap.h" - -typedef struct coap_separate { - - uip_ipaddr_t addr; - uint16_t port; - - coap_message_type_t type; - uint16_t mid; - - uint8_t token_len; - uint8_t token[COAP_TOKEN_LEN]; - - /* separate + blockwise is untested! */ - uint32_t block2_num; - uint16_t block2_size; - -} coap_separate_t; - -int coap_separate_handler(resource_t * resource, void *request, - void *response); -void coap_separate_reject(); -void coap_separate_accept(void *request, coap_separate_t * separate_store); -void coap_separate_resume(void *response, coap_separate_t * separate_store, - uint8_t code); - -#endif /* COAP_SEPARATE_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 separate responses. + * \author + * Matthias Kovatsch + */ + +#ifndef COAP_SEPARATE_H_ +#define COAP_SEPARATE_H_ + +#include "er-coap.h" + +typedef struct coap_separate { + + uip_ipaddr_t addr; + uint16_t port; + + coap_message_type_t type; + uint16_t mid; + + uint8_t token_len; + uint8_t token[COAP_TOKEN_LEN]; + + /* separate + blockwise is untested! */ + uint32_t block2_num; + uint16_t block2_size; +} coap_separate_t; + +int coap_separate_handler(resource_t *resource, void *request, + void *response); +void coap_separate_reject(); +void coap_separate_accept(void *request, coap_separate_t *separate_store); +void coap_separate_resume(void *response, coap_separate_t *separate_store, + uint8_t code); + +#endif /* COAP_SEPARATE_H_ */ diff --git a/apps/er-coap/er-coap-transactions.c b/apps/er-coap/er-coap-transactions.c old mode 100755 new mode 100644 index ce201821a..7f6537932 --- a/apps/er-coap/er-coap-transactions.c +++ b/apps/er-coap/er-coap-transactions.c @@ -1,178 +1,185 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 reliable transport - * \author - * Matthias Kovatsch - */ - -#include "contiki.h" -#include "contiki-net.h" -#include "er-coap-transactions.h" -#include "er-coap-observe.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -/*---------------------------------------------------------------------------*/ -MEMB(transactions_memb, coap_transaction_t, COAP_MAX_OPEN_TRANSACTIONS); -LIST(transactions_list); - -static struct process *transaction_handler_process = NULL; - -/*---------------------------------------------------------------------------*/ -/*- Internal API ------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -coap_register_as_transaction_handler() -{ - transaction_handler_process = PROCESS_CURRENT(); -} - -coap_transaction_t * -coap_new_transaction(uint16_t mid, uip_ipaddr_t * addr, uint16_t port) -{ - coap_transaction_t *t = memb_alloc(&transactions_memb); - - if(t) { - t->mid = mid; - t->retrans_counter = 0; - - /* save client address */ - uip_ipaddr_copy(&t->addr, addr); - t->port = port; - - list_add(transactions_list, t); /* list itself makes sure same element is not added twice */ - } - - return t; -} -/*---------------------------------------------------------------------------*/ -void -coap_send_transaction(coap_transaction_t * t) -{ - PRINTF("Sending transaction %u\n", t->mid); - - coap_send_message(&t->addr, t->port, t->packet, t->packet_len); - - if(COAP_TYPE_CON == - ((COAP_HEADER_TYPE_MASK & t->packet[0]) >> COAP_HEADER_TYPE_POSITION)) { - if(t->retrans_counter < COAP_MAX_RETRANSMIT) { - /* not timed out yet */ - PRINTF("Keeping transaction %u\n", t->mid); - - if(t->retrans_counter == 0) { - t->retrans_timer.timer.interval = - COAP_RESPONSE_TIMEOUT_TICKS + (random_rand() - % - (clock_time_t) - COAP_RESPONSE_TIMEOUT_BACKOFF_MASK); - PRINTF("Initial interval %f\n", - (float)t->retrans_timer.timer.interval / CLOCK_SECOND); - } else { - t->retrans_timer.timer.interval <<= 1; /* double */ - PRINTF("Doubled (%u) interval %f\n", t->retrans_counter, - (float)t->retrans_timer.timer.interval / CLOCK_SECOND); - } - - /*FIXME - * 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 */ - process_current = process_actual; - - t = NULL; - } else { - /* timed out */ - PRINTF("Timeout\n"); - restful_response_handler callback = t->callback; - void *callback_data = t->callback_data; - - /* handle observers */ - coap_remove_observer_by_client(&t->addr, t->port); - - coap_clear_transaction(t); - - if(callback) { - callback(callback_data, NULL); - } - } - } else { - coap_clear_transaction(t); - } -} -/*---------------------------------------------------------------------------*/ -void -coap_clear_transaction(coap_transaction_t * t) -{ - if(t) { - PRINTF("Freeing transaction %u: %p\n", t->mid, t); - - etimer_stop(&t->retrans_timer); - list_remove(transactions_list, t); - memb_free(&transactions_memb, t); - } -} - -coap_transaction_t * -coap_get_transaction_by_mid(uint16_t mid) -{ - coap_transaction_t *t = NULL; - - for(t = (coap_transaction_t *) list_head(transactions_list); t; t = t->next) { - if(t->mid == mid) { - PRINTF("Found transaction for MID %u: %p\n", t->mid, t); - return t; - } - } - return NULL; -} -/*---------------------------------------------------------------------------*/ -void -coap_check_transactions() -{ - coap_transaction_t *t = NULL; - - for(t = (coap_transaction_t *) list_head(transactions_list); t; t = t->next) { - if(etimer_expired(&t->retrans_timer)) { - ++(t->retrans_counter); - PRINTF("Retransmitting %u (%u)\n", t->mid, t->retrans_counter); - coap_send_transaction(t); - } - } -} -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 reliable transport + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "er-coap-transactions.h" +#include "er-coap-observe.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/*---------------------------------------------------------------------------*/ +MEMB(transactions_memb, coap_transaction_t, COAP_MAX_OPEN_TRANSACTIONS); +LIST(transactions_list); + +static struct process *transaction_handler_process = NULL; + +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_register_as_transaction_handler() +{ + transaction_handler_process = PROCESS_CURRENT(); +} +coap_transaction_t * +coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, uint16_t port) +{ + coap_transaction_t *t = memb_alloc(&transactions_memb); + + if(t) { + t->mid = mid; + t->retrans_counter = 0; + + /* save client address */ + uip_ipaddr_copy(&t->addr, addr); + t->port = port; + + list_add(transactions_list, t); /* list itself makes sure same element is not added twice */ + } + + return t; +} +/*---------------------------------------------------------------------------*/ +void +coap_send_transaction(coap_transaction_t *t) +{ + PRINTF("Sending transaction %u\n", t->mid); + + coap_send_message(&t->addr, t->port, t->packet, t->packet_len); + + if(COAP_TYPE_CON == + ((COAP_HEADER_TYPE_MASK & t->packet[0]) >> COAP_HEADER_TYPE_POSITION)) { + if(t->retrans_counter < COAP_MAX_RETRANSMIT) { + /* not timed out yet */ + PRINTF("Keeping transaction %u\n", t->mid); + + if(t->retrans_counter == 0) { + t->retrans_timer.timer.interval = + COAP_RESPONSE_TIMEOUT_TICKS + (random_rand() + % + (clock_time_t) + COAP_RESPONSE_TIMEOUT_BACKOFF_MASK); + PRINTF("Initial interval %f\n", + (float)t->retrans_timer.timer.interval / CLOCK_SECOND); + } else { + t->retrans_timer.timer.interval <<= 1; /* double */ + PRINTF("Doubled (%u) interval %f\n", t->retrans_counter, + (float)t->retrans_timer.timer.interval / CLOCK_SECOND); + } + + /*FIXME + * 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 */ + process_current = process_actual; + + t = NULL; + } else { + /* timed out */ + PRINTF("Timeout\n"); + restful_response_handler callback = t->callback; + void *callback_data = t->callback_data; + + /* handle observers */ + coap_remove_observer_by_client(&t->addr, t->port); + + coap_clear_transaction(t); + + if(callback) { + callback(callback_data, NULL); + } + } + } else { + coap_clear_transaction(t); + } +} +/*---------------------------------------------------------------------------*/ +void +coap_clear_transaction(coap_transaction_t *t) +{ + if(t) { + PRINTF("Freeing transaction %u: %p\n", t->mid, t); + + etimer_stop(&t->retrans_timer); + list_remove(transactions_list, t); + memb_free(&transactions_memb, t); + } +} +coap_transaction_t * +coap_get_transaction_by_mid(uint16_t mid) +{ + coap_transaction_t *t = NULL; + + for(t = (coap_transaction_t *)list_head(transactions_list); t; t = t->next) { + if(t->mid == mid) { + PRINTF("Found transaction for MID %u: %p\n", t->mid, t); + return t; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +coap_check_transactions() +{ + coap_transaction_t *t = NULL; + + for(t = (coap_transaction_t *)list_head(transactions_list); t; t = t->next) { + if(etimer_expired(&t->retrans_timer)) { + ++(t->retrans_counter); + PRINTF("Retransmitting %u (%u)\n", t->mid, t->retrans_counter); + coap_send_transaction(t); + } + } +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap-transactions.h b/apps/er-coap/er-coap-transactions.h old mode 100755 new mode 100644 index 2db9ab477..18bb421b1 --- a/apps/er-coap/er-coap-transactions.h +++ b/apps/er-coap/er-coap-transactions.h @@ -1,80 +1,80 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 reliable transport - * \author - * Matthias Kovatsch - */ - -#ifndef COAP_TRANSACTIONS_H_ -#define COAP_TRANSACTIONS_H_ - -#include "er-coap.h" - -/* - * Modulo mask (thus +1) for a random number to get the tick number for the random - * retransmission time between COAP_RESPONSE_TIMEOUT and COAP_RESPONSE_TIMEOUT*COAP_RESPONSE_RANDOM_FACTOR. - */ -#define COAP_RESPONSE_TIMEOUT_TICKS (CLOCK_SECOND * COAP_RESPONSE_TIMEOUT) -#define COAP_RESPONSE_TIMEOUT_BACKOFF_MASK (long)((CLOCK_SECOND * COAP_RESPONSE_TIMEOUT * ((float)COAP_RESPONSE_RANDOM_FACTOR - 1.0)) + 0.5) + 1 - -/* container for transactions with message buffer and retransmission info */ -typedef struct coap_transaction { - struct coap_transaction *next; /* for LIST */ - - uint16_t mid; - struct etimer retrans_timer; - uint8_t retrans_counter; - - uip_ipaddr_t addr; - uint16_t port; - - restful_response_handler callback; - void *callback_data; - - uint16_t packet_len; - uint8_t packet[COAP_MAX_PACKET_SIZE + 1]; /* +1 for the terminating '\0' which will not be sent - * Use snprintf(buf, len+1, "", ...) to completely fill payload */ -} coap_transaction_t; - -void coap_register_as_transaction_handler(); - -coap_transaction_t *coap_new_transaction(uint16_t mid, uip_ipaddr_t * addr, - uint16_t port); -void coap_send_transaction(coap_transaction_t * t); -void coap_clear_transaction(coap_transaction_t * t); -coap_transaction_t *coap_get_transaction_by_mid(uint16_t mid); - -void coap_check_transactions(); - -#endif /* COAP_TRANSACTIONS_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 reliable transport + * \author + * Matthias Kovatsch + */ + +#ifndef COAP_TRANSACTIONS_H_ +#define COAP_TRANSACTIONS_H_ + +#include "er-coap.h" + +/* + * Modulo mask (thus +1) for a random number to get the tick number for the random + * retransmission time between COAP_RESPONSE_TIMEOUT and COAP_RESPONSE_TIMEOUT*COAP_RESPONSE_RANDOM_FACTOR. + */ +#define COAP_RESPONSE_TIMEOUT_TICKS (CLOCK_SECOND * COAP_RESPONSE_TIMEOUT) +#define COAP_RESPONSE_TIMEOUT_BACKOFF_MASK (long)((CLOCK_SECOND * COAP_RESPONSE_TIMEOUT * ((float)COAP_RESPONSE_RANDOM_FACTOR - 1.0)) + 0.5) + 1 + +/* container for transactions with message buffer and retransmission info */ +typedef struct coap_transaction { + struct coap_transaction *next; /* for LIST */ + + uint16_t mid; + struct etimer retrans_timer; + uint8_t retrans_counter; + + uip_ipaddr_t addr; + uint16_t port; + + restful_response_handler callback; + void *callback_data; + + uint16_t packet_len; + uint8_t packet[COAP_MAX_PACKET_SIZE + 1]; /* +1 for the terminating '\0' which will not be sent + * Use snprintf(buf, len+1, "", ...) to completely fill payload */ +} coap_transaction_t; + +void coap_register_as_transaction_handler(); + +coap_transaction_t *coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, + uint16_t port); +void coap_send_transaction(coap_transaction_t *t); +void coap_clear_transaction(coap_transaction_t *t); +coap_transaction_t *coap_get_transaction_by_mid(uint16_t mid); + +void coap_check_transactions(); + +#endif /* COAP_TRANSACTIONS_H_ */ diff --git a/apps/er-coap/er-coap.c b/apps/er-coap/er-coap.c old mode 100755 new mode 100644 index 62a186d0f..23fac35cb --- a/apps/er-coap/er-coap.c +++ b/apps/er-coap/er-coap.c @@ -1,1184 +1,1186 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * An implementation of the Constrained Application Protocol (RFC). - * \author - * Matthias Kovatsch - */ - -#include -#include -#include "contiki.h" -#include "contiki-net.h" -#include "er-coap.h" -#include "er-coap-transactions.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -/*---------------------------------------------------------------------------*/ -/*- Variables ---------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -static struct uip_udp_conn *udp_conn = NULL; -static uint16_t current_mid = 0; - -coap_status_t erbium_status_code = NO_ERROR; -char *coap_error_message = ""; -/*---------------------------------------------------------------------------*/ -/*- Local helper functions --------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -static uint16_t -coap_log_2(uint16_t value) -{ - uint16_t result = 0; - - do { - value = value >> 1; - result++; - } while(value); - - return result ? result - 1 : result; -} -/*---------------------------------------------------------------------------*/ -static uint32_t -coap_parse_int_option(uint8_t * bytes, size_t length) -{ - uint32_t var = 0; - int i = 0; - - while(i < length) { - var <<= 8; - var |= bytes[i++]; - } - return var; -} -/*---------------------------------------------------------------------------*/ -static uint8_t -coap_option_nibble(unsigned int value) -{ - if(value < 13) { - return value; - } else if(value <= 0xFF + 13) { - return 13; - } else { - return 14; - } -} -/*---------------------------------------------------------------------------*/ -static size_t -coap_set_option_header(unsigned int delta, size_t length, uint8_t * buffer) -{ - size_t written = 0; - - buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length); - - /* avoids code duplication without function overhead */ - unsigned int *x = δ - - do { - if(*x > 268) { - buffer[++written] = (*x - 269) >> 8; - buffer[++written] = (*x - 269); - } else if(*x > 12) { - buffer[++written] = (*x - 13); - } - } while(x != &length && (x = &length)); - - PRINTF("WRITTEN %u B opt header\n", 1 + written); - - return ++written; -} -/*---------------------------------------------------------------------------*/ -static size_t -coap_serialize_int_option(unsigned int number, unsigned int current_number, - uint8_t * buffer, uint32_t value) -{ - size_t i = 0; - - if(0xFF000000 & value) - ++i; - if(0xFFFF0000 & value) - ++i; - if(0xFFFFFF00 & value) - ++i; - if(0xFFFFFFFF & value) - ++i; - - PRINTF("OPTION %u (delta %u, len %u)\n", number, number - current_number, - i); - - i = coap_set_option_header(number - current_number, i, buffer); - - if(0xFF000000 & value) - buffer[i++] = (uint8_t) (value >> 24); - if(0xFFFF0000 & value) - buffer[i++] = (uint8_t) (value >> 16); - if(0xFFFFFF00 & value) - buffer[i++] = (uint8_t) (value >> 8); - if(0xFFFFFFFF & value) - buffer[i++] = (uint8_t) (value); - - return i; -} -/*---------------------------------------------------------------------------*/ -static size_t -coap_serialize_array_option(unsigned int number, unsigned int current_number, - uint8_t * buffer, uint8_t * array, size_t length, - char split_char) -{ - size_t i = 0; - - PRINTF("ARRAY type %u, len %u, full [%.*s]\n", number, length, length, - array); - - if(split_char != '\0') { - int j; - uint8_t *part_start = array; - uint8_t *part_end = NULL; - size_t temp_length; - - for(j = 0; j <= length + 1; ++j) { - PRINTF("STEP %u/%u (%c)\n", j, length, array[j]); - if(array[j] == split_char || j == length) { - part_end = array + j; - temp_length = part_end - part_start; - - i += coap_set_option_header(number - current_number, temp_length, - &buffer[i]); - memcpy(&buffer[i], part_start, temp_length); - i += temp_length; - - PRINTF("OPTION type %u, delta %u, len %u, part [%.*s]\n", number, - number - current_number, i, temp_length, part_start); - - ++j; /* skip the splitter */ - current_number = number; - part_start = array + j; - } - } /* for */ - } else { - i += coap_set_option_header(number - current_number, length, &buffer[i]); - memcpy(&buffer[i], array, length); - i += length; - - PRINTF("OPTION type %u, delta %u, len %u\n", number, - number - current_number, length); - } - - return i; -} -/*---------------------------------------------------------------------------*/ -static void -coap_merge_multi_option(char **dst, size_t * dst_len, uint8_t * option, - size_t option_len, char separator) -{ - /* merge multiple options */ - if(*dst_len > 0) { - /* dst already contains an option: concatenate */ - (*dst)[*dst_len] = separator; - *dst_len += 1; - - /* memmove handles 2-byte option headers */ - memmove((*dst) + (*dst_len), option, option_len); - - *dst_len += option_len; - } else { - /* dst is empty: set to option */ - *dst = (char *)option; - *dst_len = option_len; - } -} -/*---------------------------------------------------------------------------*/ -static int -coap_get_variable(const char *buffer, size_t length, const char *name, - const char **output) -{ - const char *start = NULL; - const char *end = NULL; - const char *value_end = NULL; - size_t name_len = 0; - - /*initialize the output buffer first */ - *output = 0; - - name_len = strlen(name); - end = buffer + length; - - for(start = buffer; start + name_len < end; ++start) { - if((start == buffer || start[-1] == '&') && start[name_len] == '=' - && strncmp(name, start, name_len) == 0) { - - /* Point start to variable value */ - start += name_len + 1; - - /* Point end to the end of the value */ - value_end = (const char *)memchr(start, '&', end - start); - if(value_end == NULL) { - value_end = end; - } - - *output = start; - - return (value_end - start); - } - } - - return 0; -} -/*---------------------------------------------------------------------------*/ -/*- Internal API ------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -void -coap_init_connection(uint16_t port) -{ - /* new connection with remote host */ - udp_conn = udp_new(NULL, 0, NULL); - udp_bind(udp_conn, port); - PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport)); - - /* initialize transaction ID */ - current_mid = random_rand(); -} -/*---------------------------------------------------------------------------*/ -uint16_t -coap_get_mid() -{ - return ++current_mid; -} -/*---------------------------------------------------------------------------*/ -void -coap_init_message(void *packet, coap_message_type_t type, uint8_t code, - uint16_t mid) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - /* Important thing */ - memset(coap_pkt, 0, sizeof(coap_packet_t)); - - coap_pkt->type = type; - coap_pkt->code = code; - coap_pkt->mid = mid; -} -/*---------------------------------------------------------------------------*/ -size_t -coap_serialize_message(void *packet, uint8_t * buffer) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - uint8_t *option; - unsigned int current_number = 0; - - /* Initialize */ - coap_pkt->buffer = buffer; - coap_pkt->version = 1; - - PRINTF("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer); - - /* set header fields */ - coap_pkt->buffer[0] = 0x00; - coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK - & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION; - coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK - & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION; - coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK - & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION; - coap_pkt->buffer[1] = coap_pkt->code; - coap_pkt->buffer[2] = (uint8_t) ((coap_pkt->mid) >> 8); - coap_pkt->buffer[3] = (uint8_t) (coap_pkt->mid); - - /* set Token */ - PRINTF("Token (len %u)", coap_pkt->token_len); - option = coap_pkt->buffer + COAP_HEADER_LEN; - for(current_number = 0; current_number < coap_pkt->token_len; - ++current_number) { - PRINTF(" %02X", coap_pkt->token[current_number]); - *option = coap_pkt->token[current_number]; - ++option; - } - PRINTF("-\n"); - - /* Serialize options */ - current_number = 0; - - PRINTF("-Serializing options at %p-\n", option); - - /* The options must be serialized in the order of their number */ - COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0', - "Uri-Host"); - COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH, - content_format - - coap_pkt-> - content_format /* hack to get a zero field */ , - "If-None-Match"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/', - "Location-Path"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/', - "Uri-Path"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, - "Content-Format"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&', - "Uri-Query"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query, - '&', "Location-Query"); - COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2"); - COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0', - "Proxy-Uri"); - COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0', - "Proxy-Scheme"); - COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1"); - - PRINTF("-Done serializing at %p----\n", option); - - /* Pack payload */ - if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) { - /* Payload marker */ - if(coap_pkt->payload_len) { - *option = 0xFF; - ++option; - } - memmove(option, coap_pkt->payload, coap_pkt->payload_len); - } else { - /* an error occurred: caller must check for !=0 */ - coap_pkt->buffer = NULL; - coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE"; - return 0; - } - - PRINTF("-Done %u B (header len %u, payload len %u)-\n", - coap_pkt->payload_len + option - buffer, option - buffer, - coap_pkt->payload_len); - - PRINTF("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n", - coap_pkt->buffer[0], - coap_pkt->buffer[1], - coap_pkt->buffer[2], - coap_pkt->buffer[3], - coap_pkt->buffer[4], - coap_pkt->buffer[5], coap_pkt->buffer[6], coap_pkt->buffer[7] - ); - - return (option - buffer) + coap_pkt->payload_len; /* packet length */ -} -/*---------------------------------------------------------------------------*/ -void -coap_send_message(uip_ipaddr_t * addr, uint16_t port, uint8_t * data, - uint16_t length) -{ - /* configure connection to reply to client */ - uip_ipaddr_copy(&udp_conn->ripaddr, addr); - udp_conn->rport = port; - - uip_udp_packet_send(udp_conn, data, length); - PRINTF("-sent UDP datagram (%u)-\n", length); - - /* restore server socket to allow data from any node */ - memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr)); - udp_conn->rport = 0; -} -/*---------------------------------------------------------------------------*/ -coap_status_t -coap_parse_message(void *packet, uint8_t * data, uint16_t data_len) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - /* initialize packet */ - memset(coap_pkt, 0, sizeof(coap_packet_t)); - - /* pointer to packet bytes */ - coap_pkt->buffer = data; - - /* parse header fields */ - coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0]) - >> COAP_HEADER_VERSION_POSITION; - coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0]) - >> COAP_HEADER_TYPE_POSITION; - coap_pkt->token_len = - MIN(COAP_TOKEN_LEN, - (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt-> - buffer[0]) >> COAP_HEADER_TOKEN_LEN_POSITION); - coap_pkt->code = coap_pkt->buffer[1]; - coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3]; - - if(coap_pkt->version != 1) { - coap_error_message = "CoAP version must be 1"; - return BAD_REQUEST_4_00; - } - - uint8_t *current_option = data + COAP_HEADER_LEN; - - memcpy(coap_pkt->token, current_option, coap_pkt->token_len); - PRINTF("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1], - coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4], - coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7] - ); /*FIXME always prints 8 bytes */ - - /* parse options */ - memset(coap_pkt->options, 0, sizeof(coap_pkt->options)); - current_option += coap_pkt->token_len; - - unsigned int option_number = 0; - unsigned int option_delta = 0; - size_t option_length = 0; - - while(current_option < data + data_len) { - /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */ - if((current_option[0] & 0xF0) == 0xF0) { - coap_pkt->payload = ++current_option; - coap_pkt->payload_len = data_len - (coap_pkt->payload - data); - - /* also for receiving, the Erbium upper bound is REST_MAX_CHUNK_SIZE */ - if(coap_pkt->payload_len > REST_MAX_CHUNK_SIZE) { - coap_pkt->payload_len = REST_MAX_CHUNK_SIZE; - } - - /* null-terminate payload */ - coap_pkt->payload[coap_pkt->payload_len] = '\0'; - - break; - } - - option_delta = current_option[0] >> 4; - option_length = current_option[0] & 0x0F; - ++current_option; - - /* avoids code duplication without function overhead */ - unsigned int *x = &option_delta; - - do { - if(*x == 13) { - *x += current_option[0]; - ++current_option; - } else if(*x == 14) { - *x += 255; - *x += current_option[0] << 8; - ++current_option; - *x += current_option[0]; - ++current_option; - } - } while(x != &option_length && (x = &option_length)); - - option_number += option_delta; - - PRINTF("OPTION %u (delta %u, len %u): ", option_number, option_delta, - option_length); - - SET_OPTION(coap_pkt, option_number); - - switch (option_number) { - case COAP_OPTION_CONTENT_FORMAT: - coap_pkt->content_format = coap_parse_int_option(current_option, - option_length); - PRINTF("Content-Format [%u]\n", coap_pkt->content_format); - break; - case COAP_OPTION_MAX_AGE: - coap_pkt->max_age = coap_parse_int_option(current_option, - option_length); - PRINTF("Max-Age [%lu]\n", coap_pkt->max_age); - break; - case COAP_OPTION_ETAG: - coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length); - memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len); - PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1], - coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4], - coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7] - ); /*FIXME always prints 8 bytes */ - break; - case COAP_OPTION_ACCEPT: - coap_pkt->accept = coap_parse_int_option(current_option, option_length); - PRINTF("Accept [%u]\n", coap_pkt->accept); - break; - case COAP_OPTION_IF_MATCH: - /* TODO support multiple ETags */ - coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length); - memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len); - PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - coap_pkt->if_match_len, coap_pkt->if_match[0], - coap_pkt->if_match[1], coap_pkt->if_match[2], - coap_pkt->if_match[3], coap_pkt->if_match[4], - coap_pkt->if_match[5], coap_pkt->if_match[6], - coap_pkt->if_match[7] - ); /* FIXME always prints 8 bytes */ - break; - case COAP_OPTION_IF_NONE_MATCH: - coap_pkt->if_none_match = 1; - PRINTF("If-None-Match\n"); - break; - - case COAP_OPTION_PROXY_URI: -#if COAP_PROXY_OPTION_PROCESSING - coap_pkt->proxy_uri = (char *)current_option; - coap_pkt->proxy_uri_len = option_length; -#endif - PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, - coap_pkt->proxy_uri); - coap_error_message = "This is a constrained server (Contiki)"; - return PROXYING_NOT_SUPPORTED_5_05; - break; - case COAP_OPTION_PROXY_SCHEME: -#if COAP_PROXY_OPTION_PROCESSING - coap_pkt->proxy_scheme = (char *)current_option; - coap_pkt->proxy_scheme_len = option_length; -#endif - PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", - coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme); - coap_error_message = "This is a constrained server (Contiki)"; - return PROXYING_NOT_SUPPORTED_5_05; - break; - - case COAP_OPTION_URI_HOST: - coap_pkt->uri_host = (char *)current_option; - coap_pkt->uri_host_len = option_length; - PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); - break; - case COAP_OPTION_URI_PORT: - coap_pkt->uri_port = coap_parse_int_option(current_option, - option_length); - PRINTF("Uri-Port [%u]\n", coap_pkt->uri_port); - break; - case COAP_OPTION_URI_PATH: - /* 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_path), - &(coap_pkt->uri_path_len), current_option, - option_length, '/'); - PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->uri_path); - break; - 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((char **)&(coap_pkt->uri_query), - &(coap_pkt->uri_query_len), current_option, - option_length, '&'); - PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, - coap_pkt->uri_query); - break; - - case COAP_OPTION_LOCATION_PATH: - /* 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->location_path), - &(coap_pkt->location_path_len), current_option, - option_length, '/'); - PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, - coap_pkt->location_path); - break; - case COAP_OPTION_LOCATION_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((char **)&(coap_pkt->location_query), - &(coap_pkt->location_query_len), current_option, - option_length, '&'); - PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, - coap_pkt->location_query); - break; - - case COAP_OPTION_OBSERVE: - coap_pkt->observe = coap_parse_int_option(current_option, - option_length); - PRINTF("Observe [%lu]\n", coap_pkt->observe); - break; - case COAP_OPTION_BLOCK2: - coap_pkt->block2_num = coap_parse_int_option(current_option, - option_length); - coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3; - coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07); - coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F) - << (coap_pkt->block2_num & 0x07); - coap_pkt->block2_num >>= 4; - PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, - coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); - break; - case COAP_OPTION_BLOCK1: - coap_pkt->block1_num = coap_parse_int_option(current_option, - option_length); - coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3; - coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07); - coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F) - << (coap_pkt->block1_num & 0x07); - coap_pkt->block1_num >>= 4; - PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, - coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size); - break; - case COAP_OPTION_SIZE2: - coap_pkt->size2 = coap_parse_int_option(current_option, option_length); - PRINTF("Size2 [%lu]\n", coap_pkt->size2); - break; - case COAP_OPTION_SIZE1: - coap_pkt->size1 = coap_parse_int_option(current_option, option_length); - PRINTF("Size1 [%lu]\n", coap_pkt->size1); - break; - default: - PRINTF("unknown (%u)\n", option_number); - /* check if critical (odd) */ - if(option_number & 1) { - coap_error_message = "Unsupported critical option"; - return BAD_OPTION_4_02; - } - } - - current_option += option_length; - } /* for */ - PRINTF("-Done parsing-------\n"); - - return NO_ERROR; -} -/*---------------------------------------------------------------------------*/ -/*- REST Engine API ---------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -int -coap_get_query_variable(void *packet, const char *name, const char **output) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { - return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len, - name, output); - } - return 0; -} - -int -coap_get_post_variable(void *packet, const char *name, const char **output) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(coap_pkt->payload_len) { - return coap_get_variable((const char *)coap_pkt->payload, - coap_pkt->payload_len, name, output); - } - return 0; -} -/*---------------------------------------------------------------------------*/ -int -coap_set_status_code(void *packet, unsigned int code) -{ - if(code <= 0xFF) { - ((coap_packet_t *) packet)->code = (uint8_t) code; - return 1; - } else { - return 0; - } -} -/*---------------------------------------------------------------------------*/ -int -coap_set_token(void *packet, const uint8_t * token, size_t token_len) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len); - memcpy(coap_pkt->token, token, coap_pkt->token_len); - - return coap_pkt->token_len; -} -/*---------------------------------------------------------------------------*/ -/*- CoAP REST Implementation API --------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -int -coap_get_header_content_format(void *packet, unsigned int *format) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) - return 0; - - *format = coap_pkt->content_format; - return 1; -} - -int -coap_set_header_content_format(void *packet, unsigned int format) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->content_format = (coap_content_format_t) format; - SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_accept(void *packet, unsigned int *accept) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) - return 0; - - *accept = coap_pkt->accept; - return 1; -} - -int -coap_set_header_accept(void *packet, unsigned int accept) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->accept = (coap_content_format_t) accept; - SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_max_age(void *packet, uint32_t * age) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { - *age = COAP_DEFAULT_MAX_AGE; - } else { - *age = coap_pkt->max_age; - } - return 1; -} - -int -coap_set_header_max_age(void *packet, uint32_t age) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->max_age = age; - SET_OPTION(coap_pkt, COAP_OPTION_MAX_AGE); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_etag(void *packet, const uint8_t ** etag) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) - return 0; - - *etag = coap_pkt->etag; - return coap_pkt->etag_len; -} - -int -coap_set_header_etag(void *packet, const uint8_t * etag, size_t etag_len) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len); - memcpy(coap_pkt->etag, etag, coap_pkt->etag_len); - - SET_OPTION(coap_pkt, COAP_OPTION_ETAG); - return coap_pkt->etag_len; -} -/*---------------------------------------------------------------------------*/ -/*FIXME support multiple ETags */ -int -coap_get_header_if_match(void *packet, const uint8_t ** etag) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) - return 0; - - *etag = coap_pkt->if_match; - return coap_pkt->if_match_len; -} - -int -coap_set_header_if_match(void *packet, const uint8_t * etag, size_t etag_len) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len); - memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len); - - SET_OPTION(coap_pkt, COAP_OPTION_IF_MATCH); - return coap_pkt->if_match_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_if_none_match(void *packet) -{ - return IS_OPTION((coap_packet_t *) packet, - COAP_OPTION_IF_NONE_MATCH) ? 1 : 0; -} - -int -coap_set_header_if_none_match(void *packet) -{ - SET_OPTION((coap_packet_t *) packet, COAP_OPTION_IF_NONE_MATCH); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_proxy_uri(void *packet, const char **uri) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) - return 0; - - *uri = coap_pkt->proxy_uri; - return coap_pkt->proxy_uri_len; -} - -int -coap_set_header_proxy_uri(void *packet, const char *uri) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - /*TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide er-coap-conf define */ - - coap_pkt->proxy_uri = uri; - coap_pkt->proxy_uri_len = strlen(uri); - - SET_OPTION(coap_pkt, COAP_OPTION_PROXY_URI); - return coap_pkt->proxy_uri_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_uri_host(void *packet, const char **host) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) - return 0; - - *host = coap_pkt->uri_host; - return coap_pkt->uri_host_len; -} - -int -coap_set_header_uri_host(void *packet, const char *host) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->uri_host = host; - coap_pkt->uri_host_len = strlen(host); - - SET_OPTION(coap_pkt, COAP_OPTION_URI_HOST); - return coap_pkt->uri_host_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_uri_path(void *packet, const char **path) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) - return 0; - - *path = coap_pkt->uri_path; - return coap_pkt->uri_path_len; -} - -int -coap_set_header_uri_path(void *packet, const char *path) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - while(path[0] == '/') - ++path; - - coap_pkt->uri_path = path; - coap_pkt->uri_path_len = strlen(path); - - SET_OPTION(coap_pkt, COAP_OPTION_URI_PATH); - return coap_pkt->uri_path_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_uri_query(void *packet, const char **query) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) - return 0; - - *query = coap_pkt->uri_query; - return coap_pkt->uri_query_len; -} - -int -coap_set_header_uri_query(void *packet, const char *query) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - while(query[0] == '?') - ++query; - - coap_pkt->uri_query = query; - coap_pkt->uri_query_len = strlen(query); - - SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); - return coap_pkt->uri_query_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_location_path(void *packet, const char **path) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) - return 0; - - *path = coap_pkt->location_path; - return coap_pkt->location_path_len; -} - -int -coap_set_header_location_path(void *packet, const char *path) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - char *query; - - while(path[0] == '/') - ++path; - - if((query = strchr(path, '?'))) { - coap_set_header_location_query(packet, query + 1); - coap_pkt->location_path_len = query - path; - } else { - coap_pkt->location_path_len = strlen(path); - } - - coap_pkt->location_path = path; - - if(coap_pkt->location_path_len > 0) - SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH); - return coap_pkt->location_path_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_location_query(void *packet, const char **query) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) - return 0; - - *query = coap_pkt->location_query; - return coap_pkt->location_query_len; -} - -int -coap_set_header_location_query(void *packet, const char *query) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - while(query[0] == '?') - ++query; - - coap_pkt->location_query = query; - coap_pkt->location_query_len = strlen(query); - - SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY); - return coap_pkt->location_query_len; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_observe(void *packet, uint32_t * observe) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) - return 0; - - *observe = coap_pkt->observe; - return 1; -} - -int -coap_set_header_observe(void *packet, uint32_t observe) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->observe = observe; - SET_OPTION(coap_pkt, COAP_OPTION_OBSERVE); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_block2(void *packet, uint32_t * num, uint8_t * more, - uint16_t * size, uint32_t * offset) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK2)) - return 0; - - /* pointers may be NULL to get only specific block parameters */ - if(num != NULL) - *num = coap_pkt->block2_num; - if(more != NULL) - *more = coap_pkt->block2_more; - if(size != NULL) - *size = coap_pkt->block2_size; - if(offset != NULL) - *offset = coap_pkt->block2_offset; - - return 1; -} - -int -coap_set_header_block2(void *packet, uint32_t num, uint8_t more, - uint16_t size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(size < 16) - return 0; - if(size > 2048) - return 0; - if(num > 0x0FFFFF) - return 0; - - coap_pkt->block2_num = num; - coap_pkt->block2_more = more ? 1 : 0; - coap_pkt->block2_size = size; - - SET_OPTION(coap_pkt, COAP_OPTION_BLOCK2); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_block1(void *packet, uint32_t * num, uint8_t * more, - uint16_t * size, uint32_t * offset) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK1)) - return 0; - - /* pointers may be NULL to get only specific block parameters */ - if(num != NULL) - *num = coap_pkt->block1_num; - if(more != NULL) - *more = coap_pkt->block1_more; - if(size != NULL) - *size = coap_pkt->block1_size; - if(offset != NULL) - *offset = coap_pkt->block1_offset; - - return 1; -} - -int -coap_set_header_block1(void *packet, uint32_t num, uint8_t more, - uint16_t size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(size < 16) - return 0; - if(size > 2048) - return 0; - if(num > 0x0FFFFF) - return 0; - - coap_pkt->block1_num = num; - coap_pkt->block1_more = more; - coap_pkt->block1_size = size; - - SET_OPTION(coap_pkt, COAP_OPTION_BLOCK1); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_size2(void *packet, uint32_t * size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_SIZE2)) - return 0; - - *size = coap_pkt->size2; - return 1; -} - -int -coap_set_header_size2(void *packet, uint32_t size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->size2 = size; - SET_OPTION(coap_pkt, COAP_OPTION_SIZE2); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_header_size1(void *packet, uint32_t * size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(!IS_OPTION(coap_pkt, COAP_OPTION_SIZE1)) - return 0; - - *size = coap_pkt->size1; - return 1; -} - -int -coap_set_header_size1(void *packet, uint32_t size) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->size1 = size; - SET_OPTION(coap_pkt, COAP_OPTION_SIZE1); - return 1; -} -/*---------------------------------------------------------------------------*/ -int -coap_get_payload(void *packet, const uint8_t ** payload) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - if(coap_pkt->payload) { - *payload = coap_pkt->payload; - return coap_pkt->payload_len; - } else { - *payload = NULL; - return 0; - } -} - -int -coap_set_payload(void *packet, const void *payload, size_t length) -{ - coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - - coap_pkt->payload = (uint8_t *) payload; - coap_pkt->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); - - return coap_pkt->payload_len; -} -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * An implementation of the Constrained Application Protocol (RFC). + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "contiki.h" +#include "contiki-net.h" + +#include "er-coap.h" +#include "er-coap-transactions.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/*---------------------------------------------------------------------------*/ +/*- Variables ---------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +static struct uip_udp_conn *udp_conn = NULL; +static uint16_t current_mid = 0; + +coap_status_t erbium_status_code = NO_ERROR; +char *coap_error_message = ""; +/*---------------------------------------------------------------------------*/ +/*- Local helper functions --------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +static uint16_t +coap_log_2(uint16_t value) +{ + uint16_t result = 0; + + do { + value = value >> 1; + result++; + } while(value); + + return result ? result - 1 : result; +} +/*---------------------------------------------------------------------------*/ +static uint32_t +coap_parse_int_option(uint8_t *bytes, size_t length) +{ + uint32_t var = 0; + int i = 0; + + while(i < length) { + var <<= 8; + var |= bytes[i++]; + } + return var; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +coap_option_nibble(unsigned int value) +{ + if(value < 13) { + return value; + } else if(value <= 0xFF + 13) { + return 13; + } else { + return 14; + } +} +/*---------------------------------------------------------------------------*/ +static size_t +coap_set_option_header(unsigned int delta, size_t length, uint8_t *buffer) +{ + size_t written = 0; + + buffer[0] = coap_option_nibble(delta) << 4 | coap_option_nibble(length); + + /* avoids code duplication without function overhead */ + unsigned int *x = δ + + do { + if(*x > 268) { + buffer[++written] = (*x - 269) >> 8; + buffer[++written] = (*x - 269); + } else if(*x > 12) { + buffer[++written] = (*x - 13); + } + } while(x != &length && (x = &length)); + + PRINTF("WRITTEN %u B opt header\n", 1 + written); + + return ++written; +} +/*---------------------------------------------------------------------------*/ +static size_t +coap_serialize_int_option(unsigned int number, unsigned int current_number, + uint8_t *buffer, uint32_t value) +{ + size_t i = 0; + + if(0xFF000000 & value) { + ++i; + } + if(0xFFFF0000 & value) { + ++i; + } + if(0xFFFFFF00 & value) { + ++i; + } + if(0xFFFFFFFF & value) { + ++i; + } + PRINTF("OPTION %u (delta %u, len %u)\n", number, number - current_number, + i); + + i = coap_set_option_header(number - current_number, i, buffer); + + if(0xFF000000 & value) { + buffer[i++] = (uint8_t)(value >> 24); + } + if(0xFFFF0000 & value) { + buffer[i++] = (uint8_t)(value >> 16); + } + if(0xFFFFFF00 & value) { + buffer[i++] = (uint8_t)(value >> 8); + } + if(0xFFFFFFFF & value) { + buffer[i++] = (uint8_t)(value); + } + return i; +} +/*---------------------------------------------------------------------------*/ +static size_t +coap_serialize_array_option(unsigned int number, unsigned int current_number, + uint8_t *buffer, uint8_t *array, size_t length, + char split_char) +{ + size_t i = 0; + + PRINTF("ARRAY type %u, len %u, full [%.*s]\n", number, length, length, + array); + + if(split_char != '\0') { + int j; + uint8_t *part_start = array; + uint8_t *part_end = NULL; + size_t temp_length; + + for(j = 0; j <= length + 1; ++j) { + PRINTF("STEP %u/%u (%c)\n", j, length, array[j]); + if(array[j] == split_char || j == length) { + part_end = array + j; + temp_length = part_end - part_start; + + i += coap_set_option_header(number - current_number, temp_length, + &buffer[i]); + memcpy(&buffer[i], part_start, temp_length); + i += temp_length; + + PRINTF("OPTION type %u, delta %u, len %u, part [%.*s]\n", number, + number - current_number, i, temp_length, part_start); + + ++j; /* skip the splitter */ + current_number = number; + part_start = array + j; + } + } /* for */ + } else { + i += coap_set_option_header(number - current_number, length, &buffer[i]); + memcpy(&buffer[i], array, length); + i += length; + + PRINTF("OPTION type %u, delta %u, len %u\n", number, + number - current_number, length); + } + + return i; +} +/*---------------------------------------------------------------------------*/ +static void +coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, + size_t option_len, char separator) +{ + /* merge multiple options */ + if(*dst_len > 0) { + /* dst already contains an option: concatenate */ + (*dst)[*dst_len] = separator; + *dst_len += 1; + + /* memmove handles 2-byte option headers */ + memmove((*dst) + (*dst_len), option, option_len); + + *dst_len += option_len; + } else { + /* dst is empty: set to option */ + *dst = (char *)option; + *dst_len = option_len; + } +} +/*---------------------------------------------------------------------------*/ +static int +coap_get_variable(const char *buffer, size_t length, const char *name, + const char **output) +{ + const char *start = NULL; + const char *end = NULL; + const char *value_end = NULL; + size_t name_len = 0; + + /*initialize the output buffer first */ + *output = 0; + + name_len = strlen(name); + end = buffer + length; + + for(start = buffer; start + name_len < end; ++start) { + if((start == buffer || start[-1] == '&') && start[name_len] == '=' + && strncmp(name, start, name_len) == 0) { + + /* Point start to variable value */ + start += name_len + 1; + + /* Point end to the end of the value */ + value_end = (const char *)memchr(start, '&', end - start); + if(value_end == NULL) { + value_end = end; + } + *output = start; + + return value_end - start; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_init_connection(uint16_t port) +{ + /* new connection with remote host */ + udp_conn = udp_new(NULL, 0, NULL); + udp_bind(udp_conn, port); + PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport)); + + /* initialize transaction ID */ + current_mid = random_rand(); +} +/*---------------------------------------------------------------------------*/ +uint16_t +coap_get_mid() +{ + return ++current_mid; +} +/*---------------------------------------------------------------------------*/ +void +coap_init_message(void *packet, coap_message_type_t type, uint8_t code, + uint16_t mid) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + /* Important thing */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + coap_pkt->type = type; + coap_pkt->code = code; + coap_pkt->mid = mid; +} +/*---------------------------------------------------------------------------*/ +size_t +coap_serialize_message(void *packet, uint8_t *buffer) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + uint8_t *option; + unsigned int current_number = 0; + + /* Initialize */ + coap_pkt->buffer = buffer; + coap_pkt->version = 1; + + PRINTF("-Serializing MID %u to %p, ", coap_pkt->mid, coap_pkt->buffer); + + /* set header fields */ + coap_pkt->buffer[0] = 0x00; + coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK + & (coap_pkt->version) << COAP_HEADER_VERSION_POSITION; + coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK + & (coap_pkt->type) << COAP_HEADER_TYPE_POSITION; + coap_pkt->buffer[0] |= COAP_HEADER_TOKEN_LEN_MASK + & (coap_pkt->token_len) << COAP_HEADER_TOKEN_LEN_POSITION; + coap_pkt->buffer[1] = coap_pkt->code; + coap_pkt->buffer[2] = (uint8_t)((coap_pkt->mid) >> 8); + coap_pkt->buffer[3] = (uint8_t)(coap_pkt->mid); + + /* set Token */ + PRINTF("Token (len %u)", coap_pkt->token_len); + option = coap_pkt->buffer + COAP_HEADER_LEN; + for(current_number = 0; current_number < coap_pkt->token_len; + ++current_number) { + PRINTF(" %02X", coap_pkt->token[current_number]); + *option = coap_pkt->token[current_number]; + ++option; + } + PRINTF("-\n"); + + /* Serialize options */ + current_number = 0; + + PRINTF("-Serializing options at %p-\n", option); + + /* The options must be serialized in the order of their number */ + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_IF_MATCH, if_match, "If-Match"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_HOST, uri_host, '\0', + "Uri-Host"); + COAP_SERIALIZE_BYTE_OPTION(COAP_OPTION_ETAG, etag, "ETag"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_IF_NONE_MATCH, + content_format - + coap_pkt-> + content_format /* hack to get a zero field */, + "If-None-Match"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, '/', + "Location-Path"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/', + "Uri-Path"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, + "Content-Format"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&', + "Uri-Query"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query, + '&', "Location-Query"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK2, block2, "Block2"); + COAP_SERIALIZE_BLOCK_OPTION(COAP_OPTION_BLOCK1, block1, "Block1"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE2, size2, "Size2"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_URI, proxy_uri, '\0', + "Proxy-Uri"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_PROXY_SCHEME, proxy_scheme, '\0', + "Proxy-Scheme"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1"); + + PRINTF("-Done serializing at %p----\n", option); + + /* Pack payload */ + if((option - coap_pkt->buffer) <= COAP_MAX_HEADER_SIZE) { + /* Payload marker */ + if(coap_pkt->payload_len) { + *option = 0xFF; + ++option; + } + memmove(option, coap_pkt->payload, coap_pkt->payload_len); + } else { + /* an error occurred: caller must check for !=0 */ + coap_pkt->buffer = NULL; + coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE"; + return 0; + } + + PRINTF("-Done %u B (header len %u, payload len %u)-\n", + coap_pkt->payload_len + option - buffer, option - buffer, + coap_pkt->payload_len); + + PRINTF("Dump [0x%02X %02X %02X %02X %02X %02X %02X %02X]\n", + coap_pkt->buffer[0], + coap_pkt->buffer[1], + coap_pkt->buffer[2], + coap_pkt->buffer[3], + coap_pkt->buffer[4], + coap_pkt->buffer[5], coap_pkt->buffer[6], coap_pkt->buffer[7] + ); + + return (option - buffer) + coap_pkt->payload_len; /* packet length */ +} +/*---------------------------------------------------------------------------*/ +void +coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, + uint16_t length) +{ + /* configure connection to reply to client */ + uip_ipaddr_copy(&udp_conn->ripaddr, addr); + udp_conn->rport = port; + + uip_udp_packet_send(udp_conn, data, length); + PRINTF("-sent UDP datagram (%u)-\n", length); + + /* restore server socket to allow data from any node */ + memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr)); + udp_conn->rport = 0; +} +/*---------------------------------------------------------------------------*/ +coap_status_t +coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + /* initialize packet */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + /* pointer to packet bytes */ + coap_pkt->buffer = data; + + /* parse header fields */ + coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0]) + >> COAP_HEADER_VERSION_POSITION; + coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0]) + >> COAP_HEADER_TYPE_POSITION; + coap_pkt->token_len = + MIN(COAP_TOKEN_LEN, + (COAP_HEADER_TOKEN_LEN_MASK & coap_pkt-> + buffer[0]) >> COAP_HEADER_TOKEN_LEN_POSITION); + coap_pkt->code = coap_pkt->buffer[1]; + coap_pkt->mid = coap_pkt->buffer[2] << 8 | coap_pkt->buffer[3]; + + if(coap_pkt->version != 1) { + coap_error_message = "CoAP version must be 1"; + return BAD_REQUEST_4_00; + } + + uint8_t *current_option = data + COAP_HEADER_LEN; + + memcpy(coap_pkt->token, current_option, coap_pkt->token_len); + PRINTF("Token (len %u) [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->token_len, coap_pkt->token[0], coap_pkt->token[1], + coap_pkt->token[2], coap_pkt->token[3], coap_pkt->token[4], + coap_pkt->token[5], coap_pkt->token[6], coap_pkt->token[7] + ); /*FIXME always prints 8 bytes */ + + /* parse options */ + memset(coap_pkt->options, 0, sizeof(coap_pkt->options)); + current_option += coap_pkt->token_len; + + unsigned int option_number = 0; + unsigned int option_delta = 0; + size_t option_length = 0; + + while(current_option < data + data_len) { + /* payload marker 0xFF, currently only checking for 0xF* because rest is reserved */ + if((current_option[0] & 0xF0) == 0xF0) { + coap_pkt->payload = ++current_option; + coap_pkt->payload_len = data_len - (coap_pkt->payload - data); + + /* also for receiving, the Erbium upper bound is REST_MAX_CHUNK_SIZE */ + if(coap_pkt->payload_len > REST_MAX_CHUNK_SIZE) { + coap_pkt->payload_len = REST_MAX_CHUNK_SIZE; + /* null-terminate payload */ + } + coap_pkt->payload[coap_pkt->payload_len] = '\0'; + + break; + } + + option_delta = current_option[0] >> 4; + option_length = current_option[0] & 0x0F; + ++current_option; + + /* avoids code duplication without function overhead */ + unsigned int *x = &option_delta; + + do { + if(*x == 13) { + *x += current_option[0]; + ++current_option; + } else if(*x == 14) { + *x += 255; + *x += current_option[0] << 8; + ++current_option; + *x += current_option[0]; + ++current_option; + } + } while(x != &option_length && (x = &option_length)); + + option_number += option_delta; + + PRINTF("OPTION %u (delta %u, len %u): ", option_number, option_delta, + option_length); + + SET_OPTION(coap_pkt, option_number); + + switch(option_number) { + case COAP_OPTION_CONTENT_FORMAT: + coap_pkt->content_format = coap_parse_int_option(current_option, + option_length); + PRINTF("Content-Format [%u]\n", coap_pkt->content_format); + break; + case COAP_OPTION_MAX_AGE: + coap_pkt->max_age = coap_parse_int_option(current_option, + option_length); + PRINTF("Max-Age [%lu]\n", coap_pkt->max_age); + break; + case COAP_OPTION_ETAG: + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_length); + memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len); + PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->etag_len, coap_pkt->etag[0], coap_pkt->etag[1], + coap_pkt->etag[2], coap_pkt->etag[3], coap_pkt->etag[4], + coap_pkt->etag[5], coap_pkt->etag[6], coap_pkt->etag[7] + ); /*FIXME always prints 8 bytes */ + break; + case COAP_OPTION_ACCEPT: + coap_pkt->accept = coap_parse_int_option(current_option, option_length); + PRINTF("Accept [%u]\n", coap_pkt->accept); + break; + case COAP_OPTION_IF_MATCH: + /* TODO support multiple ETags */ + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_length); + memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len); + PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + coap_pkt->if_match_len, coap_pkt->if_match[0], + coap_pkt->if_match[1], coap_pkt->if_match[2], + coap_pkt->if_match[3], coap_pkt->if_match[4], + coap_pkt->if_match[5], coap_pkt->if_match[6], + coap_pkt->if_match[7] + ); /* FIXME always prints 8 bytes */ + break; + case COAP_OPTION_IF_NONE_MATCH: + coap_pkt->if_none_match = 1; + PRINTF("If-None-Match\n"); + break; + + case COAP_OPTION_PROXY_URI: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_uri = (char *)current_option; + coap_pkt->proxy_uri_len = option_length; +#endif + PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, + coap_pkt->proxy_uri); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + case COAP_OPTION_PROXY_SCHEME: +#if COAP_PROXY_OPTION_PROCESSING + coap_pkt->proxy_scheme = (char *)current_option; + coap_pkt->proxy_scheme_len = option_length; +#endif + PRINTF("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", + coap_pkt->proxy_scheme_len, coap_pkt->proxy_scheme); + coap_error_message = "This is a constrained server (Contiki)"; + return PROXYING_NOT_SUPPORTED_5_05; + break; + + case COAP_OPTION_URI_HOST: + coap_pkt->uri_host = (char *)current_option; + coap_pkt->uri_host_len = option_length; + PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); + break; + case COAP_OPTION_URI_PORT: + coap_pkt->uri_port = coap_parse_int_option(current_option, + option_length); + PRINTF("Uri-Port [%u]\n", coap_pkt->uri_port); + break; + case COAP_OPTION_URI_PATH: + /* 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_path), + &(coap_pkt->uri_path_len), current_option, + option_length, '/'); + PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->uri_path); + break; + 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((char **)&(coap_pkt->uri_query), + &(coap_pkt->uri_query_len), current_option, + option_length, '&'); + PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, + coap_pkt->uri_query); + break; + + case COAP_OPTION_LOCATION_PATH: + /* 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->location_path), + &(coap_pkt->location_path_len), current_option, + option_length, '/'); + PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, + coap_pkt->location_path); + break; + case COAP_OPTION_LOCATION_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((char **)&(coap_pkt->location_query), + &(coap_pkt->location_query_len), current_option, + option_length, '&'); + PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, + coap_pkt->location_query); + break; + + case COAP_OPTION_OBSERVE: + coap_pkt->observe = coap_parse_int_option(current_option, + option_length); + PRINTF("Observe [%lu]\n", coap_pkt->observe); + break; + case COAP_OPTION_BLOCK2: + coap_pkt->block2_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block2_more = (coap_pkt->block2_num & 0x08) >> 3; + coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F) + << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_num >>= 4; + PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, + coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); + break; + case COAP_OPTION_BLOCK1: + coap_pkt->block1_num = coap_parse_int_option(current_option, + option_length); + coap_pkt->block1_more = (coap_pkt->block1_num & 0x08) >> 3; + coap_pkt->block1_size = 16 << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_offset = (coap_pkt->block1_num & ~0x0000000F) + << (coap_pkt->block1_num & 0x07); + coap_pkt->block1_num >>= 4; + PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, + coap_pkt->block1_more ? "+" : "", coap_pkt->block1_size); + break; + case COAP_OPTION_SIZE2: + coap_pkt->size2 = coap_parse_int_option(current_option, option_length); + PRINTF("Size2 [%lu]\n", coap_pkt->size2); + break; + case COAP_OPTION_SIZE1: + coap_pkt->size1 = coap_parse_int_option(current_option, option_length); + PRINTF("Size1 [%lu]\n", coap_pkt->size1); + break; + default: + PRINTF("unknown (%u)\n", option_number); + /* check if critical (odd) */ + if(option_number & 1) { + coap_error_message = "Unsupported critical option"; + return BAD_OPTION_4_02; + } + } + + current_option += option_length; + } /* for */ + PRINTF("-Done parsing-------\n"); + + return NO_ERROR; +} +/*---------------------------------------------------------------------------*/ +/*- REST Engine API ---------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +int +coap_get_query_variable(void *packet, const char *name, const char **output) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len, + name, output); + } + return 0; +} +int +coap_get_post_variable(void *packet, const char *name, const char **output) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(coap_pkt->payload_len) { + return coap_get_variable((const char *)coap_pkt->payload, + coap_pkt->payload_len, name, output); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +int +coap_set_status_code(void *packet, unsigned int code) +{ + if(code <= 0xFF) { + ((coap_packet_t *)packet)->code = (uint8_t)code; + return 1; + } else { + return 0; + } +} +/*---------------------------------------------------------------------------*/ +int +coap_set_token(void *packet, const uint8_t *token, size_t token_len) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len); + memcpy(coap_pkt->token, token, coap_pkt->token_len); + + return coap_pkt->token_len; +} +/*---------------------------------------------------------------------------*/ +/*- CoAP REST Implementation API --------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +int +coap_get_header_content_format(void *packet, unsigned int *format) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT)) { + return 0; + } + *format = coap_pkt->content_format; + return 1; +} +int +coap_set_header_content_format(void *packet, unsigned int format) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->content_format = (coap_content_format_t)format; + SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_accept(void *packet, unsigned int *accept) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) { + return 0; + } + *accept = coap_pkt->accept; + return 1; +} +int +coap_set_header_accept(void *packet, unsigned int accept) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->accept = (coap_content_format_t)accept; + SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_max_age(void *packet, uint32_t *age) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { + *age = COAP_DEFAULT_MAX_AGE; + } else { + *age = coap_pkt->max_age; + } return 1; +} +int +coap_set_header_max_age(void *packet, uint32_t age) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->max_age = age; + SET_OPTION(coap_pkt, COAP_OPTION_MAX_AGE); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_etag(void *packet, const uint8_t **etag) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { + return 0; + } + *etag = coap_pkt->etag; + return coap_pkt->etag_len; +} +int +coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len); + memcpy(coap_pkt->etag, etag, coap_pkt->etag_len); + + SET_OPTION(coap_pkt, COAP_OPTION_ETAG); + return coap_pkt->etag_len; +} +/*---------------------------------------------------------------------------*/ +/*FIXME support multiple ETags */ +int +coap_get_header_if_match(void *packet, const uint8_t **etag) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) { + return 0; + } + *etag = coap_pkt->if_match; + return coap_pkt->if_match_len; +} +int +coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len); + memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len); + + SET_OPTION(coap_pkt, COAP_OPTION_IF_MATCH); + return coap_pkt->if_match_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_if_none_match(void *packet) +{ + return IS_OPTION((coap_packet_t *)packet, + COAP_OPTION_IF_NONE_MATCH) ? 1 : 0; +} +int +coap_set_header_if_none_match(void *packet) +{ + SET_OPTION((coap_packet_t *)packet, COAP_OPTION_IF_NONE_MATCH); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_proxy_uri(void *packet, const char **uri) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) { + return 0; + } + *uri = coap_pkt->proxy_uri; + return coap_pkt->proxy_uri_len; +} +int +coap_set_header_proxy_uri(void *packet, const char *uri) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + /*TODO Provide alternative that sets Proxy-Scheme and Uri-* options and provide er-coap-conf define */ + + coap_pkt->proxy_uri = uri; + coap_pkt->proxy_uri_len = strlen(uri); + + SET_OPTION(coap_pkt, COAP_OPTION_PROXY_URI); + return coap_pkt->proxy_uri_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_uri_host(void *packet, const char **host) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) { + return 0; + } + *host = coap_pkt->uri_host; + return coap_pkt->uri_host_len; +} +int +coap_set_header_uri_host(void *packet, const char *host) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->uri_host = host; + coap_pkt->uri_host_len = strlen(host); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_HOST); + return coap_pkt->uri_host_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_uri_path(void *packet, const char **path) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) { + return 0; + } + *path = coap_pkt->uri_path; + return coap_pkt->uri_path_len; +} +int +coap_set_header_uri_path(void *packet, const char *path) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + while(path[0] == '/') + ++path; + + coap_pkt->uri_path = path; + coap_pkt->uri_path_len = strlen(path); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_PATH); + return coap_pkt->uri_path_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_uri_query(void *packet, const char **query) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + return 0; + } + *query = coap_pkt->uri_query; + return coap_pkt->uri_query_len; +} +int +coap_set_header_uri_query(void *packet, const char *query) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + while(query[0] == '?') + ++query; + + coap_pkt->uri_query = query; + coap_pkt->uri_query_len = strlen(query); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); + return coap_pkt->uri_query_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_location_path(void *packet, const char **path) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) { + return 0; + } + *path = coap_pkt->location_path; + return coap_pkt->location_path_len; +} +int +coap_set_header_location_path(void *packet, const char *path) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + char *query; + + while(path[0] == '/') + ++path; + + if((query = strchr(path, '?'))) { + coap_set_header_location_query(packet, query + 1); + coap_pkt->location_path_len = query - path; + } else { + coap_pkt->location_path_len = strlen(path); + } coap_pkt->location_path = path; + + if(coap_pkt->location_path_len > 0) { + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH); + } + return coap_pkt->location_path_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_location_query(void *packet, const char **query) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) { + return 0; + } + *query = coap_pkt->location_query; + return coap_pkt->location_query_len; +} +int +coap_set_header_location_query(void *packet, const char *query) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + while(query[0] == '?') + ++query; + + coap_pkt->location_query = query; + coap_pkt->location_query_len = strlen(query); + + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY); + return coap_pkt->location_query_len; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_observe(void *packet, uint32_t *observe) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { + return 0; + } + *observe = coap_pkt->observe; + return 1; +} +int +coap_set_header_observe(void *packet, uint32_t observe) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->observe = observe; + SET_OPTION(coap_pkt, COAP_OPTION_OBSERVE); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK2)) { + return 0; + } + /* pointers may be NULL to get only specific block parameters */ + if(num != NULL) { + *num = coap_pkt->block2_num; + } + if(more != NULL) { + *more = coap_pkt->block2_more; + } + if(size != NULL) { + *size = coap_pkt->block2_size; + } + if(offset != NULL) { + *offset = coap_pkt->block2_offset; + } + return 1; +} +int +coap_set_header_block2(void *packet, uint32_t num, uint8_t more, + uint16_t size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(size < 16) { + return 0; + } + if(size > 2048) { + return 0; + } + if(num > 0x0FFFFF) { + return 0; + } + coap_pkt->block2_num = num; + coap_pkt->block2_more = more ? 1 : 0; + coap_pkt->block2_size = size; + + SET_OPTION(coap_pkt, COAP_OPTION_BLOCK2); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_BLOCK1)) { + return 0; + } + /* pointers may be NULL to get only specific block parameters */ + if(num != NULL) { + *num = coap_pkt->block1_num; + } + if(more != NULL) { + *more = coap_pkt->block1_more; + } + if(size != NULL) { + *size = coap_pkt->block1_size; + } + if(offset != NULL) { + *offset = coap_pkt->block1_offset; + } + return 1; +} +int +coap_set_header_block1(void *packet, uint32_t num, uint8_t more, + uint16_t size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(size < 16) { + return 0; + } + if(size > 2048) { + return 0; + } + if(num > 0x0FFFFF) { + return 0; + } + coap_pkt->block1_num = num; + coap_pkt->block1_more = more; + coap_pkt->block1_size = size; + + SET_OPTION(coap_pkt, COAP_OPTION_BLOCK1); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_size2(void *packet, uint32_t *size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_SIZE2)) { + return 0; + } + *size = coap_pkt->size2; + return 1; +} +int +coap_set_header_size2(void *packet, uint32_t size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->size2 = size; + SET_OPTION(coap_pkt, COAP_OPTION_SIZE2); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_header_size1(void *packet, uint32_t *size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(!IS_OPTION(coap_pkt, COAP_OPTION_SIZE1)) { + return 0; + } + *size = coap_pkt->size1; + return 1; +} +int +coap_set_header_size1(void *packet, uint32_t size) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->size1 = size; + SET_OPTION(coap_pkt, COAP_OPTION_SIZE1); + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_get_payload(void *packet, const uint8_t **payload) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + if(coap_pkt->payload) { + *payload = coap_pkt->payload; + return coap_pkt->payload_len; + } else { + *payload = NULL; + return 0; + } +} +int +coap_set_payload(void *packet, const void *payload, size_t length) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->payload = (uint8_t *)payload; + coap_pkt->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); + + return coap_pkt->payload_len; +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/er-coap/er-coap.h b/apps/er-coap/er-coap.h old mode 100755 new mode 100644 index 573201b7d..11fcbebb0 --- a/apps/er-coap/er-coap.h +++ b/apps/er-coap/er-coap.h @@ -1,257 +1,256 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * An implementation of the Constrained Application Protocol (RFC). - * \author - * Matthias Kovatsch - */ - -#ifndef ER_COAP_H_ -#define ER_COAP_H_ - -#include /* for size_t */ -#include "net/uip.h" -#include "er-coap-constants.h" -#include "er-coap-conf.h" - -/* sanity check for configured values */ -#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE) -#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_IPH_LEN - UIP_UDPH_LEN) -#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE" -#endif - -/* use Erbium CoAP for the REST Engine. Must come before include of rest-engine.h. */ -#define REST coap_rest_implementation -#include "rest-engine.h" - -/* direct access into the buffer */ -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#if UIP_CONF_IPV6 -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) -#else -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN]) -#endif - -/* bitmap for set options */ -enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 }; - -#define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE)) -#define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE))) - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - -/* parsed message struct */ -typedef struct { - uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */ - - uint8_t version; - coap_message_type_t type; - uint8_t code; - uint16_t mid; - - uint8_t token_len; - uint8_t token[COAP_TOKEN_LEN]; - - 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 */ - uint32_t max_age; - uint8_t etag_len; - uint8_t etag[COAP_ETAG_LEN]; - size_t proxy_uri_len; - const char *proxy_uri; - size_t proxy_scheme_len; - const char *proxy_scheme; - size_t uri_host_len; - const char *uri_host; - size_t location_path_len; - const char *location_path; - uint16_t uri_port; - size_t location_query_len; - const char *location_query; - size_t uri_path_len; - const char *uri_path; - int32_t observe; - coap_content_format_t accept; - uint8_t if_match_len; - uint8_t if_match[COAP_ETAG_LEN]; - uint32_t block2_num; - uint8_t block2_more; - uint16_t block2_size; - uint32_t block2_offset; - uint32_t block1_num; - uint8_t block1_more; - uint16_t block1_size; - uint32_t block1_offset; - uint32_t size2; - uint32_t size1; - size_t uri_query_len; - const char *uri_query; - uint8_t if_none_match; - - uint16_t payload_len; - uint8_t *payload; - -} coap_packet_t; - -/* option format serialization */ -#define COAP_SERIALIZE_INT_OPTION(number, field, text) \ - if (IS_OPTION(coap_pkt, number)) { \ - PRINTF(text" [%u]\n", coap_pkt->field); \ - option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \ - current_number = number; \ - } -#define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \ - if (IS_OPTION(coap_pkt, number)) { \ - PRINTF(text" %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->field##_len, \ - coap_pkt->field[0], \ - coap_pkt->field[1], \ - coap_pkt->field[2], \ - coap_pkt->field[3], \ - coap_pkt->field[4], \ - coap_pkt->field[5], \ - coap_pkt->field[6], \ - coap_pkt->field[7] \ - ); /* FIXME always prints 8 bytes */ \ - option += coap_serialize_array_option(number, current_number, option, coap_pkt->field, coap_pkt->field##_len, '\0'); \ - current_number = number; \ - } -#define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \ - if (IS_OPTION(coap_pkt, number)) { \ - PRINTF(text" [%.*s]\n", 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); \ - current_number = number; \ - } -#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \ - 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); \ - uint32_t block = coap_pkt->field##_num << 4; \ - if (coap_pkt->field##_more) block |= 0x8; \ - block |= 0xF & coap_log_2(coap_pkt->field##_size/16); \ - PRINTF(text" encoded: 0x%lX\n", block); \ - option += coap_serialize_int_option(number, current_number, option, block); \ - current_number = number; \ - } - -/* to store error code and human-readable payload */ -extern coap_status_t erbium_status_code; -extern char *coap_error_message; - -void coap_init_connection(uint16_t port); -uint16_t coap_get_mid(void); - -void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, - uint16_t mid); -size_t coap_serialize_message(void *packet, uint8_t * buffer); -void coap_send_message(uip_ipaddr_t * addr, uint16_t port, uint8_t * data, - uint16_t length); -coap_status_t coap_parse_message(void *request, uint8_t * data, - uint16_t data_len); - -int coap_get_query_variable(void *packet, const char *name, - const char **output); -int coap_get_post_variable(void *packet, const char *name, - const char **output); - -/*---------------------------------------------------------------------------*/ - -int coap_set_status_code(void *packet, unsigned int code); - -int coap_set_token(void *packet, const uint8_t * token, size_t token_len); - -int coap_get_header_content_format(void *packet, unsigned int *format); -int coap_set_header_content_format(void *packet, unsigned int format); - -int coap_get_header_accept(void *packet, unsigned int *accept); -int coap_set_header_accept(void *packet, unsigned int accept); - -int coap_get_header_max_age(void *packet, uint32_t * age); -int coap_set_header_max_age(void *packet, uint32_t age); - -int coap_get_header_etag(void *packet, const uint8_t ** etag); -int coap_set_header_etag(void *packet, const uint8_t * etag, size_t etag_len); - -int coap_get_header_if_match(void *packet, const uint8_t ** etag); -int coap_set_header_if_match(void *packet, const uint8_t * etag, - size_t etag_len); - -int coap_get_header_if_none_match(void *packet); -int coap_set_header_if_none_match(void *packet); - -int coap_get_header_proxy_uri(void *packet, const char **uri); /* in-place string might not be 0-terminated. */ -int coap_set_header_proxy_uri(void *packet, const char *uri); - -int coap_get_header_proxy_scheme(void *packet, const char **scheme); /* in-place string might not be 0-terminated. */ -int coap_set_header_proxy_scheme(void *packet, const char *scheme); - -int coap_get_header_uri_host(void *packet, const char **host); /* in-place string might not be 0-terminated. */ -int coap_set_header_uri_host(void *packet, const char *host); - -int coap_get_header_uri_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ -int coap_set_header_uri_path(void *packet, const char *path); - -int coap_get_header_uri_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ -int coap_set_header_uri_query(void *packet, const char *query); - -int coap_get_header_location_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ -int coap_set_header_location_path(void *packet, const char *path); /* also splits optional query into Location-Query option. */ - -int coap_get_header_location_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ -int coap_set_header_location_query(void *packet, const char *query); - -int coap_get_header_observe(void *packet, uint32_t * observe); -int coap_set_header_observe(void *packet, uint32_t observe); - -int coap_get_header_block2(void *packet, uint32_t * num, uint8_t * more, - uint16_t * size, uint32_t * offset); -int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, - uint16_t size); - -int coap_get_header_block1(void *packet, uint32_t * num, uint8_t * more, - uint16_t * size, uint32_t * offset); -int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, - uint16_t size); - -int coap_get_header_size2(void *packet, uint32_t * size); -int coap_set_header_size2(void *packet, uint32_t size); - -int coap_get_header_size1(void *packet, uint32_t * size); -int coap_set_header_size1(void *packet, uint32_t size); - -int coap_get_payload(void *packet, const uint8_t ** payload); -int coap_set_payload(void *packet, const void *payload, size_t length); - -#endif /* ER_COAP_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * An implementation of the Constrained Application Protocol (RFC). + * \author + * Matthias Kovatsch + */ + +#ifndef ER_COAP_H_ +#define ER_COAP_H_ + +#include /* for size_t */ +#include "contiki-net.h" +#include "er-coap-constants.h" +#include "er-coap-conf.h" + +/* sanity check for configured values */ +#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE) +#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_IPH_LEN - UIP_UDPH_LEN) +#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE" +#endif + +/* use Erbium CoAP for the REST Engine. Must come before include of rest-engine.h. */ +#define REST coap_rest_implementation +#include "rest-engine.h" + +/* direct access into the buffer */ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#if UIP_CONF_IPV6 +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#else +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN]) +#endif + +/* bitmap for set options */ +enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 }; + +#define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE)) +#define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE))) + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +/* parsed message struct */ +typedef struct { + uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */ + + uint8_t version; + coap_message_type_t type; + uint8_t code; + uint16_t mid; + + uint8_t token_len; + uint8_t token[COAP_TOKEN_LEN]; + + 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 */ + uint32_t max_age; + uint8_t etag_len; + uint8_t etag[COAP_ETAG_LEN]; + size_t proxy_uri_len; + const char *proxy_uri; + size_t proxy_scheme_len; + const char *proxy_scheme; + size_t uri_host_len; + const char *uri_host; + size_t location_path_len; + const char *location_path; + uint16_t uri_port; + size_t location_query_len; + const char *location_query; + size_t uri_path_len; + const char *uri_path; + int32_t observe; + coap_content_format_t accept; + uint8_t if_match_len; + uint8_t if_match[COAP_ETAG_LEN]; + uint32_t block2_num; + uint8_t block2_more; + uint16_t block2_size; + uint32_t block2_offset; + uint32_t block1_num; + uint8_t block1_more; + uint16_t block1_size; + uint32_t block1_offset; + uint32_t size2; + uint32_t size1; + size_t uri_query_len; + const char *uri_query; + uint8_t if_none_match; + + uint16_t payload_len; + uint8_t *payload; +} coap_packet_t; + +/* option format serialization */ +#define COAP_SERIALIZE_INT_OPTION(number, field, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " [%u]\n", coap_pkt->field); \ + option += coap_serialize_int_option(number, current_number, option, coap_pkt->field); \ + current_number = number; \ + } +#define COAP_SERIALIZE_BYTE_OPTION(number, field, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->field##_len, \ + coap_pkt->field[0], \ + coap_pkt->field[1], \ + coap_pkt->field[2], \ + coap_pkt->field[3], \ + coap_pkt->field[4], \ + coap_pkt->field[5], \ + coap_pkt->field[6], \ + coap_pkt->field[7] \ + ); /* FIXME always prints 8 bytes */ \ + option += coap_serialize_array_option(number, current_number, option, coap_pkt->field, coap_pkt->field##_len, '\0'); \ + current_number = number; \ + } +#define COAP_SERIALIZE_STRING_OPTION(number, field, splitter, text) \ + if(IS_OPTION(coap_pkt, number)) { \ + PRINTF(text " [%.*s]\n", 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); \ + current_number = number; \ + } +#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \ + 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); \ + uint32_t block = coap_pkt->field##_num << 4; \ + if(coap_pkt->field##_more) { block |= 0x8; } \ + block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \ + PRINTF(text " encoded: 0x%lX\n", block); \ + option += coap_serialize_int_option(number, current_number, option, block); \ + current_number = number; \ + } + +/* to store error code and human-readable payload */ +extern coap_status_t erbium_status_code; +extern char *coap_error_message; + +void coap_init_connection(uint16_t port); +uint16_t coap_get_mid(void); + +void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, + uint16_t mid); +size_t coap_serialize_message(void *packet, uint8_t *buffer); +void coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, + uint16_t length); +coap_status_t coap_parse_message(void *request, uint8_t *data, + uint16_t data_len); + +int coap_get_query_variable(void *packet, const char *name, + const char **output); +int coap_get_post_variable(void *packet, const char *name, + const char **output); + +/*---------------------------------------------------------------------------*/ + +int coap_set_status_code(void *packet, unsigned int code); + +int coap_set_token(void *packet, const uint8_t *token, size_t token_len); + +int coap_get_header_content_format(void *packet, unsigned int *format); +int coap_set_header_content_format(void *packet, unsigned int format); + +int coap_get_header_accept(void *packet, unsigned int *accept); +int coap_set_header_accept(void *packet, unsigned int accept); + +int coap_get_header_max_age(void *packet, uint32_t *age); +int coap_set_header_max_age(void *packet, uint32_t age); + +int coap_get_header_etag(void *packet, const uint8_t **etag); +int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len); + +int coap_get_header_if_match(void *packet, const uint8_t **etag); +int coap_set_header_if_match(void *packet, const uint8_t *etag, + size_t etag_len); + +int coap_get_header_if_none_match(void *packet); +int coap_set_header_if_none_match(void *packet); + +int coap_get_header_proxy_uri(void *packet, const char **uri); /* in-place string might not be 0-terminated. */ +int coap_set_header_proxy_uri(void *packet, const char *uri); + +int coap_get_header_proxy_scheme(void *packet, const char **scheme); /* in-place string might not be 0-terminated. */ +int coap_set_header_proxy_scheme(void *packet, const char *scheme); + +int coap_get_header_uri_host(void *packet, const char **host); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_host(void *packet, const char *host); + +int coap_get_header_uri_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_path(void *packet, const char *path); + +int coap_get_header_uri_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ +int coap_set_header_uri_query(void *packet, const char *query); + +int coap_get_header_location_path(void *packet, const char **path); /* in-place string might not be 0-terminated. */ +int coap_set_header_location_path(void *packet, const char *path); /* also splits optional query into Location-Query option. */ + +int coap_get_header_location_query(void *packet, const char **query); /* in-place string might not be 0-terminated. */ +int coap_set_header_location_query(void *packet, const char *query); + +int coap_get_header_observe(void *packet, uint32_t *observe); +int coap_set_header_observe(void *packet, uint32_t observe); + +int coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset); +int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, + uint16_t size); + +int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, + uint16_t *size, uint32_t *offset); +int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, + uint16_t size); + +int coap_get_header_size2(void *packet, uint32_t *size); +int coap_set_header_size2(void *packet, uint32_t size); + +int coap_get_header_size1(void *packet, uint32_t *size); +int coap_set_header_size1(void *packet, uint32_t size); + +int coap_get_payload(void *packet, const uint8_t **payload); +int coap_set_payload(void *packet, const void *payload, size_t length); + +#endif /* ER_COAP_H_ */ diff --git a/apps/rest-engine/rest-constants.h b/apps/rest-engine/rest-constants.h old mode 100755 new mode 100644 index d05e54bc2..addc0970b --- a/apps/rest-engine/rest-constants.h +++ b/apps/rest-engine/rest-constants.h @@ -1,118 +1,118 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Constants for the REST Engine (Erbium). - * \author - * Matthias Kovatsch - */ - -#ifndef REST_CONSTANTS_H_ -#define REST_CONSTANTS_H_ - -/** - * Generic status codes that are mapped to either HTTP or CoAP codes. - */ -struct rest_implementation_status { - const unsigned int OK; /* CONTENT_2_05, OK_200 */ - const unsigned int CREATED; /* CREATED_2_01, CREATED_201 */ - const unsigned int CHANGED; /* CHANGED_2_04, NO_CONTENT_204 */ - const unsigned int DELETED; /* DELETED_2_02, NO_CONTENT_204 */ - const unsigned int NOT_MODIFIED; /* VALID_2_03, NOT_MODIFIED_304 */ - - const unsigned int BAD_REQUEST; /* BAD_REQUEST_4_00, BAD_REQUEST_400 */ - const unsigned int UNAUTHORIZED; /* UNAUTHORIZED_4_01, UNAUTHORIZED_401 */ - const unsigned int BAD_OPTION; /* BAD_OPTION_4_02, BAD_REQUEST_400 */ - const unsigned int FORBIDDEN; /* FORBIDDEN_4_03, FORBIDDEN_403 */ - const unsigned int NOT_FOUND; /* NOT_FOUND_4_04, NOT_FOUND_404 */ - const unsigned int METHOD_NOT_ALLOWED; /* METHOD_NOT_ALLOWED_4_05, METHOD_NOT_ALLOWED_405 */ - const unsigned int NOT_ACCEPTABLE; /* NOT_ACCEPTABLE_4_06, NOT_ACCEPTABLE_406 */ - const unsigned int REQUEST_ENTITY_TOO_LARGE; /* REQUEST_ENTITY_TOO_LARGE_4_13, REQUEST_ENTITY_TOO_LARGE_413 */ - const unsigned int UNSUPPORTED_MEDIA_TYPE; /* UNSUPPORTED_MEDIA_TYPE_4_15, UNSUPPORTED_MEDIA_TYPE_415 */ - - const unsigned int INTERNAL_SERVER_ERROR; /* INTERNAL_SERVER_ERROR_5_00, INTERNAL_SERVER_ERROR_500 */ - const unsigned int NOT_IMPLEMENTED; /* NOT_IMPLEMENTED_5_01, NOT_IMPLEMENTED_501 */ - const unsigned int BAD_GATEWAY; /* BAD_GATEWAY_5_02, BAD_GATEWAY_502 */ - const unsigned int SERVICE_UNAVAILABLE; /* SERVICE_UNAVAILABLE_5_03, SERVICE_UNAVAILABLE_503 */ - const unsigned int GATEWAY_TIMEOUT; /* GATEWAY_TIMEOUT_5_04, GATEWAY_TIMEOUT_504 */ - const unsigned int PROXYING_NOT_SUPPORTED; /* PROXYING_NOT_SUPPORTED_5_05, INTERNAL_SERVER_ERROR_500 */ -}; - -/** - * List of Content-Formats which are Internet Media Types plus encoding. - * TODO This should be a constant enum taken from CoAP for both CoAP and HTTP. - */ -struct rest_implementation_type { - unsigned int TEXT_PLAIN; - unsigned int TEXT_XML; - unsigned int TEXT_CSV; - unsigned int TEXT_HTML; - unsigned int IMAGE_GIF; - unsigned int IMAGE_JPEG; - unsigned int IMAGE_PNG; - unsigned int IMAGE_TIFF; - unsigned int AUDIO_RAW; - unsigned int VIDEO_RAW; - unsigned int APPLICATION_LINK_FORMAT; - unsigned int APPLICATION_XML; - unsigned int APPLICATION_OCTET_STREAM; - unsigned int APPLICATION_RDF_XML; - unsigned int APPLICATION_SOAP_XML; - unsigned int APPLICATION_ATOM_XML; - unsigned int APPLICATION_XMPP_XML; - unsigned int APPLICATION_EXI; - unsigned int APPLICATION_FASTINFOSET; - unsigned int APPLICATION_SOAP_FASTINFOSET; - unsigned int APPLICATION_JSON; - unsigned int APPLICATION_X_OBIX_BINARY; -}; - -/** - * Resource flags for allowed methods and special functionalities. - */ -typedef enum { - NO_FLAGS = 0, - - /* methods to handle */ - METHOD_GET = (1 << 0), - METHOD_POST = (1 << 1), - METHOD_PUT = (1 << 2), - METHOD_DELETE = (1 << 3), - - /* special flags */ - HAS_SUB_RESOURCES = (1 << 4), - IS_SEPARATE = (1 << 5), - IS_OBSERVABLE = (1 << 6), - IS_PERIODIC = (1 << 7) -} rest_resource_flags_t; - -#endif /* REST_CONSTANTS_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Constants for the REST Engine (Erbium). + * \author + * Matthias Kovatsch + */ + +#ifndef REST_CONSTANTS_H_ +#define REST_CONSTANTS_H_ + +/** + * Generic status codes that are mapped to either HTTP or CoAP codes. + */ +struct rest_implementation_status { + const unsigned int OK; /* CONTENT_2_05, OK_200 */ + const unsigned int CREATED; /* CREATED_2_01, CREATED_201 */ + const unsigned int CHANGED; /* CHANGED_2_04, NO_CONTENT_204 */ + const unsigned int DELETED; /* DELETED_2_02, NO_CONTENT_204 */ + const unsigned int NOT_MODIFIED; /* VALID_2_03, NOT_MODIFIED_304 */ + + const unsigned int BAD_REQUEST; /* BAD_REQUEST_4_00, BAD_REQUEST_400 */ + const unsigned int UNAUTHORIZED; /* UNAUTHORIZED_4_01, UNAUTHORIZED_401 */ + const unsigned int BAD_OPTION; /* BAD_OPTION_4_02, BAD_REQUEST_400 */ + const unsigned int FORBIDDEN; /* FORBIDDEN_4_03, FORBIDDEN_403 */ + const unsigned int NOT_FOUND; /* NOT_FOUND_4_04, NOT_FOUND_404 */ + const unsigned int METHOD_NOT_ALLOWED; /* METHOD_NOT_ALLOWED_4_05, METHOD_NOT_ALLOWED_405 */ + const unsigned int NOT_ACCEPTABLE; /* NOT_ACCEPTABLE_4_06, NOT_ACCEPTABLE_406 */ + const unsigned int REQUEST_ENTITY_TOO_LARGE; /* REQUEST_ENTITY_TOO_LARGE_4_13, REQUEST_ENTITY_TOO_LARGE_413 */ + const unsigned int UNSUPPORTED_MEDIA_TYPE; /* UNSUPPORTED_MEDIA_TYPE_4_15, UNSUPPORTED_MEDIA_TYPE_415 */ + + const unsigned int INTERNAL_SERVER_ERROR; /* INTERNAL_SERVER_ERROR_5_00, INTERNAL_SERVER_ERROR_500 */ + const unsigned int NOT_IMPLEMENTED; /* NOT_IMPLEMENTED_5_01, NOT_IMPLEMENTED_501 */ + const unsigned int BAD_GATEWAY; /* BAD_GATEWAY_5_02, BAD_GATEWAY_502 */ + const unsigned int SERVICE_UNAVAILABLE; /* SERVICE_UNAVAILABLE_5_03, SERVICE_UNAVAILABLE_503 */ + const unsigned int GATEWAY_TIMEOUT; /* GATEWAY_TIMEOUT_5_04, GATEWAY_TIMEOUT_504 */ + const unsigned int PROXYING_NOT_SUPPORTED; /* PROXYING_NOT_SUPPORTED_5_05, INTERNAL_SERVER_ERROR_500 */ +}; + +/** + * List of Content-Formats which are Internet Media Types plus encoding. + * TODO This should be a constant enum taken from CoAP for both CoAP and HTTP. + */ +struct rest_implementation_type { + unsigned int TEXT_PLAIN; + unsigned int TEXT_XML; + unsigned int TEXT_CSV; + unsigned int TEXT_HTML; + unsigned int IMAGE_GIF; + unsigned int IMAGE_JPEG; + unsigned int IMAGE_PNG; + unsigned int IMAGE_TIFF; + unsigned int AUDIO_RAW; + unsigned int VIDEO_RAW; + unsigned int APPLICATION_LINK_FORMAT; + unsigned int APPLICATION_XML; + unsigned int APPLICATION_OCTET_STREAM; + unsigned int APPLICATION_RDF_XML; + unsigned int APPLICATION_SOAP_XML; + unsigned int APPLICATION_ATOM_XML; + unsigned int APPLICATION_XMPP_XML; + unsigned int APPLICATION_EXI; + unsigned int APPLICATION_FASTINFOSET; + unsigned int APPLICATION_SOAP_FASTINFOSET; + unsigned int APPLICATION_JSON; + unsigned int APPLICATION_X_OBIX_BINARY; +}; + +/** + * Resource flags for allowed methods and special functionalities. + */ +typedef enum { + NO_FLAGS = 0, + + /* methods to handle */ + METHOD_GET = (1 << 0), + METHOD_POST = (1 << 1), + METHOD_PUT = (1 << 2), + METHOD_DELETE = (1 << 3), + + /* special flags */ + HAS_SUB_RESOURCES = (1 << 4), + IS_SEPARATE = (1 << 5), + IS_OBSERVABLE = (1 << 6), + IS_PERIODIC = (1 << 7) +} rest_resource_flags_t; + +#endif /* REST_CONSTANTS_H_ */ diff --git a/apps/rest-engine/rest-engine.c b/apps/rest-engine/rest-engine.c old mode 100755 new mode 100644 index 12153dfe1..7eb686d4d --- a/apps/rest-engine/rest-engine.c +++ b/apps/rest-engine/rest-engine.c @@ -1,212 +1,218 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * An abstraction layer for RESTful Web services (Erbium). - * Inspired by RESTful Contiki by Dogan Yazar. - * \author - * Matthias Kovatsch - */ - -#include -#include -#include "contiki.h" -#include "rest-engine.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -PROCESS(rest_engine_process, "REST Engine"); -/*---------------------------------------------------------------------------*/ -LIST(restful_services); -LIST(restful_periodic_services); -/*---------------------------------------------------------------------------*/ -/*- REST Engine API ---------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -/** - * \brief Initializes and starts the REST Engine process - * - * This function must be called by server processes before any resources are - * registered through rest_activate_resource(). - */ -void -rest_init_engine(void) -{ - list_init(restful_services); - - REST.set_service_callback(rest_invoke_restful_service); - - /* Start the RESTful server implementation. */ - REST.init(); - - /*Start REST engine process */ - process_start(&rest_engine_process, NULL); -} -/*---------------------------------------------------------------------------*/ -/** - * \brief Makes a resource available under the given URI path - * \param resource A pointer to a resource implementation - * \param path The URI path string for this resource - * - * The resource implementation must be imported first using the - * extern keyword. The build system takes care of compiling every - * *.c file in the ./resources/ sub-directory (see example Makefile). - */ -void -rest_activate_resource(resource_t * resource, char *path) -{ - resource->url = path; - list_add(restful_services, resource); - - PRINTF("Activating: %s\n", resource->url); - - /* Only add periodic resources with a periodic_handler and a period > 0. */ - if(resource->flags & IS_PERIODIC && resource->periodic->periodic_handler - && resource->periodic->period) { - PRINTF("Periodic resource: %p (%s)\n", resource->periodic, - resource->periodic->resource->url); - list_add(restful_periodic_services, resource->periodic); - } -} -/*---------------------------------------------------------------------------*/ -/*- Internal API ------------------------------------------------------------*/ -/*---------------------------------------------------------------------------*/ -list_t -rest_get_resources(void) -{ - return restful_services; -} -/*---------------------------------------------------------------------------*/ -int -rest_invoke_restful_service(void *request, void *response, uint8_t * buffer, - uint16_t buffer_size, int32_t * offset) -{ - uint8_t found = 0; - uint8_t allowed = 1; - - resource_t *resource = NULL; - const char *url = NULL; - - for(resource = (resource_t *) list_head(restful_services); - resource; resource = resource->next) { - - /* if the web service handles that kind of requests and urls matches */ - if((REST.get_url(request, &url) == strlen(resource->url) - || (REST.get_url(request, &url) > strlen(resource->url) - && (resource->flags & HAS_SUB_RESOURCES))) - && strncmp(resource->url, url, strlen(resource->url)) == 0) { - found = 1; - rest_resource_flags_t method = REST.get_method_type(request); - - PRINTF("/%s, method %u, resource->flags %u\n", resource->url, - (uint16_t) method, resource->flags); - - if((method & METHOD_GET) && resource->get_handler != NULL) { - /* call handler function */ - resource->get_handler(request, response, buffer, buffer_size, offset); - } else if((method & METHOD_POST) && resource->post_handler != NULL) { - /* call handler function */ - resource->post_handler(request, response, buffer, buffer_size, - offset); - } else if((method & METHOD_PUT) && resource->put_handler != NULL) { - /* call handler function */ - resource->put_handler(request, response, buffer, buffer_size, offset); - } else if((method & METHOD_DELETE) && resource->delete_handler != NULL) { - /* call handler function */ - resource->delete_handler(request, response, buffer, buffer_size, - offset); - } else { - allowed = 0; - REST.set_response_status(response, REST.status.METHOD_NOT_ALLOWED); - } - break; - } - } - - if(!found) { - REST.set_response_status(response, REST.status.NOT_FOUND); - } else if(allowed) { - /* final handler for special flags */ - if(resource->flags & IS_OBSERVABLE) { - REST.subscription_handler(resource, request, response); - } - } - - return found & allowed; -} -/*-----------------------------------------------------------------------------------*/ -PROCESS_THREAD(rest_engine_process, ev, data) -{ - PROCESS_BEGIN(); - - /* pause to let REST server finish adding resources. */ - PROCESS_PAUSE(); - - /* initialize the PERIODIC_RESOURCE timers, which will be handled by this process. */ - periodic_resource_t *periodic_resource = NULL; - - for(periodic_resource = - (periodic_resource_t *) list_head(restful_periodic_services); - periodic_resource; periodic_resource = periodic_resource->next) { - if(periodic_resource->periodic_handler && periodic_resource->period) { - PRINTF("Periodic: Set timer for /%s to %lu\n", - periodic_resource->resource->url, periodic_resource->period); - etimer_set(&periodic_resource->periodic_timer, - periodic_resource->period); - } - } - - while(1) { - PROCESS_WAIT_EVENT(); - - if(ev == PROCESS_EVENT_TIMER) { - for(periodic_resource = - (periodic_resource_t *) list_head(restful_periodic_services); - periodic_resource; periodic_resource = periodic_resource->next) { - if(periodic_resource->period - && etimer_expired(&periodic_resource->periodic_timer)) { - - PRINTF("Periodic: etimer expired for /%s (period: %lu)\n", - periodic_resource->resource->url, periodic_resource->period); - - /* Call the periodic_handler function, which was checked during adding to list. */ - (periodic_resource->periodic_handler) (); - - etimer_reset(&periodic_resource->periodic_timer); - } - } - } - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * An abstraction layer for RESTful Web services (Erbium). + * Inspired by RESTful Contiki by Dogan Yazar. + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "contiki.h" +#include "rest-engine.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +PROCESS(rest_engine_process, "REST Engine"); +/*---------------------------------------------------------------------------*/ +LIST(restful_services); +LIST(restful_periodic_services); +/*---------------------------------------------------------------------------*/ +/*- REST Engine API ---------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/** + * \brief Initializes and starts the REST Engine process + * + * This function must be called by server processes before any resources are + * registered through rest_activate_resource(). + */ +void +rest_init_engine(void) +{ + list_init(restful_services); + + REST.set_service_callback(rest_invoke_restful_service); + + /* Start the RESTful server implementation. */ + REST.init(); + + /*Start REST engine process */ + process_start(&rest_engine_process, NULL); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Makes a resource available under the given URI path + * \param resource A pointer to a resource implementation + * \param path The URI path string for this resource + * + * The resource implementation must be imported first using the + * extern keyword. The build system takes care of compiling every + * *.c file in the ./resources/ sub-directory (see example Makefile). + */ +void +rest_activate_resource(resource_t *resource, char *path) +{ + resource->url = path; + list_add(restful_services, resource); + + PRINTF("Activating: %s\n", resource->url); + + /* Only add periodic resources with a periodic_handler and a period > 0. */ + if(resource->flags & IS_PERIODIC && resource->periodic->periodic_handler + && resource->periodic->period) { + PRINTF("Periodic resource: %p (%s)\n", resource->periodic, + resource->periodic->resource->url); + list_add(restful_periodic_services, resource->periodic); + } +} +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +list_t +rest_get_resources(void) +{ + return restful_services; +} +/*---------------------------------------------------------------------------*/ +int +rest_invoke_restful_service(void *request, void *response, uint8_t *buffer, + uint16_t buffer_size, int32_t *offset) +{ + uint8_t found = 0; + uint8_t allowed = 1; + + resource_t *resource = NULL; + const char *url = NULL; + + for(resource = (resource_t *)list_head(restful_services); + resource; resource = resource->next) { + + /* if the web service handles that kind of requests and urls matches */ + if((REST.get_url(request, &url) == strlen(resource->url) + || (REST.get_url(request, &url) > strlen(resource->url) + && (resource->flags & HAS_SUB_RESOURCES))) + && strncmp(resource->url, url, strlen(resource->url)) == 0) { + found = 1; + rest_resource_flags_t method = REST.get_method_type(request); + + PRINTF("/%s, method %u, resource->flags %u\n", resource->url, + (uint16_t)method, resource->flags); + + if((method & METHOD_GET) && resource->get_handler != NULL) { + /* call handler function */ + resource->get_handler(request, response, buffer, buffer_size, offset); + } else if((method & METHOD_POST) && resource->post_handler != NULL) { + /* call handler function */ + resource->post_handler(request, response, buffer, buffer_size, + offset); + } else if((method & METHOD_PUT) && resource->put_handler != NULL) { + /* call handler function */ + resource->put_handler(request, response, buffer, buffer_size, offset); + } else if((method & METHOD_DELETE) && resource->delete_handler != NULL) { + /* call handler function */ + resource->delete_handler(request, response, buffer, buffer_size, + offset); + } else { + allowed = 0; + REST.set_response_status(response, REST.status.METHOD_NOT_ALLOWED); + } + break; + } + } + if(!found) { + REST.set_response_status(response, REST.status.NOT_FOUND); + } else if(allowed) { + /* final handler for special flags */ + if(resource->flags & IS_OBSERVABLE) { + REST.subscription_handler(resource, request, response); + } + } + return found & allowed; +} +/*-----------------------------------------------------------------------------------*/ +PROCESS_THREAD(rest_engine_process, ev, data) +{ + PROCESS_BEGIN(); + + /* pause to let REST server finish adding resources. */ + PROCESS_PAUSE(); + + /* initialize the PERIODIC_RESOURCE timers, which will be handled by this process. */ + periodic_resource_t *periodic_resource = NULL; + + for(periodic_resource = + (periodic_resource_t *)list_head(restful_periodic_services); + periodic_resource; periodic_resource = periodic_resource->next) { + if(periodic_resource->periodic_handler && periodic_resource->period) { + PRINTF("Periodic: Set timer for /%s to %lu\n", + periodic_resource->resource->url, periodic_resource->period); + etimer_set(&periodic_resource->periodic_timer, + periodic_resource->period); + } + } + while(1) { + PROCESS_WAIT_EVENT(); + + if(ev == PROCESS_EVENT_TIMER) { + for(periodic_resource = + (periodic_resource_t *)list_head(restful_periodic_services); + periodic_resource; periodic_resource = periodic_resource->next) { + if(periodic_resource->period + && etimer_expired(&periodic_resource->periodic_timer)) { + + PRINTF("Periodic: etimer expired for /%s (period: %lu)\n", + periodic_resource->resource->url, periodic_resource->period); + + /* Call the periodic_handler function, which was checked during adding to list. */ + (periodic_resource->periodic_handler)(); + + etimer_reset(&periodic_resource->periodic_timer); + } + } + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/apps/rest-engine/rest-engine.h b/apps/rest-engine/rest-engine.h old mode 100755 new mode 100644 index e88dfd68d..3a2848f58 --- a/apps/rest-engine/rest-engine.h +++ b/apps/rest-engine/rest-engine.h @@ -1,263 +1,262 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * An abstraction layer for RESTful Web services (Erbium). - * Inspired by RESTful Contiki by Dogan Yazar. - * \author - * Matthias Kovatsch - */ - -#ifndef REST_ENGINE_H_ -#define REST_ENGINE_H_ - -#include -#include "contiki.h" -#include "contiki-lib.h" -#include "rest-constants.h" - -/* list of valid REST Enigne implementations */ -#define REGISTERED_ENGINE_ERBIUM coap_rest_implementation -#define REGISTERED_ENGINE_HELIUM http_rest_implementation - -/* sanity check for configured implementation */ -#if !defined(REST) || (REST!=REGISTERED_ENGINE_ERBIUM && REST!=REGISTERED_ENGINE_HELIUM) -#error "Define a valid REST Engine implementation (REST define)!" -#endif - -/* - * The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer. - * Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks. - */ -#ifndef REST_MAX_CHUNK_SIZE -#define REST_MAX_CHUNK_SIZE 64 -#endif - -#ifndef MIN -#define MIN(a, b) ((a) < (b)? (a) : (b)) -#endif /* MIN */ - - -struct resource_s; -struct periodic_resource_s; - -/* signatures of handler functions */ -typedef void (*restful_handler) (void *request, void *response, - uint8_t * buffer, uint16_t preferred_size, - int32_t * offset); -typedef void (*restful_final_handler) (struct resource_s * resource, - void *request, void *response); -typedef void (*restful_periodic_handler) (void); -typedef void (*restful_response_handler) (void *data, void *response); -typedef void (*restful_trigger_handler) (void); - -/* signature of the rest-engine service function */ -typedef int (*service_callback_t) (void *request, void *response, - uint8_t * buffer, uint16_t preferred_size, - int32_t * offset); - -/* data structure representing a resource in REST */ -struct resource_s { - struct resource_s *next; /* for LIST, points to next resource defined */ - const char *url; /*handled URL */ - rest_resource_flags_t flags; /* handled RESTful methods */ - const char *attributes; /* link-format attributes */ - restful_handler get_handler; /* handler function */ - restful_handler post_handler; /* handler function */ - restful_handler put_handler; /* handler function */ - restful_handler delete_handler; /* handler function */ - union { - struct periodic_resource_s *periodic; /* special data depending on flags */ - restful_trigger_handler trigger; - restful_trigger_handler resume; - }; -}; -typedef struct resource_s resource_t; - -struct periodic_resource_s { - struct periodic_resource_s *next; /* for LIST, points to next resource defined */ - const resource_t *resource; - uint32_t period; - struct etimer periodic_timer; - const restful_periodic_handler periodic_handler; -}; -typedef struct periodic_resource_s periodic_resource_t; - -/* - * Macro to define a RESTful resource. - * Resources are statically defined for the sake of efficiency and better memory management. - */ -#define RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler) \ - resource_t name = {NULL, NULL, NO_FLAGS, attributes, get_handler, post_handler, put_handler, delete_handler, {NULL}} - -#define PARENT_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler) \ - resource_t name = {NULL, NULL, HAS_SUB_RESOURCES, attributes, get_handler, post_handler, put_handler, delete_handler, {NULL}} - -#define SEPARATE_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, resume_handler) \ - resource_t name = {NULL, NULL, IS_SEPARATE, attributes, get_handler, post_handler, put_handler, delete_handler, { .resume = resume_handler }} - -#define EVENT_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, event_handler) \ - resource_t name = {NULL, NULL, IS_OBSERVABLE, attributes, get_handler, post_handler, put_handler, delete_handler, { .trigger = event_handler }} - -/* - * Macro to define a periodic resource. - * The corresponding [name]_periodic_handler() function will be called every period. - * For instance polling a sensor and publishing a changed value to subscribed clients would be done there. - * The subscriber list will be maintained by the final_handler rest_subscription_handler() (see rest-mapping header file). - */ -#define PERIODIC_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, period, periodic_handler) \ - periodic_resource_t periodic_##name; \ - resource_t name = {NULL, NULL, IS_OBSERVABLE | IS_PERIODIC, attributes, get_handler, post_handler, put_handler, delete_handler, { .periodic = &periodic_##name }}; \ - periodic_resource_t periodic_##name = {NULL, &name, period, {{0}}, periodic_handler}; - -struct rest_implementation { - char *name; - - /** Initialize the REST implementation. */ - void (*init) (void); - - /** Register the RESTful service callback at implementation. */ - void (*set_service_callback) (service_callback_t callback); - - /** Get request URI path. */ - int (*get_url) (void *request, const char **url); - - /** Get the method of a request. */ - rest_resource_flags_t (*get_method_type) (void *request); - - /** Set the status code of a response. */ - int (*set_response_status) (void *response, unsigned int code); - - /** Get the content-type of a request. */ - int (*get_header_content_type) (void *request, - unsigned int *content_format); - - /** Set the Content-Type of a response. */ - int (*set_header_content_type) (void *response, - unsigned int content_format); - - /** Get the Accept types of a request. */ - int (*get_header_accept) (void *request, unsigned int *accept); - - /** Get the Length option of a request. */ - int (*get_header_length) (void *request, uint32_t * size); - - /** Set the Length option of a response. */ - int (*set_header_length) (void *response, uint32_t size); - - /** Get the Max-Age option of a request. */ - int (*get_header_max_age) (void *request, uint32_t * age); - - /** Set the Max-Age option of a response. */ - int (*set_header_max_age) (void *response, uint32_t age); - - /** Set the ETag option of a response. */ - int (*set_header_etag) (void *response, const uint8_t * etag, - size_t length); - - /** Get the If-Match option of a request. */ - int (*get_header_if_match) (void *request, const uint8_t ** etag); - - /** Get the If-Match option of a request. */ - int (*get_header_if_none_match) (void *request); - - /** Get the Host option of a request. */ - int (*get_header_host) (void *request, const char **host); - - /** Set the location option of a response. */ - int (*set_header_location) (void *response, const char *location); - - /** Get the payload option of a request. */ - int (*get_request_payload) (void *request, const uint8_t ** payload); - - /** Set the payload option of a response. */ - int (*set_response_payload) (void *response, const void *payload, - size_t length); - - /** Get the query string of a request. */ - int (*get_query) (void *request, const char **value); - - /** Get the value of a request query key-value pair. */ - int (*get_query_variable) (void *request, const char *name, - const char **value); - - /** Get the value of a request POST key-value pair. */ - int (*get_post_variable) (void *request, const char *name, - const char **value); - - /** Send the payload to all subscribers of the resource at url. */ - void (*notify_subscribers) (resource_t * resource); - - /** The handler for resource subscriptions. */ - restful_final_handler subscription_handler; - - /* REST status codes. */ - const struct rest_implementation_status status; - - /* REST content-types. */ - const struct rest_implementation_type type; -}; - -/* instance of REST implementation */ -extern const struct rest_implementation REST; - -/* - * To be called by HTTP/COAP server as a callback function when a new service request appears. - * This function dispatches the corresponding RESTful service. - */ -int rest_invoke_restful_service(void *request, void *response, - uint8_t * buffer, uint16_t buffer_size, - int32_t * offset); -/*---------------------------------------------------------------------------*/ -/** - * \brief Initializes REST framework and starts the HTTP or CoAP process. - */ -void rest_init_engine(void); -/*---------------------------------------------------------------------------*/ -/** - * - * \brief Resources wanted to be accessible should be activated with the following code. - * \param resource - * A RESTful resource defined through the RESOURCE macros. - * \param path - * The local URI path where to provide the resource. - */ -void rest_activate_resource(resource_t * resource, char *path); -/*---------------------------------------------------------------------------*/ -/** - * \brief Returns the list of registered RESTful resources. - * \return The resource list. - */ -list_t rest_get_resources(void); -/*---------------------------------------------------------------------------*/ - -#endif /*REST_ENGINE_H_ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * An abstraction layer for RESTful Web services (Erbium). + * Inspired by RESTful Contiki by Dogan Yazar. + * \author + * Matthias Kovatsch + */ + +#ifndef REST_ENGINE_H_ +#define REST_ENGINE_H_ + +#include +#include "contiki.h" +#include "contiki-lib.h" +#include "rest-constants.h" + +/* list of valid REST Enigne implementations */ +#define REGISTERED_ENGINE_ERBIUM coap_rest_implementation +#define REGISTERED_ENGINE_HELIUM http_rest_implementation + +/* sanity check for configured implementation */ +#if !defined(REST) || (REST != REGISTERED_ENGINE_ERBIUM && REST != REGISTERED_ENGINE_HELIUM) +#error "Define a valid REST Engine implementation (REST define)!" +#endif + +/* + * The maximum buffer size that is provided for resource responses and must be respected due to the limited IP buffer. + * Larger data must be handled by the resource and will be sent chunk-wise through a TCP stream or CoAP blocks. + */ +#ifndef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE 64 +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ + +struct resource_s; +struct periodic_resource_s; + +/* signatures of handler functions */ +typedef void (*restful_handler)(void *request, void *response, + uint8_t *buffer, uint16_t preferred_size, + int32_t *offset); +typedef void (*restful_final_handler)(struct resource_s *resource, + void *request, void *response); +typedef void (*restful_periodic_handler)(void); +typedef void (*restful_response_handler)(void *data, void *response); +typedef void (*restful_trigger_handler)(void); + +/* signature of the rest-engine service function */ +typedef int (*service_callback_t)(void *request, void *response, + uint8_t *buffer, uint16_t preferred_size, + int32_t *offset); + +/* data structure representing a resource in REST */ +struct resource_s { + struct resource_s *next; /* for LIST, points to next resource defined */ + const char *url; /*handled URL */ + rest_resource_flags_t flags; /* handled RESTful methods */ + const char *attributes; /* link-format attributes */ + restful_handler get_handler; /* handler function */ + restful_handler post_handler; /* handler function */ + restful_handler put_handler; /* handler function */ + restful_handler delete_handler; /* handler function */ + union { + struct periodic_resource_s *periodic; /* special data depending on flags */ + restful_trigger_handler trigger; + restful_trigger_handler resume; + }; +}; +typedef struct resource_s resource_t; + +struct periodic_resource_s { + struct periodic_resource_s *next; /* for LIST, points to next resource defined */ + const resource_t *resource; + uint32_t period; + struct etimer periodic_timer; + const restful_periodic_handler periodic_handler; +}; +typedef struct periodic_resource_s periodic_resource_t; + +/* + * Macro to define a RESTful resource. + * Resources are statically defined for the sake of efficiency and better memory management. + */ +#define RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler) \ + resource_t name = { NULL, NULL, NO_FLAGS, attributes, get_handler, post_handler, put_handler, delete_handler, { NULL } } + +#define PARENT_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler) \ + resource_t name = { NULL, NULL, HAS_SUB_RESOURCES, attributes, get_handler, post_handler, put_handler, delete_handler, { NULL } } + +#define SEPARATE_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, resume_handler) \ + resource_t name = { NULL, NULL, IS_SEPARATE, attributes, get_handler, post_handler, put_handler, delete_handler, { .resume = resume_handler } } + +#define EVENT_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, event_handler) \ + resource_t name = { NULL, NULL, IS_OBSERVABLE, attributes, get_handler, post_handler, put_handler, delete_handler, { .trigger = event_handler } } + +/* + * Macro to define a periodic resource. + * The corresponding [name]_periodic_handler() function will be called every period. + * For instance polling a sensor and publishing a changed value to subscribed clients would be done there. + * The subscriber list will be maintained by the final_handler rest_subscription_handler() (see rest-mapping header file). + */ +#define PERIODIC_RESOURCE(name, attributes, get_handler, post_handler, put_handler, delete_handler, period, periodic_handler) \ + periodic_resource_t periodic_##name; \ + resource_t name = { NULL, NULL, IS_OBSERVABLE | IS_PERIODIC, attributes, get_handler, post_handler, put_handler, delete_handler, { .periodic = &periodic_##name } }; \ + periodic_resource_t periodic_##name = { NULL, &name, period, { { 0 } }, periodic_handler }; + +struct rest_implementation { + char *name; + + /** Initialize the REST implementation. */ + void (*init)(void); + + /** Register the RESTful service callback at implementation. */ + void (*set_service_callback)(service_callback_t callback); + + /** Get request URI path. */ + int (*get_url)(void *request, const char **url); + + /** Get the method of a request. */ + rest_resource_flags_t (*get_method_type)(void *request); + + /** Set the status code of a response. */ + int (*set_response_status)(void *response, unsigned int code); + + /** Get the content-type of a request. */ + int (*get_header_content_type)(void *request, + unsigned int *content_format); + + /** Set the Content-Type of a response. */ + int (*set_header_content_type)(void *response, + unsigned int content_format); + + /** Get the Accept types of a request. */ + int (*get_header_accept)(void *request, unsigned int *accept); + + /** Get the Length option of a request. */ + int (*get_header_length)(void *request, uint32_t *size); + + /** Set the Length option of a response. */ + int (*set_header_length)(void *response, uint32_t size); + + /** Get the Max-Age option of a request. */ + int (*get_header_max_age)(void *request, uint32_t *age); + + /** Set the Max-Age option of a response. */ + int (*set_header_max_age)(void *response, uint32_t age); + + /** Set the ETag option of a response. */ + int (*set_header_etag)(void *response, const uint8_t *etag, + size_t length); + + /** Get the If-Match option of a request. */ + int (*get_header_if_match)(void *request, const uint8_t **etag); + + /** Get the If-Match option of a request. */ + int (*get_header_if_none_match)(void *request); + + /** Get the Host option of a request. */ + int (*get_header_host)(void *request, const char **host); + + /** Set the location option of a response. */ + int (*set_header_location)(void *response, const char *location); + + /** Get the payload option of a request. */ + int (*get_request_payload)(void *request, const uint8_t **payload); + + /** Set the payload option of a response. */ + int (*set_response_payload)(void *response, const void *payload, + size_t length); + + /** Get the query string of a request. */ + int (*get_query)(void *request, const char **value); + + /** Get the value of a request query key-value pair. */ + int (*get_query_variable)(void *request, const char *name, + const char **value); + + /** Get the value of a request POST key-value pair. */ + int (*get_post_variable)(void *request, const char *name, + const char **value); + + /** Send the payload to all subscribers of the resource at url. */ + void (*notify_subscribers)(resource_t *resource); + + /** The handler for resource subscriptions. */ + restful_final_handler subscription_handler; + + /* REST status codes. */ + const struct rest_implementation_status status; + + /* REST content-types. */ + const struct rest_implementation_type type; +}; + +/* instance of REST implementation */ +extern const struct rest_implementation REST; + +/* + * To be called by HTTP/COAP server as a callback function when a new service request appears. + * This function dispatches the corresponding RESTful service. + */ +int rest_invoke_restful_service(void *request, void *response, + uint8_t *buffer, uint16_t buffer_size, + int32_t *offset); +/*---------------------------------------------------------------------------*/ +/** + * \brief Initializes REST framework and starts the HTTP or CoAP process. + */ +void rest_init_engine(void); +/*---------------------------------------------------------------------------*/ +/** + * + * \brief Resources wanted to be accessible should be activated with the following code. + * \param resource + * A RESTful resource defined through the RESOURCE macros. + * \param path + * The local URI path where to provide the resource. + */ +void rest_activate_resource(resource_t *resource, char *path); +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the list of registered RESTful resources. + * \return The resource list. + */ +list_t rest_get_resources(void); +/*---------------------------------------------------------------------------*/ + +#endif /*REST_ENGINE_H_ */ diff --git a/examples/er-rest-example/Makefile b/examples/er-rest-example/Makefile index 348102789..7411e4d71 100755 --- a/examples/er-rest-example/Makefile +++ b/examples/er-rest-example/Makefile @@ -13,7 +13,15 @@ CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" # automatically build RESTful resources REST_RESOURCES_DIR = ./resources +ifndef TARGET REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c')) +else +ifeq ($(TARGET), native) +REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c')) +else +REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c' ! -name 'res-plugtest*')) +endif +endif PROJECTDIRS += $(REST_RESOURCES_DIR) PROJECT_SOURCEFILES += $(REST_RESOURCES_FILES) diff --git a/examples/er-rest-example/er-example-client.c b/examples/er-rest-example/er-example-client.c old mode 100755 new mode 100644 index f8dc47f09..fa3df6a22 --- a/examples/er-rest-example/er-example-client.c +++ b/examples/er-rest-example/er-example-client.c @@ -1,156 +1,159 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Erbium (Er) CoAP client example. - * \author - * Matthias Kovatsch - */ - -#include -#include -#include -#include "contiki.h" -#include "contiki-net.h" -#include "er-coap-engine.h" -#include "dev/button-sensor.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - - -/* FIXME: This server address is hard-coded for Cooja and link-local for unconnected border router. */ -#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202) /* cooja2 */ -//#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xbbbb, 0, 0, 0, 0, 0, 0, 0x1) - -#define LOCAL_PORT UIP_HTONS(COAP_DEFAULT_PORT+1) -#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) - -#define TOGGLE_INTERVAL 10 - -PROCESS(er_example_client, "Erbium Example Client"); -AUTOSTART_PROCESSES(&er_example_client); - - -uip_ipaddr_t server_ipaddr; -static struct etimer et; - -/* Example URIs that can be queried. */ -#define NUMBER_OF_URLS 4 -/* leading and ending slashes only for demo purposes, get cropped automatically when setting the Uri-Path */ -char *service_urls[NUMBER_OF_URLS] = - { ".well-known/core", "/actuators/toggle", "battery/", "error/in//path" }; -#if PLATFORM_HAS_BUTTON -static int uri_switch = 0; -#endif - -/* This function is will be passed to COAP_BLOCKING_REQUEST() to handle responses. */ -void -client_chunk_handler(void *response) -{ - const uint8_t *chunk; - - int len = coap_get_payload(response, &chunk); - - printf("|%.*s", len, (char *)chunk); -} - - -PROCESS_THREAD(er_example_client, ev, data) -{ - PROCESS_BEGIN(); - - static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ - - SERVER_NODE(&server_ipaddr); - - /* receives all CoAP messages */ - coap_init_engine(); - - etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); - -#if PLATFORM_HAS_BUTTON - SENSORS_ACTIVATE(button_sensor); - printf("Press a button to request %s\n", service_urls[uri_switch]); -#endif - - while(1) { - PROCESS_YIELD(); - - if(etimer_expired(&et)) { - printf("--Toggle timer--\n"); - - /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ - coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); - coap_set_header_uri_path(request, service_urls[1]); - - const char msg[] = "Toggle!"; - - coap_set_payload(request, (uint8_t *) msg, sizeof(msg) - 1); - - - PRINT6ADDR(&server_ipaddr); - PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); - - COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, - client_chunk_handler); - - printf("\n--Done--\n"); - - etimer_reset(&et); - -#if PLATFORM_HAS_BUTTON - } else if(ev == sensors_event && data == &button_sensor) { - - /* send a request to notify the end of the process */ - - coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0); - coap_set_header_uri_path(request, service_urls[uri_switch]); - - printf("--Requesting %s--\n", service_urls[uri_switch]); - - PRINT6ADDR(&server_ipaddr); - PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); - - COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, - client_chunk_handler); - - printf("\n--Done--\n"); - - uri_switch = (uri_switch + 1) % NUMBER_OF_URLS; -#endif - - } - } - - PROCESS_END(); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Erbium (Er) CoAP client example. + * \author + * Matthias Kovatsch + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "er-coap-engine.h" +#include "dev/button-sensor.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/* FIXME: This server address is hard-coded for Cooja and link-local for unconnected border router. */ +#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202) /* cooja2 */ +/* #define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xbbbb, 0, 0, 0, 0, 0, 0, 0x1) */ + +#define LOCAL_PORT UIP_HTONS(COAP_DEFAULT_PORT + 1) +#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) + +#define TOGGLE_INTERVAL 10 + +PROCESS(er_example_client, "Erbium Example Client"); +AUTOSTART_PROCESSES(&er_example_client); + +uip_ipaddr_t server_ipaddr; +static struct etimer et; + +/* Example URIs that can be queried. */ +#define NUMBER_OF_URLS 4 +/* leading and ending slashes only for demo purposes, get cropped automatically when setting the Uri-Path */ +char *service_urls[NUMBER_OF_URLS] = +{ ".well-known/core", "/actuators/toggle", "battery/", "error/in//path" }; +#if PLATFORM_HAS_BUTTON +static int uri_switch = 0; +#endif + +/* This function is will be passed to COAP_BLOCKING_REQUEST() to handle responses. */ +void +client_chunk_handler(void *response) +{ + const uint8_t *chunk; + + int len = coap_get_payload(response, &chunk); + + printf("|%.*s", len, (char *)chunk); +} +PROCESS_THREAD(er_example_client, ev, data) +{ + PROCESS_BEGIN(); + + static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ + + SERVER_NODE(&server_ipaddr); + + /* receives all CoAP messages */ + coap_init_engine(); + + etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); + +#if PLATFORM_HAS_BUTTON + SENSORS_ACTIVATE(button_sensor); + printf("Press a button to request %s\n", service_urls[uri_switch]); +#endif + + while(1) { + PROCESS_YIELD(); + + if(etimer_expired(&et)) { + printf("--Toggle timer--\n"); + + /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ + coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); + coap_set_header_uri_path(request, service_urls[1]); + + const char msg[] = "Toggle!"; + + coap_set_payload(request, (uint8_t *)msg, sizeof(msg) - 1); + + PRINT6ADDR(&server_ipaddr); + PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); + + COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, + client_chunk_handler); + + printf("\n--Done--\n"); + + etimer_reset(&et); + +#if PLATFORM_HAS_BUTTON + } else if(ev == sensors_event && data == &button_sensor) { + + /* send a request to notify the end of the process */ + + coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0); + coap_set_header_uri_path(request, service_urls[uri_switch]); + + printf("--Requesting %s--\n", service_urls[uri_switch]); + + PRINT6ADDR(&server_ipaddr); + PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); + + COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, + client_chunk_handler); + + printf("\n--Done--\n"); + + uri_switch = (uri_switch + 1) % NUMBER_OF_URLS; +#endif + } + } + + PROCESS_END(); +} diff --git a/examples/er-rest-example/er-example-server.c b/examples/er-rest-example/er-example-server.c old mode 100755 new mode 100644 diff --git a/examples/er-rest-example/er-plugtest-server.c b/examples/er-rest-example/er-plugtest-server.c old mode 100755 new mode 100644 index 9eca4f6e3..ae637dc4c --- a/examples/er-rest-example/er-plugtest-server.c +++ b/examples/er-rest-example/er-plugtest-server.c @@ -1,129 +1,128 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Server for the ETSI IoT CoAP Plugtests, Las Vegas, NV, USA, Nov 2013. - * \author - * Matthias Kovatsch - */ - -#include -#include -#include -#include "contiki.h" -#include "contiki-net.h" -#include "er-coap.h" -#include "er-coap-transactions.h" -#include "er-coap-separate.h" -#include "rest-engine.h" -#include "er-plugtest.h" - -/* - * Resources to be activated need to be imported through the extern keyword. - * The build system automatically compiles the resources in the corresponding - * sub-directory. - */ -extern resource_t - res_plugtest_test, - res_plugtest_validate, - res_plugtest_create1, - res_plugtest_create2, - res_plugtest_create3, - res_plugtest_longpath, - res_plugtest_query, - res_plugtest_locquery, - res_plugtest_multi, - res_plugtest_link1, - res_plugtest_link2, - res_plugtest_link3, - res_plugtest_path, - res_plugtest_separate, - res_plugtest_large, - res_plugtest_large_update, - res_plugtest_large_create, - res_plugtest_obs, - res_mirror; - -PROCESS(plugtest_server, "PlugtestServer"); -AUTOSTART_PROCESSES(&plugtest_server); - -PROCESS_THREAD(plugtest_server, ev, data) -{ - PROCESS_BEGIN(); - - PRINTF("ETSI IoT CoAP Plugtests Server\n"); - -#ifdef RF_CHANNEL - PRINTF("RF channel: %u\n", RF_CHANNEL); -#endif -#ifdef IEEE802154_PANID - PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); -#endif - - PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); - PRINTF("LL header: %u\n", UIP_LLH_LEN); - PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); - PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); - - /* Initialize the REST engine. */ - rest_init_engine(); - - /* Activate the application-specific resources. */ - rest_activate_resource(&res_plugtest_test, "test"); - rest_activate_resource(&res_plugtest_validate, "validate"); - rest_activate_resource(&res_plugtest_create1, "create1"); - rest_activate_resource(&res_plugtest_create2, "create2"); - rest_activate_resource(&res_plugtest_create3, "create3"); - rest_activate_resource(&res_plugtest_longpath, "seg1/seg2/seg3"); - rest_activate_resource(&res_plugtest_query, "query"); - rest_activate_resource(&res_plugtest_locquery, "location-query"); - rest_activate_resource(&res_plugtest_multi, "multi-format"); - rest_activate_resource(&res_plugtest_link1, "link1"); - rest_activate_resource(&res_plugtest_link2, "link2"); - rest_activate_resource(&res_plugtest_link3, "link3"); - rest_activate_resource(&res_plugtest_path, "path"); - rest_activate_resource(&res_plugtest_separate, "separate"); - rest_activate_resource(&res_plugtest_large, "large"); - rest_activate_resource(&res_plugtest_large_update, "large-update"); - rest_activate_resource(&res_plugtest_large_create, "large-create"); - rest_activate_resource(&res_plugtest_obs, "obs"); - - rest_activate_resource(&res_mirror, "mirror"); - - /* Define application-specific events here. */ - while(1) { - PROCESS_WAIT_EVENT(); - - } /* while (1) */ - - PROCESS_END(); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Server for the ETSI IoT CoAP Plugtests, Las Vegas, NV, USA, Nov 2013. + * \author + * Matthias Kovatsch + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "er-coap-separate.h" +#include "rest-engine.h" +#include "er-plugtest.h" + +/* + * Resources to be activated need to be imported through the extern keyword. + * The build system automatically compiles the resources in the corresponding + * sub-directory. + */ +extern resource_t + res_plugtest_test, + res_plugtest_validate, + res_plugtest_create1, + res_plugtest_create2, + res_plugtest_create3, + res_plugtest_longpath, + res_plugtest_query, + res_plugtest_locquery, + res_plugtest_multi, + res_plugtest_link1, + res_plugtest_link2, + res_plugtest_link3, + res_plugtest_path, + res_plugtest_separate, + res_plugtest_large, + res_plugtest_large_update, + res_plugtest_large_create, + res_plugtest_obs, + res_mirror; + +PROCESS(plugtest_server, "PlugtestServer"); +AUTOSTART_PROCESSES(&plugtest_server); + +PROCESS_THREAD(plugtest_server, ev, data) +{ + PROCESS_BEGIN(); + + PRINTF("ETSI IoT CoAP Plugtests Server\n"); + +#ifdef RF_CHANNEL + PRINTF("RF channel: %u\n", RF_CHANNEL); +#endif +#ifdef IEEE802154_PANID + PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); +#endif + + PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); + PRINTF("LL header: %u\n", UIP_LLH_LEN); + PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); + PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + + /* Initialize the REST engine. */ + rest_init_engine(); + + /* Activate the application-specific resources. */ + rest_activate_resource(&res_plugtest_test, "test"); + rest_activate_resource(&res_plugtest_validate, "validate"); + rest_activate_resource(&res_plugtest_create1, "create1"); + rest_activate_resource(&res_plugtest_create2, "create2"); + rest_activate_resource(&res_plugtest_create3, "create3"); + rest_activate_resource(&res_plugtest_longpath, "seg1/seg2/seg3"); + rest_activate_resource(&res_plugtest_query, "query"); + rest_activate_resource(&res_plugtest_locquery, "location-query"); + rest_activate_resource(&res_plugtest_multi, "multi-format"); + rest_activate_resource(&res_plugtest_link1, "link1"); + rest_activate_resource(&res_plugtest_link2, "link2"); + rest_activate_resource(&res_plugtest_link3, "link3"); + rest_activate_resource(&res_plugtest_path, "path"); + rest_activate_resource(&res_plugtest_separate, "separate"); + rest_activate_resource(&res_plugtest_large, "large"); + rest_activate_resource(&res_plugtest_large_update, "large-update"); + rest_activate_resource(&res_plugtest_large_create, "large-create"); + rest_activate_resource(&res_plugtest_obs, "obs"); + + rest_activate_resource(&res_mirror, "mirror"); + + /* Define application-specific events here. */ + while(1) { + PROCESS_WAIT_EVENT(); + } /* while (1) */ + + PROCESS_END(); +} diff --git a/examples/er-rest-example/er-plugtest.h b/examples/er-rest-example/er-plugtest.h old mode 100755 new mode 100644 index fb705f868..0b156656a --- a/examples/er-rest-example/er-plugtest.h +++ b/examples/er-rest-example/er-plugtest.h @@ -1,57 +1,66 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Erbium (Er) CoAP client example - * \author - * Matthias Kovatsch - */ - -#ifndef __ER_PLUGTEST_H__ -#define __ER_PLUGTEST_H__ - -#if !defined (CONTIKI_TARGET_NATIVE) -#warning "Should only be compiled for native!" -#endif - -#define DEBUG DEBUG_PRINT -#include "net/uip-debug.h" - -/* double expansion */ -#define TO_STRING2(x) #x -#define TO_STRING(x) TO_STRING2(x) - -#define MAX_PLUGFEST_PAYLOAD 64+1 /* +1 for the terminating zero, which is not transmitted */ -#define MAX_PLUGFEST_BODY 2048 -#define CHUNKS_TOTAL 2012 - -#endif /* __ER_PLUGTEST_H__ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Erbium (Er) CoAP client example + * \author + * Matthias Kovatsch + */ + +#ifndef __ER_PLUGTEST_H__ +#define __ER_PLUGTEST_H__ + +#if !defined(CONTIKI_TARGET_NATIVE) +#warning "Should only be compiled for native!" +#endif + +#define DEBUG 0 +#if DEBUG +#include +#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 + +/* double expansion */ +#define TO_STRING2(x) # x +#define TO_STRING(x) TO_STRING2(x) + +#define MAX_PLUGFEST_PAYLOAD 64 + 1 /* +1 for the terminating zero, which is not transmitted */ +#define MAX_PLUGFEST_BODY 2048 +#define CHUNKS_TOTAL 2012 + +#endif /* __ER_PLUGTEST_H__ */ diff --git a/examples/er-rest-example/project-conf.h b/examples/er-rest-example/project-conf.h old mode 100755 new mode 100644 index 06282735a..0ae70731e --- a/examples/er-rest-example/project-conf.h +++ b/examples/er-rest-example/project-conf.h @@ -1,92 +1,92 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Erbium (Er) example project configuration. - * \author - * Matthias Kovatsch - */ - -#ifndef __PROJECT_ERBIUM_CONF_H__ -#define __PROJECT_ERBIUM_CONF_H__ - -/* Custom channel and PAN ID configuration for your project. */ -/* -#undef RF_CHANNEL -#define RF_CHANNEL 26 - -#undef IEEE802154_CONF_PANID -#define IEEE802154_CONF_PANID 0xABCD -*/ - -/* IP buffer size must match all other hops, in particular the border router. */ -/* -#undef UIP_CONF_BUFFER_SIZE -#define UIP_CONF_BUFFER_SIZE 256 -*/ - -/* Disabling RDC for demo purposes. Core updates often require more memory. */ -/* For projects, optimize memory and enable RDC again. */ -#undef NETSTACK_CONF_RDC -#define NETSTACK_CONF_RDC nullrdc_driver - -/* Disabling TCP on CoAP nodes. */ -#undef UIP_CONF_TCP -#define UIP_CONF_TCP 0 - -/* Increase rpl-border-router IP-buffer when using more than 64. */ -#undef REST_MAX_CHUNK_SIZE -#define REST_MAX_CHUNK_SIZE 64 - -/* Estimate your header size, especially when using Proxy-Uri. */ -/* -#undef COAP_MAX_HEADER_SIZE -#define COAP_MAX_HEADER_SIZE 70 -*/ - -/* Multiplies with chunk size, be aware of memory constraints. */ -#undef COAP_MAX_OPEN_TRANSACTIONS -#define COAP_MAX_OPEN_TRANSACTIONS 4 - -/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ -/* -#undef COAP_MAX_OBSERVERS -#define COAP_MAX_OBSERVERS 2 -*/ - -/* Filtering .well-known/core per query can be disabled to save space. */ -#undef COAP_LINK_FORMAT_FILTERING -#define COAP_LINK_FORMAT_FILTERING 0 -#undef COAP_PROXY_OPTION_PROCESSING -#define COAP_PROXY_OPTION_PROCESSING 0 - -#endif /* __PROJECT_ERBIUM_CONF_H__ */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Erbium (Er) example project configuration. + * \author + * Matthias Kovatsch + */ + +#ifndef __PROJECT_ERBIUM_CONF_H__ +#define __PROJECT_ERBIUM_CONF_H__ + +/* Custom channel and PAN ID configuration for your project. */ +/* + #undef RF_CHANNEL + #define RF_CHANNEL 26 + + #undef IEEE802154_CONF_PANID + #define IEEE802154_CONF_PANID 0xABCD + */ + +/* IP buffer size must match all other hops, in particular the border router. */ +/* + #undef UIP_CONF_BUFFER_SIZE + #define UIP_CONF_BUFFER_SIZE 256 + */ + +/* Disabling RDC for demo purposes. Core updates often require more memory. */ +/* For projects, optimize memory and enable RDC again. */ +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nullrdc_driver + +/* Disabling TCP on CoAP nodes. */ +#undef UIP_CONF_TCP +#define UIP_CONF_TCP 0 + +/* Increase rpl-border-router IP-buffer when using more than 64. */ +#undef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE 64 + +/* Estimate your header size, especially when using Proxy-Uri. */ +/* + #undef COAP_MAX_HEADER_SIZE + #define COAP_MAX_HEADER_SIZE 70 + */ + +/* Multiplies with chunk size, be aware of memory constraints. */ +#undef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 4 + +/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ +/* + #undef COAP_MAX_OBSERVERS + #define COAP_MAX_OBSERVERS 2 + */ + +/* Filtering .well-known/core per query can be disabled to save space. */ +#undef COAP_LINK_FORMAT_FILTERING +#define COAP_LINK_FORMAT_FILTERING 0 +#undef COAP_PROXY_OPTION_PROCESSING +#define COAP_PROXY_OPTION_PROCESSING 0 + +#endif /* __PROJECT_ERBIUM_CONF_H__ */ diff --git a/examples/er-rest-example/resources/res-battery.c b/examples/er-rest-example/resources/res-battery.c old mode 100755 new mode 100644 index 1bda32816..3024246ed --- a/examples/er-rest-example/resources/res-battery.c +++ b/examples/er-rest-example/resources/res-battery.c @@ -1,82 +1,81 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include "contiki.h" - -#if PLATFORM_HAS_BATTERY - -#include -#include "rest-engine.h" -#include "dev/battery-sensor.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(battery, - "title=\"Battery status\";rt=\"Battery\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int battery = battery_sensor.value(0); - - unsigned int accept = -1; - REST.get_header_accept(request, &accept); - - if(accept==-1 || accept==REST.type.TEXT_PLAIN) { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept==REST.type.APPLICATION_JSON) { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } else { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } -} - -#endif /* PLATFORM_HAS_BATTERY */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_BATTERY + +#include +#include "rest-engine.h" +#include "dev/battery-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading from light sensor with a simple etag */ +RESOURCE(battery, + "title=\"Battery status\";rt=\"Battery\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int battery = battery_sensor.value(0); + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_BATTERY */ diff --git a/examples/er-rest-example/resources/res-chunks.c b/examples/er-rest-example/resources/res-chunks.c old mode 100755 new mode 100644 index 0424084e1..79ad55094 --- a/examples/er-rest-example/resources/res-chunks.c +++ b/examples/er-rest-example/resources/res-chunks.c @@ -1,99 +1,97 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* - * For data larger than REST_MAX_CHUNK_SIZE (e.g., when stored in flash) resources must be aware of the buffer limitation - * and split their responses by themselves. To transfer the complete resource through a TCP stream or CoAP's blockwise transfer, - * the byte offset where to continue is provided to the handler as int32_t pointer. - * These chunk-wise resources must set the offset value to its new position or -1 of the end is reached. - * (The offset for CoAP's blockwise transfer can go up to 2'147'481'600 = ~2047 M for block size 2048 (reduced to 1024 in observe-03.) - */ -RESOURCE(res_chunks, - "title=\"Blockwise demo\";rt=\"Data\"", - res_get_handler, - NULL, - NULL, - NULL); - -#define CHUNKS_TOTAL 2050 - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int32_t strpos = 0; - - /* Check the offset for boundaries of the resource data. */ - if(*offset>=CHUNKS_TOTAL) { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - /* Generate data until reaching CHUNKS_TOTAL. */ - while (strpos preferred_size) { - strpos = preferred_size; - } - - /* Truncate if above CHUNKS_TOTAL bytes. */ - if(*offset+(int32_t)strpos > CHUNKS_TOTAL) { - strpos = CHUNKS_TOTAL - *offset; - } - - REST.set_response_payload(response, buffer, strpos); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += strpos; - - /* Signal end of resource representation. */ - if(*offset>=CHUNKS_TOTAL) { - *offset = -1; - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * For data larger than REST_MAX_CHUNK_SIZE (e.g., when stored in flash) resources must be aware of the buffer limitation + * and split their responses by themselves. To transfer the complete resource through a TCP stream or CoAP's blockwise transfer, + * the byte offset where to continue is provided to the handler as int32_t pointer. + * These chunk-wise resources must set the offset value to its new position or -1 of the end is reached. + * (The offset for CoAP's blockwise transfer can go up to 2'147'481'600 = ~2047 M for block size 2048 (reduced to 1024 in observe-03.) + */ +RESOURCE(res_chunks, + "title=\"Blockwise demo\";rt=\"Data\"", + res_get_handler, + NULL, + NULL, + NULL); + +#define CHUNKS_TOTAL 2050 + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if(*offset >= CHUNKS_TOTAL) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while(strpos < preferred_size) { + strpos += snprintf((char *)buffer + strpos, preferred_size - strpos + 1, "|%ld|", *offset); + } + + /* snprintf() does not adjust return value if truncated by size. */ + if(strpos > preferred_size) { + strpos = preferred_size; + /* Truncate if above CHUNKS_TOTAL bytes. */ + } + if(*offset + (int32_t)strpos > CHUNKS_TOTAL) { + strpos = CHUNKS_TOTAL - *offset; + } + REST.set_response_payload(response, buffer, strpos); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if(*offset >= CHUNKS_TOTAL) { + *offset = -1; + } +} diff --git a/examples/er-rest-example/resources/res-event.c b/examples/er-rest-example/resources/res-event.c old mode 100755 new mode 100644 index fca8f95b2..d20f0caa9 --- a/examples/er-rest-example/resources/res-event.c +++ b/examples/er-rest-example/resources/res-event.c @@ -1,93 +1,101 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_event_handler(); - -/* - * Example for an event resource. - * Additionally takes a period parameter that defines the interval to call [name]_periodic_handler(). - * A default post_handler takes care of subscriptions and manages a list of subscribers to notify. - */ -EVENT_RESOURCE(res_event, - "title=\"Event demo\";obs", - res_get_handler, - NULL, - NULL, - NULL, - res_event_handler); - -/* - * Use local resource state that is accessed by res_get_handler() and altered by res_event_handler() or PUT or POST. - */ -static int32_t event_counter = 0; - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "EVENT %lu", event_counter)); - - /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */ -} - -/* - * Additionally, res_event_handler must be implemented for each EVENT_RESOURCE. - * It is called through .trigger(), usually from the server process. - */ -static void -res_event_handler() -{ - /* Do the update triggered by the event here, e.g., sampling a sensor. */ - ++event_counter; - - /* Usually a condition is defined under with subscribers are notified, e.g., event was above a threshold. */ - if (1) { - PRINTF("TICK %u for /%s\n", event_counter, res_event.url); - - /* Notify the registered observers which will trigger the res_get_handler to create the response. */ - REST.notify_subscribers(&res_event); - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_event_handler(); + +/* + * Example for an event resource. + * Additionally takes a period parameter that defines the interval to call [name]_periodic_handler(). + * A default post_handler takes care of subscriptions and manages a list of subscribers to notify. + */ +EVENT_RESOURCE(res_event, + "title=\"Event demo\";obs", + res_get_handler, + NULL, + NULL, + NULL, + res_event_handler); + +/* + * Use local resource state that is accessed by res_get_handler() and altered by res_event_handler() or PUT or POST. + */ +static int32_t event_counter = 0; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "EVENT %lu", event_counter)); + + /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */ +} +/* + * Additionally, res_event_handler must be implemented for each EVENT_RESOURCE. + * It is called through .trigger(), usually from the server process. + */ +static void +res_event_handler() +{ + /* Do the update triggered by the event here, e.g., sampling a sensor. */ + ++event_counter; + + /* Usually a condition is defined under with subscribers are notified, e.g., event was above a threshold. */ + if(1) { + PRINTF("TICK %u for /%s\n", event_counter, res_event.url); + + /* Notify the registered observers which will trigger the res_get_handler to create the response. */ + REST.notify_subscribers(&res_event); + } +} diff --git a/examples/er-rest-example/resources/res-hello.c b/examples/er-rest-example/resources/res-hello.c old mode 100755 new mode 100644 index 973d6ad66..9208f8b74 --- a/examples/er-rest-example/resources/res-hello.c +++ b/examples/er-rest-example/resources/res-hello.c @@ -1,79 +1,81 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include -#include "rest-engine.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* - * A handler function named [resource name]_handler must be implemented for each RESOURCE. - * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore - * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. - * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. - */ -RESOURCE(res_hello, - "title=\"Hello world: ?len=0..\";rt=\"Text\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - const char *len = NULL; - /* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */ - char const * const message = "Hello World! ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"; - int length = 12; /* |<-------->| */ - - /* The query string can be retrieved by rest_get_query() or parsed for its key-value pairs. */ - if(REST.get_query_variable(request, "len", &len)) { - length = atoi(len); - if(length<0) length = 0; - if(length>REST_MAX_CHUNK_SIZE) length = REST_MAX_CHUNK_SIZE; - memcpy(buffer, message, length); - } else { - memcpy(buffer, message, length); - } - - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ - REST.set_header_etag(response, (uint8_t *) &length, 1); - REST.set_response_payload(response, buffer, length); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * A handler function named [resource name]_handler must be implemented for each RESOURCE. + * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore + * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. + * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. + */ +RESOURCE(res_hello, + "title=\"Hello world: ?len=0..\";rt=\"Text\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + const char *len = NULL; + /* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */ + char const *const message = "Hello World! ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"; + int length = 12; /* |<-------->| */ + + /* The query string can be retrieved by rest_get_query() or parsed for its key-value pairs. */ + if(REST.get_query_variable(request, "len", &len)) { + length = atoi(len); + if(length < 0) { + length = 0; + } + if(length > REST_MAX_CHUNK_SIZE) { + length = REST_MAX_CHUNK_SIZE; + } + memcpy(buffer, message, length); + } else { + memcpy(buffer, message, length); + } REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ + REST.set_header_etag(response, (uint8_t *)&length, 1); + REST.set_response_payload(response, buffer, length); +} diff --git a/examples/er-rest-example/resources/res-leds.c b/examples/er-rest-example/resources/res-leds.c old mode 100755 new mode 100644 index 32d2aab6b..5fbcf6c77 --- a/examples/er-rest-example/resources/res-leds.c +++ b/examples/er-rest-example/resources/res-leds.c @@ -1,104 +1,108 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include "contiki.h" - -#if PLATFORM_HAS_LEDS - -#include -#include "rest-engine.h" -#include "dev/leds.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -static void res_post_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ -RESOURCE(res_leds, - "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\"", - NULL, - res_post_put_handler, - res_post_put_handler, - NULL); - -static void -res_post_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *color = NULL; - const char *mode = NULL; - uint8_t led = 0; - int success = 1; - - if((len=REST.get_query_variable(request, "color", &color))) { - PRINTF("color %.*s\n", len, color); - - if(strncmp(color, "r", len)==0) { - led = LEDS_RED; - } else if(strncmp(color,"g", len)==0) { - led = LEDS_GREEN; - } else if(strncmp(color,"b", len)==0) { - led = LEDS_BLUE; - } else { - success = 0; - } - } else { - success = 0; - } - - if(success && (len=REST.get_post_variable(request, "mode", &mode))) { - PRINTF("mode %s\n", mode); - - if(strncmp(mode, "on", len)==0) { - leds_on(led); - } else if(strncmp(mode, "off", len)==0) { - leds_off(led); - } else { - success = 0; - } - } else { - success = 0; - } - - if(!success) { - REST.set_response_status(response, REST.status.BAD_REQUEST); - } -} - -#endif /* PLATFORM_HAS_LEDS */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LEDS + +#include +#include "rest-engine.h" +#include "dev/leds.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +static void res_post_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ +RESOURCE(res_leds, + "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\"", + NULL, + res_post_put_handler, + res_post_put_handler, + NULL); + +static void +res_post_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *color = NULL; + const char *mode = NULL; + uint8_t led = 0; + int success = 1; + + if((len = REST.get_query_variable(request, "color", &color))) { + PRINTF("color %.*s\n", len, color); + + if(strncmp(color, "r", len) == 0) { + led = LEDS_RED; + } else if(strncmp(color, "g", len) == 0) { + led = LEDS_GREEN; + } else if(strncmp(color, "b", len) == 0) { + led = LEDS_BLUE; + } else { + success = 0; + } + } else { + success = 0; + } if(success && (len = REST.get_post_variable(request, "mode", &mode))) { + PRINTF("mode %s\n", mode); + + if(strncmp(mode, "on", len) == 0) { + leds_on(led); + } else if(strncmp(mode, "off", len) == 0) { + leds_off(led); + } else { + success = 0; + } + } else { + success = 0; + } if(!success) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } +} +#endif /* PLATFORM_HAS_LEDS */ diff --git a/examples/er-rest-example/resources/res-light.c b/examples/er-rest-example/resources/res-light.c old mode 100755 new mode 100644 index d7a07ea8c..226d814bb --- a/examples/er-rest-example/resources/res-light.c +++ b/examples/er-rest-example/resources/res-light.c @@ -1,88 +1,87 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include "contiki.h" - -#if PLATFORM_HAS_LIGHT - -#include -#include "rest-engine.h" -#include "dev/light-sensor.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(res_light, - "title=\"Photosynthetic and solar light (supports JSON)\";rt=\"LightSensor\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); - uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR); - - unsigned int accept = -1; - REST.get_header_accept(request, &accept); - - if(accept==-1 || accept==REST.type.TEXT_PLAIN) { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%u;%u", light_photosynthetic, light_solar); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept==REST.type.APPLICATION_XML) { - REST.set_header_content_type(response, REST.type.APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "", light_photosynthetic, light_solar); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } else if(accept==REST.type.APPLICATION_JSON) { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'light':{'photosynthetic':%u,'solar':%u}}", light_photosynthetic, light_solar); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } else { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain, application/xml, and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } -} - -#endif /* PLATFORM_HAS_LIGHT */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LIGHT + +#include +#include "rest-engine.h" +#include "dev/light-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading from light sensor with a simple etag */ +RESOURCE(res_light, + "title=\"Photosynthetic and solar light (supports JSON)\";rt=\"LightSensor\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); + uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR); + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%u;%u", light_photosynthetic, light_solar); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_XML) { + REST.set_header_content_type(response, REST.type.APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "", light_photosynthetic, light_solar); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'light':{'photosynthetic':%u,'solar':%u}}", light_photosynthetic, light_solar); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain, application/xml, and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_LIGHT */ diff --git a/examples/er-rest-example/resources/res-mirror.c b/examples/er-rest-example/resources/res-mirror.c old mode 100755 new mode 100644 index 0aae3125d..e33bda6d3 --- a/examples/er-rest-example/resources/res-mirror.c +++ b/examples/er-rest-example/resources/res-mirror.c @@ -1,177 +1,177 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" - -#define DEBUG DEBUG_NONE -#include "net/uip-debug.h" - -static void res_any_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ -RESOURCE(res_mirror, - "title=\"Returns your decoded message\";rt=\"Debug\"", - res_any_handler, - res_any_handler, - res_any_handler, - res_any_handler); - -static void -res_any_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* The ETag and Token is copied to the header. */ - uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; - - /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ - static char location[] = {'/','f','/','a','?','k','&','e', 0}; - - /* No default my be assumed for the Content-Format. (Unsigned -1 means all bits set.) */ - unsigned int content_format = -1; - - /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ - uint32_t longint = 0; - const char *str = NULL; - const uint8_t *bytes = NULL; - uint32_t block_num = 0; - uint8_t block_more = 0; - uint16_t block_size = 0; - int len = 0; - - /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ - - int strpos = 0; - /* snprintf() counts the terminating '\0' to the size parameter. - * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. - * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ - if(REST.get_header_content_type(request, &content_format)) { - strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE+1, "CF %u\n", content_format); - } - if(strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_accept(request, &content_format))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ac %u\n", content_format); - } - - /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. - * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ - if(strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &longint)) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "MA %lu\n", longint); - } - /* For HTTP this is the Length option, for CoAP it is the Size option. */ - if(strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &longint)) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "SZ %lu\n", longint); - } - - if(strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UH %.*s\n", len, str); - } - if(strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_url(request, &str))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UP %.*s\n", len, str); - } - if(strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &str))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UQ %.*s\n", len, str); - } - - /* Undefined request options for debugging: actions not required for normal RESTful Web service. */ - if(strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LP %.*s\n", len, str); - } - if(strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LQ %.*s\n", len, str); - } - - /* CoAP-specific example: actions not required for normal RESTful Web service. */ - coap_packet_t *const coap_pkt = (coap_packet_t *) request; - - if(strpos<=REST_MAX_CHUNK_SIZE && coap_pkt->token_len>0) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "To 0x"); - int index = 0; - for(index = 0; indextoken_len; ++index) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", coap_pkt->token[index]); - } - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); - } - - if(strpos<=REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ob %lu\n", coap_pkt->observe); - } - if(strpos<=REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ET 0x"); - int index = 0; - for(index = 0; indexetag_len; ++index) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", coap_pkt->etag[index]); - } - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); - } - if(strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) { /* This getter allows NULL pointers to get only a subset of the block parameters. */ - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); - } - if(strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); - } - - - if(strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes))) { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s", len, bytes); - } - - - if(strpos >= REST_MAX_CHUNK_SIZE) { - buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* '»' to indicate truncation */ - } - - REST.set_response_payload(response, buffer, strpos); - - PRINTF("/mirror options received: %s\n", buffer); - - /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ - REST.set_header_etag(response, opaque, 2); - REST.set_header_location(response, location); /* Initial slash is omitted by framework */ - REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ - -/* CoAP-specific example: actions not required for normal RESTful Web service. */ - coap_set_header_uri_host(response, "tiki"); - coap_set_header_observe(response, 10); - coap_set_header_proxy_uri(response, "ftp://x"); - coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ - coap_set_header_block1(response, 23, 0, 16); - coap_set_header_accept(response, TEXT_PLAIN); - coap_set_header_if_none_match(response); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +#define DEBUG 0 +#if DEBUG +#include +#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 + +static void res_any_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ +RESOURCE(res_mirror, + "title=\"Returns your decoded message\";rt=\"Debug\"", + res_any_handler, + res_any_handler, + res_any_handler, + res_any_handler); + +static void +res_any_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* The ETag and Token is copied to the header. */ + uint8_t opaque[] = { 0x0A, 0xBC, 0xDE }; + + /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ + static char location[] = { '/', 'f', '/', 'a', '?', 'k', '&', 'e', 0 }; + + /* No default my be assumed for the Content-Format. (Unsigned -1 means all bits set.) */ + unsigned int content_format = -1; + + /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ + uint32_t longint = 0; + const char *str = NULL; + const uint8_t *bytes = NULL; + uint32_t block_num = 0; + uint8_t block_more = 0; + uint16_t block_size = 0; + int len = 0; + + /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ + + int strpos = 0; + /* snprintf() counts the terminating '\0' to the size parameter. + * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. + * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ + if(REST.get_header_content_type(request, &content_format)) { + strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE + 1, "CF %u\n", content_format); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_header_accept(request, &content_format))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ac %u\n", content_format); + /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. + * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "MA %lu\n", longint); + /* For HTTP this is the Length option, for CoAP it is the Size option. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "SZ %lu\n", longint); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UH %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_url(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UQ %.*s\n", len, str); + /* Undefined request options for debugging: actions not required for normal RESTful Web service. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LQ %.*s\n", len, str); + /* CoAP-specific example: actions not required for normal RESTful Web service. */ + } + coap_packet_t *const coap_pkt = (coap_packet_t *)request; + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_pkt->token_len > 0) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "To 0x"); + int index = 0; + for(index = 0; index < coap_pkt->token_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->token[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + + if(strpos <= REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ob %lu\n", coap_pkt->observe); + } + if(strpos <= REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "ET 0x"); + int index = 0; + for(index = 0; index < coap_pkt->etag_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->etag[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) { /* This getter allows NULL pointers to get only a subset of the block parameters. */ + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%.*s", len, bytes); + } + if(strpos >= REST_MAX_CHUNK_SIZE) { + buffer[REST_MAX_CHUNK_SIZE - 1] = 0xBB; /* '»' to indicate truncation */ + } + REST.set_response_payload(response, buffer, strpos); + + PRINTF("/mirror options received: %s\n", buffer); + + /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ + REST.set_header_etag(response, opaque, 2); + REST.set_header_location(response, location); /* Initial slash is omitted by framework */ + REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ + +/* CoAP-specific example: actions not required for normal RESTful Web service. */ + coap_set_header_uri_host(response, "tiki"); + coap_set_header_observe(response, 10); + coap_set_header_proxy_uri(response, "ftp://x"); + coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ + coap_set_header_block1(response, 23, 0, 16); + coap_set_header_accept(response, TEXT_PLAIN); + coap_set_header_if_none_match(response); +} diff --git a/examples/er-rest-example/resources/res-plugtest-create1.c b/examples/er-rest-example/resources/res-plugtest-create1.c old mode 100755 new mode 100644 index d7edf0572..4ba5f6181 --- a/examples/er-rest-example/resources/res-plugtest-create1.c +++ b/examples/er-rest-example/resources/res-plugtest-create1.c @@ -1,81 +1,80 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_create1, - "title=\"Creates on PUT\"", - NULL, - NULL, - res_put_handler, - res_delete_handler); - -static uint8_t create1_exists = 0; - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/create1 PUT"); - - if(coap_get_header_if_none_match(request)) { - if(!create1_exists) { - REST.set_response_status(response, REST.status.CREATED); - - create1_exists = 1; - } else { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } else { - REST.set_response_status(response, REST.status.CHANGED); - } -} - -static void -res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/create1 DELETE "); - REST.set_response_status(response, REST.status.DELETED); - - create1_exists = 0; -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create1, + "title=\"Creates on PUT\"", + NULL, + NULL, + res_put_handler, + res_delete_handler); + +static uint8_t create1_exists = 0; + +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create1 PUT"); + + if(coap_get_header_if_none_match(request)) { + if(!create1_exists) { + REST.set_response_status(response, REST.status.CREATED); + + create1_exists = 1; + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } + } else { + REST.set_response_status(response, REST.status.CHANGED); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create1 DELETE "); + REST.set_response_status(response, REST.status.DELETED); + + create1_exists = 0; +} diff --git a/examples/er-rest-example/resources/res-plugtest-create2.c b/examples/er-rest-example/resources/res-plugtest-create2.c old mode 100755 new mode 100644 index a0a3462e6..25877ac70 --- a/examples/er-rest-example/resources/res-plugtest-create2.c +++ b/examples/er-rest-example/resources/res-plugtest-create2.c @@ -1,60 +1,60 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_create2, - "title=\"Creates on POST\"", - NULL, - res_post_handler, - NULL, - NULL); - -static void -res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/create2 "); - - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/location1/location2/location3"); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create2, + "title=\"Creates on POST\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create2 "); + + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/location1/location2/location3"); +} diff --git a/examples/er-rest-example/resources/res-plugtest-create3.c b/examples/er-rest-example/resources/res-plugtest-create3.c old mode 100755 new mode 100644 index 219871252..2498c065a --- a/examples/er-rest-example/resources/res-plugtest-create3.c +++ b/examples/er-rest-example/resources/res-plugtest-create3.c @@ -1,81 +1,80 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_create3, - "title=\"Default test resource\"", - NULL, - NULL, - res_put_handler, - res_delete_handler); - -static uint8_t create3_exists = 0; - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/create3 PUT "); - - if(coap_get_header_if_none_match(request)) { - if(!create3_exists) { - REST.set_response_status(response, REST.status.CREATED); - - create3_exists = 1; - } else { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } else { - REST.set_response_status(response, REST.status.CHANGED); - } -} - -static void -res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/create3 DELETE "); - REST.set_response_status(response, REST.status.DELETED); - - create3_exists = 0; -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create3, + "title=\"Default test resource\"", + NULL, + NULL, + res_put_handler, + res_delete_handler); + +static uint8_t create3_exists = 0; + +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create3 PUT "); + + if(coap_get_header_if_none_match(request)) { + if(!create3_exists) { + REST.set_response_status(response, REST.status.CREATED); + + create3_exists = 1; + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } + } else { + REST.set_response_status(response, REST.status.CHANGED); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create3 DELETE "); + REST.set_response_status(response, REST.status.DELETED); + + create3_exists = 0; +} diff --git a/examples/er-rest-example/resources/res-plugtest-large-create.c b/examples/er-rest-example/resources/res-plugtest-large-create.c old mode 100755 new mode 100644 index ae74a24f8..888dfaa31 --- a/examples/er-rest-example/resources/res-plugtest-large-create.c +++ b/examples/er-rest-example/resources/res-plugtest-large-create.c @@ -1,91 +1,91 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* - * Large resource that can be created using POST method - */ -RESOURCE(res_plugtest_large_create, - "title=\"Large resource that can be created using POST method\";rt=\"block\"", - NULL, - res_post_handler, - NULL, - NULL); - -static void -res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - uint8_t *incoming = NULL; - size_t len = 0; - - unsigned int ct = -1; - - if(!REST.get_header_content_type(request, &ct)) { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoContentType"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - if((len = REST.get_request_payload(request, (const uint8_t **) &incoming))) { - if(coap_req->block1_num * coap_req->block1_size + len <= 2048) { - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/nirvana"); - coap_set_header_block1(response, coap_req->block1_num, 0, - coap_req->block1_size); - } else { - REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); - const char *error_msg = "2048B max."; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - } else { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoPayload"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * Large resource that can be created using POST method + */ +RESOURCE(res_plugtest_large_create, + "title=\"Large resource that can be created using POST method\";rt=\"block\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + uint8_t *incoming = NULL; + size_t len = 0; + + unsigned int ct = -1; + + if(!REST.get_header_content_type(request, &ct)) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) { + if(coap_req->block1_num * coap_req->block1_size + len <= 2048) { + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/nirvana"); + coap_set_header_block1(response, coap_req->block1_num, 0, + coap_req->block1_size); + } else { + REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); + const char *error_msg = "2048B max."; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } +} diff --git a/examples/er-rest-example/resources/res-plugtest-large-update.c b/examples/er-rest-example/resources/res-plugtest-large-update.c old mode 100755 new mode 100644 index 2627572e5..e48d08b5f --- a/examples/er-rest-example/resources/res-plugtest-large-update.c +++ b/examples/er-rest-example/resources/res-plugtest-large-update.c @@ -1,128 +1,127 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE( - res_plugtest_large_update, - "title=\"Large resource that can be updated using PUT method\";rt=\"block\";sz=\"" TO_STRING(MAX_PLUGFEST_BODY) "\"", - res_get_handler, - NULL, - res_put_handler, - NULL); - -static int32_t large_update_size = 0; -static uint8_t large_update_store[MAX_PLUGFEST_BODY] = { 0 }; -static unsigned int large_update_ct = APPLICATION_OCTET_STREAM; - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* Check the offset for boundaries of the resource data. */ - if(*offset >= large_update_size) { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - REST.set_response_payload(response, large_update_store + *offset, - MIN(large_update_size - *offset, preferred_size)); - REST.set_header_content_type(response, large_update_ct); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += preferred_size; - - /* Signal end of resource representation. */ - if(*offset >= large_update_size) { - *offset = -1; - } -} - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - uint8_t *incoming = NULL; - size_t len = 0; - - unsigned int ct = -1; - - if(!REST.get_header_content_type(request, &ct)) { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoContentType"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - if((len = REST.get_request_payload(request, (const uint8_t **) &incoming))) { - if(coap_req->block1_num * coap_req->block1_size + len <= sizeof(large_update_store)) { - memcpy( - large_update_store + coap_req->block1_num * coap_req->block1_size, - incoming, len); - large_update_size = coap_req->block1_num * coap_req->block1_size + len; - large_update_ct = ct; - - REST.set_response_status(response, REST.status.CHANGED); - coap_set_header_block1(response, coap_req->block1_num, 0, - coap_req->block1_size); - } else { - REST.set_response_status(response, - REST.status.REQUEST_ENTITY_TOO_LARGE); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", - sizeof(large_update_store))); - return; - } - } else { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoPayload"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE( + res_plugtest_large_update, + "title=\"Large resource that can be updated using PUT method\";rt=\"block\";sz=\"" TO_STRING(MAX_PLUGFEST_BODY) "\"", + res_get_handler, + NULL, + res_put_handler, + NULL); + +static int32_t large_update_size = 0; +static uint8_t large_update_store[MAX_PLUGFEST_BODY] = { 0 }; +static unsigned int large_update_ct = APPLICATION_OCTET_STREAM; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Check the offset for boundaries of the resource data. */ + if(*offset >= large_update_size) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + REST.set_response_payload(response, large_update_store + *offset, + MIN(large_update_size - *offset, preferred_size)); + REST.set_header_content_type(response, large_update_ct); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += preferred_size; + + /* Signal end of resource representation. */ + if(*offset >= large_update_size) { + *offset = -1; + } +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + uint8_t *incoming = NULL; + size_t len = 0; + + unsigned int ct = -1; + + if(!REST.get_header_content_type(request, &ct)) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) { + if(coap_req->block1_num * coap_req->block1_size + len <= sizeof(large_update_store)) { + memcpy( + large_update_store + coap_req->block1_num * coap_req->block1_size, + incoming, len); + large_update_size = coap_req->block1_num * coap_req->block1_size + len; + large_update_ct = ct; + + REST.set_response_status(response, REST.status.CHANGED); + coap_set_header_block1(response, coap_req->block1_num, 0, + coap_req->block1_size); + } else { + REST.set_response_status(response, + REST.status.REQUEST_ENTITY_TOO_LARGE); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", + sizeof(large_update_store))); + return; + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } +} diff --git a/examples/er-rest-example/resources/res-plugtest-large.c b/examples/er-rest-example/resources/res-plugtest-large.c old mode 100755 new mode 100644 index 389c9224c..d997dd927 --- a/examples/er-rest-example/resources/res-plugtest-large.c +++ b/examples/er-rest-example/resources/res-plugtest-large.c @@ -1,94 +1,92 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_large, - "title=\"Large resource\";rt=\"block\";sz=\"" TO_STRING(CHUNKS_TOTAL) "\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int32_t strpos = 0; - - /* Check the offset for boundaries of the resource data. */ - if(*offset >= CHUNKS_TOTAL) { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - /* Generate data until reaching CHUNKS_TOTAL. */ - while(strpos < preferred_size) { - strpos += snprintf((char *) buffer + strpos, preferred_size - strpos + 1, - "|%ld|", *offset); - } - - /* snprintf() does not adjust return value if truncated by size. */ - if(strpos > preferred_size) { - strpos = preferred_size; - } - - /* Truncate if above CHUNKS_TOTAL bytes. */ - if(*offset + (int32_t) strpos > CHUNKS_TOTAL) { - strpos = CHUNKS_TOTAL - *offset; - } - - REST.set_response_payload(response, buffer, strpos); - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += strpos; - - /* Signal end of resource representation. */ - if(*offset >= CHUNKS_TOTAL) { - *offset = -1; - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_large, + "title=\"Large resource\";rt=\"block\";sz=\"" TO_STRING(CHUNKS_TOTAL) "\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if(*offset >= CHUNKS_TOTAL) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while(strpos < preferred_size) { + strpos += snprintf((char *)buffer + strpos, preferred_size - strpos + 1, + "|%ld|", *offset); + } + + /* snprintf() does not adjust return value if truncated by size. */ + if(strpos > preferred_size) { + strpos = preferred_size; + /* Truncate if above CHUNKS_TOTAL bytes. */ + } + if(*offset + (int32_t)strpos > CHUNKS_TOTAL) { + strpos = CHUNKS_TOTAL - *offset; + } + REST.set_response_payload(response, buffer, strpos); + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if(*offset >= CHUNKS_TOTAL) { + *offset = -1; + } +} diff --git a/examples/er-rest-example/resources/res-plugtest-links.c b/examples/er-rest-example/resources/res-plugtest-links.c old mode 100755 new mode 100644 index ec583038e..be68aadf7 --- a/examples/er-rest-example/resources/res-plugtest-links.c +++ b/examples/er-rest-example/resources/res-plugtest-links.c @@ -1,71 +1,71 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_link1, - "rt=\"Type1 Type2\";if=\"If1\"", - res_get_handler, - NULL, - NULL, - NULL); -RESOURCE(res_plugtest_link2, - "rt=\"Type2 Type3\";if=\"If2\"", - res_get_handler, - NULL, - NULL, - NULL); -RESOURCE(res_plugtest_link3, - "rt=\"Type1 Type3\";if=\"foo\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - const char *msg = "Dummy link"; - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, msg, strlen(msg)); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_link1, + "rt=\"Type1 Type2\";if=\"If1\"", + res_get_handler, + NULL, + NULL, + NULL); +RESOURCE(res_plugtest_link2, + "rt=\"Type2 Type3\";if=\"If2\"", + res_get_handler, + NULL, + NULL, + NULL); +RESOURCE(res_plugtest_link3, + "rt=\"Type1 Type3\";if=\"foo\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + const char *msg = "Dummy link"; + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, msg, strlen(msg)); +} diff --git a/examples/er-rest-example/resources/res-plugtest-locquery.c b/examples/er-rest-example/resources/res-plugtest-locquery.c old mode 100755 new mode 100644 index 8f701eb28..64e79ff25 --- a/examples/er-rest-example/resources/res-plugtest-locquery.c +++ b/examples/er-rest-example/resources/res-plugtest-locquery.c @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_locquery, - "title=\"Resource accepting query parameters\"", - NULL, - res_post_handler, - NULL, - NULL); - -static void -res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF( - "/location-query POST (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "?first=1&second=2"); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_locquery, + "title=\"Resource accepting query parameters\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF( + "/location-query POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "?first=1&second=2"); +} diff --git a/examples/er-rest-example/resources/res-plugtest-longpath.c b/examples/er-rest-example/resources/res-plugtest-longpath.c old mode 100755 new mode 100644 index 71c354595..d6c4fb855 --- a/examples/er-rest-example/resources/res-plugtest-longpath.c +++ b/examples/er-rest-example/resources/res-plugtest-longpath.c @@ -1,68 +1,68 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_longpath, - "title=\"Long path resource\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/seg1/seg2/seg3 GET "); - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_longpath, + "title=\"Long path resource\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/seg1/seg2/seg3 GET "); + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); +} diff --git a/examples/er-rest-example/resources/res-plugtest-multi.c b/examples/er-rest-example/resources/res-plugtest-multi.c old mode 100755 new mode 100644 index 3f491c7e9..281a2268f --- a/examples/er-rest-example/resources/res-plugtest-multi.c +++ b/examples/er-rest-example/resources/res-plugtest-multi.c @@ -1,87 +1,87 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_multi, - "title=\"Resource providing text/plain and application/xml\";ct=\"0 41\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - unsigned int accept = -1; - REST.get_header_accept(request, &accept); - - PRINTF("/multi-format GET (%s %u) ", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if(accept == -1 || accept == REST.type.TEXT_PLAIN) { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, - coap_req->mid, accept != -1 ? "\nAccept: 0" : "")); - PRINTF("PLAIN\n"); - } else if(accept == REST.type.APPLICATION_XML) { - REST.set_header_content_type(response, REST.type.APPLICATION_XML); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - "", - coap_req->type, coap_req->code, coap_req->mid, accept)); - PRINTF("XML\n"); - } else { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/xml"; - REST.set_response_payload(response, msg, strlen(msg)); - PRINTF("ERROR\n"); - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_multi, + "title=\"Resource providing text/plain and application/xml\";ct=\"0 41\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + PRINTF("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, + coap_req->mid, accept != -1 ? "\nAccept: 0" : "")); + PRINTF("PLAIN\n"); + } else if(accept == REST.type.APPLICATION_XML) { + REST.set_header_content_type(response, REST.type.APPLICATION_XML); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "", + coap_req->type, coap_req->code, coap_req->mid, accept)); + PRINTF("XML\n"); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/xml"; + REST.set_response_payload(response, msg, strlen(msg)); + PRINTF("ERROR\n"); + } +} diff --git a/examples/er-rest-example/resources/res-plugtest-obs.c b/examples/er-rest-example/resources/res-plugtest-obs.c old mode 100755 new mode 100644 index f1a0c49bc..e202c2043 --- a/examples/er-rest-example/resources/res-plugtest-obs.c +++ b/examples/er-rest-example/resources/res-plugtest-obs.c @@ -1,161 +1,155 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-coap-observe.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_periodic_handler(void); - -PERIODIC_RESOURCE(res_plugtest_obs, - "title=\"Observable resource which changes every 5 seconds\";obs", - res_get_handler, - NULL, - res_put_handler, - res_delete_handler, - 5*CLOCK_SECOND, - res_periodic_handler); - -static int32_t obs_counter = 0; -static char obs_content[MAX_PLUGFEST_BODY]; -static size_t obs_content_len = 0; -static unsigned int obs_format = 0; - -static char obs_status = 0; - -static void -obs_purge_list() -{ - PRINTF("### SERVER ACTION ### Purging obs list"); - coap_remove_observer_by_uri(NULL, 0, res_plugtest_obs.url); -} - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* Keep server log clean from ticking events */ - if(request != NULL) { - PRINTF("/obs GET\n"); - } - - REST.set_header_content_type(response, obs_format); - REST.set_header_max_age(response, 5); - - if(obs_content_len) { - REST.set_header_content_type(response, obs_format); - REST.set_response_payload(response, obs_content, obs_content_len); - } else { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, obs_content, - snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter)); - } - /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ -} - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint8_t *incoming = NULL; - unsigned int ct = -1; - - REST.get_header_content_type(request, &ct); - - PRINTF("/obs PUT\n"); - - if(ct != obs_format) { - obs_status = 1; - obs_format = ct; - } else { - obs_content_len = REST.get_request_payload(request, - (const uint8_t **) &incoming); - memcpy(obs_content, incoming, obs_content_len); - res_periodic_handler(); - } - - REST.set_response_status(response, REST.status.CHANGED); -} - -static void -res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - PRINTF("/obs DELETE\n"); - - obs_status = 2; - - REST.set_response_status(response, REST.status.DELETED); -} - -/* - * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. - * It will be called by the REST manager process with the defined period. - */ -static void -res_periodic_handler() -{ - ++obs_counter; - - //PRINTF("TICK %u for /%s\n", obs_counter, r->url); - - if(obs_status == 1) { - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(&res_plugtest_obs); - - PRINTF("######### sending 5.00\n"); - - obs_purge_list(); - } else if(obs_status == 2) { - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(&res_plugtest_obs); - - obs_purge_list(); - - obs_counter = 0; - obs_content_len = 0; - } else { - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(&res_plugtest_obs); - } - obs_status = 0; -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-coap-observe.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_periodic_handler(void); + +PERIODIC_RESOURCE(res_plugtest_obs, + "title=\"Observable resource which changes every 5 seconds\";obs", + res_get_handler, + NULL, + res_put_handler, + res_delete_handler, + 5 * CLOCK_SECOND, + res_periodic_handler); + +static int32_t obs_counter = 0; +static char obs_content[MAX_PLUGFEST_BODY]; +static size_t obs_content_len = 0; +static unsigned int obs_format = 0; + +static char obs_status = 0; + +static void +obs_purge_list() +{ + PRINTF("### SERVER ACTION ### Purging obs list"); + coap_remove_observer_by_uri(NULL, 0, res_plugtest_obs.url); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Keep server log clean from ticking events */ + if(request != NULL) { + PRINTF("/obs GET\n"); + } + REST.set_header_content_type(response, obs_format); + REST.set_header_max_age(response, 5); + + if(obs_content_len) { + REST.set_header_content_type(response, obs_format); + REST.set_response_payload(response, obs_content, obs_content_len); + } else { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, obs_content, + snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter)); + } + /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + uint8_t *incoming = NULL; + unsigned int ct = -1; + + REST.get_header_content_type(request, &ct); + + PRINTF("/obs PUT\n"); + + if(ct != obs_format) { + obs_status = 1; + obs_format = ct; + } else { + obs_content_len = REST.get_request_payload(request, + (const uint8_t **)&incoming); + memcpy(obs_content, incoming, obs_content_len); + res_periodic_handler(); + } + + REST.set_response_status(response, REST.status.CHANGED); +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/obs DELETE\n"); + + obs_status = 2; + + REST.set_response_status(response, REST.status.DELETED); +} +/* + * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. + * It will be called by the REST manager process with the defined period. + */ +static void +res_periodic_handler() +{ + ++obs_counter; + + /* PRINTF("TICK %u for /%s\n", obs_counter, r->url); */ + + if(obs_status == 1) { + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + + PRINTF("######### sending 5.00\n"); + + obs_purge_list(); + } else if(obs_status == 2) { + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + + obs_purge_list(); + + obs_counter = 0; + obs_content_len = 0; + } else { + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + } obs_status = 0; +} diff --git a/examples/er-rest-example/resources/res-plugtest-path.c b/examples/er-rest-example/resources/res-plugtest-path.c old mode 100755 new mode 100644 index 62cb9eef6..3566a51b9 --- a/examples/er-rest-example/resources/res-plugtest-path.c +++ b/examples/er-rest-example/resources/res-plugtest-path.c @@ -1,72 +1,72 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -PARENT_RESOURCE(res_plugtest_path, - "title=\"Path test resource\";ct=\"40\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, - uint16_t preferred_size, int32_t *offset) -{ - - const char *uri_path = NULL; - int len = REST.get_url(request, &uri_path); - int base_len = strlen(res_plugtest_path.url); - - if(len == base_len) { - REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT); - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - ",,"); - } else { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, "/%.*s", len, uri_path); - } - - REST.set_response_payload(response, buffer, strlen((char *) buffer)); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +PARENT_RESOURCE(res_plugtest_path, + "title=\"Path test resource\";ct=\"40\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + + const char *uri_path = NULL; + int len = REST.get_url(request, &uri_path); + int base_len = strlen(res_plugtest_path.url); + + if(len == base_len) { + REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT); + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + ",,"); + } else { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "/%.*s", len, uri_path); + } + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); +} diff --git a/examples/er-rest-example/resources/res-plugtest-query.c b/examples/er-rest-example/resources/res-plugtest-query.c old mode 100755 new mode 100644 index a7390555f..f0633854a --- a/examples/er-rest-example/resources/res-plugtest-query.c +++ b/examples/er-rest-example/resources/res-plugtest-query.c @@ -1,75 +1,74 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_query, - "title=\"Resource accepting query parameters\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - int len = 0; - const char *query = NULL; - - PRINTF( - "/query GET (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if((len = REST.get_query(request, &query))) { - PRINTF("Query: %.*s\n", len, query); - } - - /* Code 2.05 CONTENT is default. */REST.set_header_content_type(response, - REST.type.TEXT_PLAIN); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - "Type: %u\nCode: %u\nMID: %u\nQuery: %.*s", coap_req->type, - coap_req->code, coap_req->mid, len, query)); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_query, + "title=\"Resource accepting query parameters\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + int len = 0; + const char *query = NULL; + + PRINTF( + "/query GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = REST.get_query(request, &query))) { + PRINTF("Query: %.*s\n", len, query); + } /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, + REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u\nQuery: %.*s", coap_req->type, + coap_req->code, coap_req->mid, len, query)); +} diff --git a/examples/er-rest-example/resources/res-plugtest-separate.c b/examples/er-rest-example/resources/res-plugtest-separate.c old mode 100755 new mode 100644 index 31989e667..a32311bba --- a/examples/er-rest-example/resources/res-plugtest-separate.c +++ b/examples/er-rest-example/resources/res-plugtest-separate.c @@ -1,135 +1,133 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-coap-transactions.h" -#include "er-coap-separate.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_resume_handler(void); - -PERIODIC_RESOURCE(res_plugtest_separate, - "title=\"Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way\"", - res_get_handler, - NULL, - NULL, - NULL, - 3*CLOCK_SECOND, - res_resume_handler); - -/* A structure to store the required information */ -typedef struct application_separate_store -{ - /* Provided by Erbium to store generic request information such as remote address and token. */ - coap_separate_t request_metadata; - /* Add fields for addition information to be stored for finalizing, e.g.: */ - char buffer[MAX_PLUGFEST_PAYLOAD]; -} application_separate_store_t; - -static uint8_t separate_active = 0; -static application_separate_store_t separate_store[1]; - -void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/separate "); - if(separate_active) { - PRINTF("REJECTED "); - coap_separate_reject(); - } else { - PRINTF("STORED "); - separate_active = 1; - - /* Take over and skip response by engine. */ - coap_separate_accept(request, &separate_store->request_metadata); - /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ - - snprintf(separate_store->buffer, MAX_PLUGFEST_PAYLOAD, - "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, - coap_req->mid); - } - - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} - -static void -res_resume_handler() -{ - if(separate_active) { - PRINTF("/separate "); - coap_transaction_t *transaction = NULL; - if((transaction = coap_new_transaction(separate_store->request_metadata.mid, - &separate_store->request_metadata.addr, - separate_store->request_metadata.port))) { - PRINTF( - "RESPONSE (%s %u)\n", separate_store->request_metadata.type==COAP_TYPE_CON?"CON":"NON", separate_store->request_metadata.mid); - - coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ - - /* Restore the request information for the response. */ - coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); - - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - coap_set_payload(response, separate_store->buffer, - strlen(separate_store->buffer)); - - /* - * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. - * As it is a critical option, this example resource pretends to handle it for compliance. - */ - coap_set_header_block2(response, - separate_store->request_metadata.block2_num, 0, - separate_store->request_metadata.block2_size); - - /* Warning: No check for serialization error. */ - transaction->packet_len = coap_serialize_message(response, - transaction->packet); - coap_send_transaction(transaction); - /* The engine will clear the transaction (right after send for NON, after acked for CON). */ - - separate_active = 0; - } else { - PRINTF("ERROR (transaction)\n"); - } - } /* if (separate_active) */ -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "er-coap-separate.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_resume_handler(void); + +PERIODIC_RESOURCE(res_plugtest_separate, + "title=\"Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way\"", + res_get_handler, + NULL, + NULL, + NULL, + 3 * CLOCK_SECOND, + res_resume_handler); + +/* A structure to store the required information */ +typedef struct application_separate_store { + /* Provided by Erbium to store generic request information such as remote address and token. */ + coap_separate_t request_metadata; + /* Add fields for addition information to be stored for finalizing, e.g.: */ + char buffer[MAX_PLUGFEST_PAYLOAD]; +} application_separate_store_t; + +static uint8_t separate_active = 0; +static application_separate_store_t separate_store[1]; + +void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/separate "); + if(separate_active) { + PRINTF("REJECTED "); + coap_separate_reject(); + } else { + PRINTF("STORED "); + separate_active = 1; + + /* Take over and skip response by engine. */ + coap_separate_accept(request, &separate_store->request_metadata); + /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ + + snprintf(separate_store->buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, + coap_req->mid); + } + + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); +} +static void +res_resume_handler() +{ + if(separate_active) { + PRINTF("/separate "); + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(separate_store->request_metadata.mid, + &separate_store->request_metadata.addr, + separate_store->request_metadata.port))) { + PRINTF( + "RESPONSE (%s %u)\n", separate_store->request_metadata.type == COAP_TYPE_CON ? "CON" : "NON", separate_store->request_metadata.mid); + + coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); + + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + coap_set_payload(response, separate_store->buffer, + strlen(separate_store->buffer)); + + /* + * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. + * As it is a critical option, this example resource pretends to handle it for compliance. + */ + coap_set_header_block2(response, + separate_store->request_metadata.block2_num, 0, + separate_store->request_metadata.block2_size); + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(response, + transaction->packet); + coap_send_transaction(transaction); + /* The engine will clear the transaction (right after send for NON, after acked for CON). */ + + separate_active = 0; + } else { + PRINTF("ERROR (transaction)\n"); + } + } /* if (separate_active) */ +} diff --git a/examples/er-rest-example/resources/res-plugtest-test.c b/examples/er-rest-example/resources/res-plugtest-test.c old mode 100755 new mode 100644 index 810526546..27bba1f3b --- a/examples/er-rest-example/resources/res-plugtest-test.c +++ b/examples/er-rest-example/resources/res-plugtest-test.c @@ -1,164 +1,159 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_test, "title=\"Default test resource\"", res_get_handler, res_post_handler, res_put_handler, res_delete_handler); - -static uint8_t test_etag[8] = { 0 }; -static uint8_t test_etag_len = 1; -static uint8_t test_change = 1; -static uint8_t test_none_match_okay = 1; - -static const uint8_t *bytes = NULL; -static size_t len = 0; - -static void -test_update_etag() -{ - int i; - test_etag_len = (random_rand() % 8) + 1; - for(i = 0; i < test_etag_len; ++i) { - test_etag[i] = random_rand(); - } - test_change = 0; - - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); -} - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - if(test_change) { - test_update_etag(); - } - - PRINTF("/test GET (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if((len = coap_get_header_etag(request, &bytes)) > 0 - && len == test_etag_len - && memcmp(test_etag, bytes, len) == 0) { - PRINTF("validate "); - REST.set_response_status(response, REST.status.NOT_MODIFIED); - REST.set_header_etag(response, test_etag, test_etag_len); - - test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); - } else { - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_etag(response, test_etag, test_etag_len); - REST.set_header_max_age(response, 30); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - } -} - -static void -res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/test POST (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/location1/location2/location3"); -} - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/test PUT (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if(coap_get_header_if_none_match(request)) { - if(test_none_match_okay) { - REST.set_response_status(response, REST.status.CREATED); - - test_none_match_okay = 0; - PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); - } else { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - - test_none_match_okay = 1; - PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); - } - } else if(((len = coap_get_header_if_match(request, &bytes)) > 0 - && (len == test_etag_len - && memcmp(test_etag, bytes, len) == 0)) - || len == 0) { - test_update_etag(); - REST.set_header_etag(response, test_etag, test_etag_len); - - REST.set_response_status(response, REST.status.CHANGED); - - if(len > 0) { - test_change = 1; - PRINTF("### SERVER ACTION ### Resource will change\n"); - } - } else { - PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - len, - test_etag_len, - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], - test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); - - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } -} - -static void -res_delete_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/test DELETE (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - REST.set_response_status(response, REST.status.DELETED); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_test, "title=\"Default test resource\"", res_get_handler, res_post_handler, res_put_handler, res_delete_handler); + +static uint8_t test_etag[8] = { 0 }; +static uint8_t test_etag_len = 1; +static uint8_t test_change = 1; +static uint8_t test_none_match_okay = 1; + +static const uint8_t *bytes = NULL; +static size_t len = 0; + +static void +test_update_etag() +{ + int i; + test_etag_len = (random_rand() % 8) + 1; + for(i = 0; i < test_etag_len; ++i) { + test_etag[i] = random_rand(); + } + test_change = 0; + + PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + if(test_change) { + test_update_etag(); + } + PRINTF("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = coap_get_header_etag(request, &bytes)) > 0 + && len == test_etag_len + && memcmp(test_etag, bytes, len) == 0) { + PRINTF("validate "); + REST.set_response_status(response, REST.status.NOT_MODIFIED); + REST.set_header_etag(response, test_etag, test_etag_len); + + test_change = 1; + PRINTF("### SERVER ACTION ### Resource will change\n"); + } else { + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_etag(response, test_etag, test_etag_len); + REST.set_header_max_age(response, 30); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + } +} +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/location1/location2/location3"); +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(coap_get_header_if_none_match(request)) { + if(test_none_match_okay) { + REST.set_response_status(response, REST.status.CREATED); + + test_none_match_okay = 0; + PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + + test_none_match_okay = 1; + PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); + } + } else if(((len = coap_get_header_if_match(request, &bytes)) > 0 + && (len == test_etag_len + && memcmp(test_etag, bytes, len) == 0)) + || len == 0) { + test_update_etag(); + REST.set_header_etag(response, test_etag, test_etag_len); + + REST.set_response_status(response, REST.status.CHANGED); + + if(len > 0) { + test_change = 1; + PRINTF("### SERVER ACTION ### Resource will change\n"); + } + } else { + PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + len, + test_etag_len, + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); + + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + REST.set_response_status(response, REST.status.DELETED); +} diff --git a/examples/er-rest-example/resources/res-plugtest-validate.c b/examples/er-rest-example/resources/res-plugtest-validate.c old mode 100755 new mode 100644 index 9dd10be41..b92ffe74d --- a/examples/er-rest-example/resources/res-plugtest-validate.c +++ b/examples/er-rest-example/resources/res-plugtest-validate.c @@ -1,141 +1,137 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * ETSI Plugtest resource - * \author - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" -#include "er-plugtest.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -RESOURCE(res_plugtest_validate, - "title=\"Validation test resource\"", - res_get_handler, - NULL, - res_put_handler, - NULL); - -static uint8_t validate_etag[8] = { 0 }; -static uint8_t validate_etag_len = 1; -static uint8_t validate_change = 1; - - -static const uint8_t *bytes = NULL; -static size_t len = 0; - -static void -validate_update_etag() -{ - int i; - validate_etag_len = (random_rand() % 8) + 1; - for(i = 0; i < validate_etag_len; ++i) { - validate_etag[i] = random_rand(); - } - validate_change = 0; - - PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", - validate_etag_len, validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); -} - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - if(validate_change) { - validate_update_etag(); - } - - PRINTF("/validate GET"); - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if((len = coap_get_header_etag(request, &bytes)) > 0 - && len == validate_etag_len && memcmp(validate_etag, bytes, len) == 0) { - PRINTF("validate "); - REST.set_response_status(response, REST.status.NOT_MODIFIED); - REST.set_header_etag(response, validate_etag, validate_etag_len); - - validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } else { - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_etag(response, validate_etag, validate_etag_len); - REST.set_header_max_age(response, 30); - REST.set_response_payload( - response, - buffer, - snprintf((char *) buffer, MAX_PLUGFEST_PAYLOAD, - "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, - coap_req->mid)); - } -} - -static void -res_put_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t * const coap_req = (coap_packet_t *) request; - - PRINTF("/validate PUT "); - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if(((len = coap_get_header_if_match(request, &bytes)) > 0 - && (len == validate_etag_len - && memcmp(validate_etag, bytes, len) == 0)) - || len == 0) { - validate_update_etag(); - REST.set_header_etag(response, validate_etag, validate_etag_len); - - REST.set_response_status(response, REST.status.CHANGED); - - if(len > 0) { - validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } - } else { - PRINTF( - "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", - len, - validate_etag_len, - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], - validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); - - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_validate, + "title=\"Validation test resource\"", + res_get_handler, + NULL, + res_put_handler, + NULL); + +static uint8_t validate_etag[8] = { 0 }; +static uint8_t validate_etag_len = 1; +static uint8_t validate_change = 1; + +static const uint8_t *bytes = NULL; +static size_t len = 0; + +static void +validate_update_etag() +{ + int i; + validate_etag_len = (random_rand() % 8) + 1; + for(i = 0; i < validate_etag_len; ++i) { + validate_etag[i] = random_rand(); + } + validate_change = 0; + + PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + validate_etag_len, validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + if(validate_change) { + validate_update_etag(); + } + PRINTF("/validate GET"); + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = coap_get_header_etag(request, &bytes)) > 0 + && len == validate_etag_len && memcmp(validate_etag, bytes, len) == 0) { + PRINTF("validate "); + REST.set_response_status(response, REST.status.NOT_MODIFIED); + REST.set_header_etag(response, validate_etag, validate_etag_len); + + validate_change = 1; + PRINTF("### SERVER ACTION ### Resouce will change\n"); + } else { + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_etag(response, validate_etag, validate_etag_len); + REST.set_header_max_age(response, 30); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, + coap_req->mid)); + } +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/validate PUT "); + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(((len = coap_get_header_if_match(request, &bytes)) > 0 + && (len == validate_etag_len + && memcmp(validate_etag, bytes, len) == 0)) + || len == 0) { + validate_update_etag(); + REST.set_header_etag(response, validate_etag, validate_etag_len); + + REST.set_response_status(response, REST.status.CHANGED); + + if(len > 0) { + validate_change = 1; + PRINTF("### SERVER ACTION ### Resouce will change\n"); + } + } else { + PRINTF( + "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", + len, + validate_etag_len, + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); + + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } +} diff --git a/examples/er-rest-example/resources/res-push.c b/examples/er-rest-example/resources/res-push.c old mode 100755 new mode 100644 index 65d342892..c169b407c --- a/examples/er-rest-example/resources/res-push.c +++ b/examples/er-rest-example/resources/res-push.c @@ -1,90 +1,89 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_periodic_handler(void); - -PERIODIC_RESOURCE(res_push, - "title=\"Periodic demo\";obs", - res_get_handler, - NULL, - NULL, - NULL, - 5*CLOCK_SECOND, - res_periodic_handler); - -/* - * Use local resource state that is accessed by res_get_handler() and altered by res_periodic_handler() or PUT or POST. - */ -static int32_t event_counter = 0; - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* - * For minimal complexity, request query and options should be ignored for GET on observable resources. - * Otherwise the requests must be stored with the observer list and passed by REST.notify_subscribers(). - * This would be a TODO in the corresponding files in contiki/apps/erbium/! - */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_max_age(response, res_push.periodic->period/CLOCK_SECOND); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "VERY LONG EVENT %lu", event_counter)); - - /* The REST.subscription_handler() will be called for observable resources by the REST framework. */ -} - -/* - * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. - * It will be called by the REST manager process with the defined period. - */ -static void -res_periodic_handler() -{ - /* Do a periodic task here, e.g., sampling a sensor. */ - ++event_counter; - - /* Usually a condition is defined under with subscribers are notified, e.g., large enough delta in sensor reading. */ - if(1) { - /* Notify the registered observers which will trigger the res_get_handler to create the response. */ - REST.notify_subscribers(&res_push); - } -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_periodic_handler(void); + +PERIODIC_RESOURCE(res_push, + "title=\"Periodic demo\";obs", + res_get_handler, + NULL, + NULL, + NULL, + 5 * CLOCK_SECOND, + res_periodic_handler); + +/* + * Use local resource state that is accessed by res_get_handler() and altered by res_periodic_handler() or PUT or POST. + */ +static int32_t event_counter = 0; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* + * For minimal complexity, request query and options should be ignored for GET on observable resources. + * Otherwise the requests must be stored with the observer list and passed by REST.notify_subscribers(). + * This would be a TODO in the corresponding files in contiki/apps/erbium/! + */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_max_age(response, res_push.periodic->period / CLOCK_SECOND); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "VERY LONG EVENT %lu", event_counter)); + + /* The REST.subscription_handler() will be called for observable resources by the REST framework. */ +} +/* + * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. + * It will be called by the REST manager process with the defined period. + */ +static void +res_periodic_handler() +{ + /* Do a periodic task here, e.g., sampling a sensor. */ + ++event_counter; + + /* Usually a condition is defined under with subscribers are notified, e.g., large enough delta in sensor reading. */ + if(1) { + /* Notify the registered observers which will trigger the res_get_handler to create the response. */ + REST.notify_subscribers(&res_push); + } +} diff --git a/examples/er-rest-example/resources/res-radio.c b/examples/er-rest-example/resources/res-radio.c old mode 100755 new mode 100644 index 17bcef9b0..ac09319a3 --- a/examples/er-rest-example/resources/res-radio.c +++ b/examples/er-rest-example/resources/res-radio.c @@ -1,106 +1,102 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include "contiki.h" - -#if PLATFORM_HAS_RADIO - -#include -#include "rest-engine.h" -#include "dev/radio-sensor.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* A simple getter example. Returns the reading of the rssi/lqi from radio sensor */ -RESOURCE(res_radio, - "title=\"RADIO: ?p=lqi|rssi\";rt=\"RadioSensor\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *p = NULL; - uint8_t param = 0; - int success = 1; - - unsigned int accept = -1; - REST.get_header_accept(request, &accept); - - if((len=REST.get_query_variable(request, "p", &p))) { - if(strncmp(p, "lqi", len)==0) { - param = RADIO_SENSOR_LAST_VALUE; - } else if(strncmp(p,"rssi", len)==0) { - param = RADIO_SENSOR_LAST_PACKET; - } else { - success = 0; - } - } else { - success = 0; - } - - if(success) { - if(accept==-1 || accept==REST.type.TEXT_PLAIN) { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", radio_sensor.value(param)); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } else if(accept==REST.type.APPLICATION_JSON) { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - - if(param == RADIO_SENSOR_LAST_VALUE) { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'lqi':%d}", radio_sensor.value(param)); - } else if(param == RADIO_SENSOR_LAST_PACKET) { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'rssi':%d}", radio_sensor.value(param)); - } - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } else { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } - } else { - REST.set_response_status(response, REST.status.BAD_REQUEST); - } -} - -#endif /* PLATFORM_HAS_RADIO */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_RADIO + +#include +#include "rest-engine.h" +#include "dev/radio-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading of the rssi/lqi from radio sensor */ +RESOURCE(res_radio, + "title=\"RADIO: ?p=lqi|rssi\";rt=\"RadioSensor\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *p = NULL; + uint8_t param = 0; + int success = 1; + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if((len = REST.get_query_variable(request, "p", &p))) { + if(strncmp(p, "lqi", len) == 0) { + param = RADIO_SENSOR_LAST_VALUE; + } else if(strncmp(p, "rssi", len) == 0) { + param = RADIO_SENSOR_LAST_PACKET; + } else { + success = 0; + } + } else { + success = 0; + } if(success) { + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", radio_sensor.value(param)); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + + if(param == RADIO_SENSOR_LAST_VALUE) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'lqi':%d}", radio_sensor.value(param)); + } else if(param == RADIO_SENSOR_LAST_PACKET) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'rssi':%d}", radio_sensor.value(param)); + } + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } +} +#endif /* PLATFORM_HAS_RADIO */ diff --git a/examples/er-rest-example/resources/res-separate.c b/examples/er-rest-example/resources/res-separate.c old mode 100755 new mode 100644 index 7fe8f6d95..bb2248c92 --- a/examples/er-rest-example/resources/res-separate.c +++ b/examples/er-rest-example/resources/res-separate.c @@ -1,129 +1,127 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" -#include "er-coap-separate.h" -#include "er-coap-transactions.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); -static void res_resume_handler(void); - -SEPARATE_RESOURCE(res_separate, - "title=\"Separate demo\"", - res_get_handler, - NULL, - NULL, - NULL, - res_resume_handler); - -/* A structure to store the information required for the separate handler */ -typedef struct application_separate_store { - - /* Provided by Erbium to store generic request information such as remote address and token. */ - coap_separate_t request_metadata; - - /* Add fields for addition information to be stored for finalizing, e.g.: */ - char buffer[16]; - -} application_separate_store_t; - -#define COAP_MAX_OPEN_SEPARATE 2 - -static uint8_t separate_active = 0; -static application_separate_store_t separate_store[COAP_MAX_OPEN_SEPARATE]; - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* - * Example allows only one open separate response. - * For multiple, the application must manage the list of stores. - */ - if (separate_active>=COAP_MAX_OPEN_SEPARATE) { - coap_separate_reject(); - } else { - ++separate_active; - - /* Take over and skip response by engine. */ - coap_separate_accept(request, &separate_store->request_metadata); - /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ - - /* - * At the moment, only the minimal information is stored in the store (client address, port, token, MID, type, and Block2). - * Extend the store, if the application requires additional information from this handler. - * buffer is an example field for custom information. - */ - snprintf(separate_store->buffer, sizeof(separate_store->buffer), "StoredInfo"); - } -} - -static void -res_resume_handler() -{ - if(separate_active) { - coap_transaction_t *transaction = NULL; - if( (transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port)) ) { - coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ - - /* Restore the request information for the response. */ - coap_separate_resume(response, &separate_store->request_metadata, REST.status.OK); - - coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); - - /* - * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. - * As it is a critical option, this example resource pretends to handle it for compliance. - */ - coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); - - /* Warning: No check for serialization error. */ - transaction->packet_len = coap_serialize_message(response, transaction->packet); - coap_send_transaction(transaction); - /* The engine will clear the transaction (right after send for NON, after acked for CON). */ - - //FIXME there could me more! - separate_active = 0; - } else { - /* - * Set timer for retry, send error message, ... - * The example simply waits for another button press. - */ - } - } /* if (separate_active) */ -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap-separate.h" +#include "er-coap-transactions.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_resume_handler(void); + +SEPARATE_RESOURCE(res_separate, + "title=\"Separate demo\"", + res_get_handler, + NULL, + NULL, + NULL, + res_resume_handler); + +/* A structure to store the information required for the separate handler */ +typedef struct application_separate_store { + + /* Provided by Erbium to store generic request information such as remote address and token. */ + coap_separate_t request_metadata; + + /* Add fields for addition information to be stored for finalizing, e.g.: */ + char buffer[16]; +} application_separate_store_t; + +#define COAP_MAX_OPEN_SEPARATE 2 + +static uint8_t separate_active = 0; +static application_separate_store_t separate_store[COAP_MAX_OPEN_SEPARATE]; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* + * Example allows only one open separate response. + * For multiple, the application must manage the list of stores. + */ + if(separate_active >= COAP_MAX_OPEN_SEPARATE) { + coap_separate_reject(); + } else { + ++separate_active; + + /* Take over and skip response by engine. */ + coap_separate_accept(request, &separate_store->request_metadata); + /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ + + /* + * At the moment, only the minimal information is stored in the store (client address, port, token, MID, type, and Block2). + * Extend the store, if the application requires additional information from this handler. + * buffer is an example field for custom information. + */ + snprintf(separate_store->buffer, sizeof(separate_store->buffer), "StoredInfo"); + } +} +static void +res_resume_handler() +{ + if(separate_active) { + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port))) { + coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(response, &separate_store->request_metadata, REST.status.OK); + + coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); + + /* + * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. + * As it is a critical option, this example resource pretends to handle it for compliance. + */ + coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(response, transaction->packet); + coap_send_transaction(transaction); + /* The engine will clear the transaction (right after send for NON, after acked for CON). */ + + /* FIXME there could me more! */ + separate_active = 0; + } else { + /* + * Set timer for retry, send error message, ... + * The example simply waits for another button press. + */ + } + } /* if (separate_active) */ +} diff --git a/examples/er-rest-example/resources/res-sub.c b/examples/er-rest-example/resources/res-sub.c old mode 100755 new mode 100644 index 53f36bbb5..1d6f17aeb --- a/examples/er-rest-example/resources/res-sub.c +++ b/examples/er-rest-example/resources/res-sub.c @@ -1,71 +1,69 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include -#include "rest-engine.h" - -static void res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* - * Example for a resource that also handles all its sub-resources. - * Use REST.get_url() to multiplex the handling of the request depending on the Uri-Path. - */ -PARENT_RESOURCE(res_sub, - "title=\"Sub-resource demo\"", - res_get_handler, - NULL, - NULL, - NULL); - -static void -res_get_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - const char *uri_path = NULL; - int len = REST.get_url(request, &uri_path); - int base_len = strlen(res_sub.url); - - if(len==base_len) { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "Request any sub-resource of /%s", res_sub.url); - } else { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%.*s", len-base_len, uri_path+base_len); - } - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); -} +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * Example for a resource that also handles all its sub-resources. + * Use REST.get_url() to multiplex the handling of the request depending on the Uri-Path. + */ +PARENT_RESOURCE(res_sub, + "title=\"Sub-resource demo\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + const char *uri_path = NULL; + int len = REST.get_url(request, &uri_path); + int base_len = strlen(res_sub.url); + + if(len == base_len) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "Request any sub-resource of /%s", res_sub.url); + } else { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%.*s", len - base_len, uri_path + base_len); + } REST.set_response_payload(response, buffer, strlen((char *)buffer)); +} diff --git a/examples/er-rest-example/resources/res-toggle.c b/examples/er-rest-example/resources/res-toggle.c old mode 100755 new mode 100644 index 967ce3ee6..a8ada909f --- a/examples/er-rest-example/resources/res-toggle.c +++ b/examples/er-rest-example/resources/res-toggle.c @@ -1,64 +1,63 @@ -/* - * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich - * 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 - * Matthias Kovatsch - */ - -#include "contiki.h" - -#if PLATFORM_HAS_LEDS - -#include -#include "contiki.h" -#include "rest-engine.h" -#include "dev/leds.h" - -static void res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); - -/* A simple actuator example. Toggles the red led */ -RESOURCE(res_toggle, - "title=\"Red LED\";rt=\"Control\"", - NULL, - res_post_handler, - NULL, - NULL); - -static void -res_post_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - leds_invert(LEDS_RED); -} - -#endif /* PLATFORM_HAS_LEDS */ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * 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 + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LEDS + +#include +#include "contiki.h" +#include "rest-engine.h" +#include "dev/leds.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple actuator example. Toggles the red led */ +RESOURCE(res_toggle, + "title=\"Red LED\";rt=\"Control\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + leds_invert(LEDS_RED); +} +#endif /* PLATFORM_HAS_LEDS */