http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/coap.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/coap.c b/net/oic/src/messaging/coap/coap.c new file mode 100644 index 0000000..d77fbbb --- /dev/null +++ b/net/oic/src/messaging/coap/coap.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#include <stdio.h> +#include <string.h> + +#include "coap.h" +#include "transactions.h" + +#ifdef OC_SECURITY +#include "security/oc_dtls.h" +#endif + +/*---------------------------------------------------------------------------*/ +/*- Variables ---------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +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 - 1); +} +/*---------------------------------------------------------------------------*/ +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); + + if (delta > 268) { + buffer[++written] = ((delta - 269) >> 8) & 0xff; + buffer[++written] = (delta - 269) & 0xff; + } else if (delta > 12) { + buffer[++written] = (delta - 13); + } + + if (length > 268) { + buffer[++written] = ((length - 269) >> 8) & 0xff; + buffer[++written] = (length - 269) & 0xff; + } else if (length > 12) { + buffer[++written] = (length - 13); + } + + LOG("WRITTEN %zu 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; + } + LOG("OPTION %u (delta %u, len %zu)\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; + + LOG("ARRAY type %u, len %zu, full [%.*s]\n", number, length, (int)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) { + LOG("STEP %u/%zu (%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; + + LOG("OPTION type %u, delta %u, len %zu, part [%.*s]\n", number, + number - current_number, i, (int)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; + + LOG("OPTION type %u, delta %u, len %zu\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; + } +} +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +void +coap_init_connection() +{ + /* initialize transaction ID */ + current_mid = oc_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; + + LOG("-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); + + /* empty packet, dont need to do more stuff */ + if (!coap_pkt->code) { + LOG("-Done serializing empty message at %p-\n", coap_pkt->buffer); + return 4; + } + + /* set Token */ + LOG("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) { + LOG(" %02X", coap_pkt->token[current_number]); + *option = coap_pkt->token[current_number]; + ++option; + } + LOG("-\n"); + + /* Serialize options */ + current_number = 0; + + LOG("-Serializing options at %p-\n", option); +#if 0 + /* 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"); +#endif + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_OBSERVE, observe, "Observe"); +#if 0 + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_URI_PORT, uri_port, "Uri-Port"); + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_PATH, location_path, + '/', "Location-Path"); +#endif + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_PATH, uri_path, '/', "Uri-Path"); + LOG("Serialize content format: %d\n", coap_pkt->content_format); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_CONTENT_FORMAT, content_format, + "Content-Format"); +#if 0 + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_MAX_AGE, max_age, "Max-Age"); +#endif + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_URI_QUERY, uri_query, '&', + "Uri-Query"); + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_ACCEPT, accept, "Accept"); +#if 0 + COAP_SERIALIZE_STRING_OPTION(COAP_OPTION_LOCATION_QUERY, location_query, + '&', "Location-Query"); +#endif + 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"); +#if 0 + 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"); +#endif + COAP_SERIALIZE_INT_OPTION(COAP_OPTION_SIZE1, size1, "Size1"); + + LOG("-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; + } + + LOG("-Done %u B (header len %u, payload len %u)-\n", + (unsigned int)(coap_pkt->payload_len + option - buffer), + (unsigned int)(option - buffer), (unsigned int)coap_pkt->payload_len); + + LOG("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(oc_message_t *message) +{ + LOG("-sending OCF message (%u)-\n", (unsigned int) message->length); + + oc_send_message(message); +} +/*---------------------------------------------------------------------------*/ +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 = (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; + } + + if (coap_pkt->token_len > COAP_TOKEN_LEN) { + coap_error_message = "Token Length must not be more than 8"; + return BAD_REQUEST_4_00; + } + + uint8_t *current_option = data + COAP_HEADER_LEN; + + memcpy(coap_pkt->token, current_option, coap_pkt->token_len); + LOG("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 MAX_PAYLOAD_SIZE */ + if (coap_pkt->payload_len > MAX_PAYLOAD_SIZE) { + coap_pkt->payload_len = MAX_PAYLOAD_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; + + if (option_delta == 13) { + option_delta += current_option[0]; + ++current_option; + } else if (option_delta == 14) { + option_delta += 255; + option_delta += current_option[0] << 8; + ++current_option; + option_delta += current_option[0]; + ++current_option; + } + + if (option_length == 13) { + option_length += current_option[0]; + ++current_option; + } else if (option_length == 14) { + option_length += 255; + option_length += current_option[0] << 8; + ++current_option; + option_length += current_option[0]; + ++current_option; + } + + option_number += option_delta; + + if (option_number < COAP_OPTION_SIZE1) { + LOG("OPTION %u (delta %u, len %zu): ", 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); + LOG("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); + LOG("Max-Age [%lu]\n", (unsigned long)coap_pkt->max_age); + break; +#if 0 + case COAP_OPTION_ETAG: + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, + option_length); + memcpy(coap_pkt->etag, current_option, + coap_pkt->etag_len); + LOG("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; +#endif + case COAP_OPTION_ACCEPT: + coap_pkt->accept = coap_parse_int_option(current_option, option_length); + LOG("Accept [%u]\n", coap_pkt->accept); + break; +#if 0 + 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); + LOG("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; + LOG("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 + LOG("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", (int)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 + LOG("Proxy-Scheme NOT IMPLEMENTED [%.*s]\n", + (int)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; + LOG("Uri-Host [%.*s]\n", (int)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); + LOG("Uri-Port [%u]\n", coap_pkt->uri_port); + break; +#endif + 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, '/'); + LOG("Uri-Path [%.*s]\n", (int)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, '&'); + LOG("Uri-Query [%.*s]\n", (int)coap_pkt->uri_query_len, + coap_pkt->uri_query); + break; +#if 0 + 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, + '/'); + LOG("Location-Path [%.*s]\n", (int)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, + '&'); + LOG("Location-Query [%.*s]\n", (int)coap_pkt->location_query_len, + coap_pkt->location_query); + break; +#endif + case COAP_OPTION_OBSERVE: + coap_pkt->observe = coap_parse_int_option(current_option, option_length); + LOG("Observe [%lu]\n", (unsigned long)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; + LOG("Block2 [%lu%s (%u B/blk)]\n", (unsigned long)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; + LOG("Block1 [%lu%s (%u B/blk)]\n", (unsigned long)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); + LOG("Size2 [%lu]\n", (unsigned long)coap_pkt->size2); + break; + case COAP_OPTION_SIZE1: + coap_pkt->size1 = coap_parse_int_option(current_option, option_length); + LOG("Size1 [%lu]\n", (unsigned long)coap_pkt->size1); + break; + default: + LOG("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 */ + LOG("-Done parsing-------\n"); + + return NO_ERROR; +} +#if 0 +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; +} +#endif +/*---------------------------------------------------------------------------*/ +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; +} +#ifdef OC_CLIENT +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; +} +#endif +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 = format; + SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_FORMAT); + return 1; +} +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +#ifdef OC_CLIENT +int +coap_set_header_accept(void *packet, unsigned int accept) +{ + coap_packet_t *const coap_pkt = (coap_packet_t *)packet; + + coap_pkt->accept = accept; + SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); + return 1; +} +#endif +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +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; +} +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +/*---------------------------------------------------------------------------*/ +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; +} +#ifdef OC_CLIENT +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; +} +#endif +/*---------------------------------------------------------------------------*/ +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; +} +#ifdef OC_CLIENT +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; +} +#endif +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +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; +} +/*---------------------------------------------------------------------------*/ +#if 0 +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; +} +#endif +/*---------------------------------------------------------------------------*/ +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(MAX_PAYLOAD_SIZE, length); + + return coap_pkt->payload_len; +} +/*---------------------------------------------------------------------------*/
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/coap.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/coap.h b/net/oic/src/messaging/coap/coap.h new file mode 100644 index 0000000..9834d31 --- /dev/null +++ b/net/oic/src/messaging/coap/coap.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#ifndef COAP_H +#define COAP_H + +#include "conf.h" +#include "constants.h" +#include <stddef.h> /* for size_t */ +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* OIC stack headers */ +#include "../src/port/mynewt/config.h" +#include "oic/oc_buffer.h" +#include "../src/port/oc_connectivity.h" +#include "../src/port/oc_log.h" +#include "../src/port/oc_random.h" + +#ifndef MAX +#define MAX(n, m) (((n) < (m)) ? (m) : (n)) +#endif + +#ifndef MIN +#define MIN(n, m) (((n) < (m)) ? (n) : (m)) +#endif + +#ifndef ABS +#define ABS(n) (((n) < 0) ? -(n) : (n)) +#endif + +#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + MAX_PAYLOAD_SIZE) + +/* MAX_PAYLOAD_SIZE can be different from 2^x so we need to get next lower 2^x + * for COAP_MAX_BLOCK_SIZE */ +#ifndef COAP_MAX_BLOCK_SIZE +#define COAP_MAX_BLOCK_SIZE \ + (MAX_PAYLOAD_SIZE < 32 \ + ? 16 \ + : (MAX_PAYLOAD_SIZE < 64 \ + ? 32 \ + : (MAX_PAYLOAD_SIZE < 128 \ + ? 64 \ + : (MAX_PAYLOAD_SIZE < 256 \ + ? 128 \ + : (MAX_PAYLOAD_SIZE < 512 \ + ? 256 \ + : (MAX_PAYLOAD_SIZE < 1024 \ + ? 512 \ + : (MAX_PAYLOAD_SIZE < 2048 ? 1024 : 2048))))))) +#endif /* COAP_MAX_BLOCK_SIZE */ + +/* 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))) + +/* 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 */ + + uint16_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; + uint16_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)) { \ + LOG(text " [%u]\n", (unsigned int)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)) { \ + LOG(text " %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", \ + (unsigned int)coap_pkt->field##_len, coap_pkt->field[0], \ + coap_pkt->field[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)) { \ + LOG(text " [%.*s]\n", (int)coap_pkt->field##_len, coap_pkt->field); \ + option += coap_serialize_array_option(number, current_number, option, \ + (uint8_t *)coap_pkt->field, \ + coap_pkt->field##_len, splitter); \ + current_number = number; \ + } +#define COAP_SERIALIZE_BLOCK_OPTION(number, field, text) \ + if (IS_OPTION(coap_pkt, number)) { \ + LOG(text " [%lu%s (%u B/blk)]\n", (unsigned long)coap_pkt->field##_num, \ + coap_pkt->field##_more ? "+" : "", coap_pkt->field##_size); \ + uint32_t block = coap_pkt->field##_num << 4; \ + if (coap_pkt->field##_more) { \ + block |= 0x8; \ + } \ + block |= 0xF & coap_log_2(coap_pkt->field##_size / 16); \ + LOG(text " encoded: 0x%lX\n", (unsigned long)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(void); +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(oc_message_t *message); +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); + +#ifdef __cplusplus +} +#endif + +#endif /* COAP_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/conf.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/conf.h b/net/oic/src/messaging/coap/conf.h new file mode 100644 index 0000000..39575b2 --- /dev/null +++ b/net/oic/src/messaging/coap/conf.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#ifndef CONF_H +#define CONF_H + +#include "../../port/mynewt/config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Features that can be disabled to achieve smaller memory footprint */ +#define COAP_LINK_FORMAT_FILTERING 0 +#define COAP_PROXY_OPTION_PROCESSING 0 + +/* 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 (MAX_NUM_CONCURRENT_REQUESTS) +#endif /* COAP_MAX_OPEN_TRANSACTIONS */ + +/* Maximum number of failed request attempts before action */ +#ifndef COAP_MAX_ATTEMPTS +#define COAP_MAX_ATTEMPTS 2 +#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 (MAX_APP_RESOURCES + MAX_NUM_CONCURRENT_REQUESTS) +#endif /* COAP_MAX_OBSERVERS */ + +/* Interval in notifies in which NON notifies are changed to CON notifies to + * check client. */ +#define COAP_OBSERVE_REFRESH_INTERVAL 20 + +#ifdef __cplusplus +} +#endif + +#endif /* CONF_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/constants.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/constants.h b/net/oic/src/messaging/coap/constants.h new file mode 100644 index 0000000..6cb37bc --- /dev/null +++ b/net/oic/src/messaging/coap/constants.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define COAP_DEFAULT_PORT 5683 + +#define COAP_DEFAULT_MAX_AGE 60 +#define COAP_RESPONSE_TIMEOUT 2 +#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 */ + CONTINUE_2_31 = 95, /* CONTINUE */ + + 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 */ + CLEAR_TRANSACTION, + EMPTY_ACK_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, + APPLICATION_CBOR = 60 +} coap_content_format_t; + +#ifdef __cplusplus +} +#endif + +#endif /* CONSTANTS_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/engine.c ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/engine.c b/net/oic/src/messaging/coap/engine.c new file mode 100644 index 0000000..0eecabf --- /dev/null +++ b/net/oic/src/messaging/coap/engine.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#include "engine.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* OIC Stack headers */ +#include "api/oc_events.h" +#include "oc_buffer.h" +#include "oc_ri.h" + +#ifdef OC_CLIENT +#include "oc_client_state.h" +#endif + +OC_PROCESS(coap_engine, "CoAP Engine"); + +extern bool oc_ri_invoke_coap_entity_handler(void *request, void *response, + uint8_t *buffer, + uint16_t buffer_size, + int32_t *offset, + oc_endpoint_t *endpoint); + +/*---------------------------------------------------------------------------*/ +/*- Internal API ------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +int +coap_receive(oc_message_t *msg) +{ + erbium_status_code = NO_ERROR; + + LOG("\n\nCoAP Engine: received datalen=%u \n", (unsigned int) msg->length); + + /* 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; + + erbium_status_code = coap_parse_message(message, msg->data, msg->length); + + if (erbium_status_code == NO_ERROR) { + +/*TODO duplicates suppression, if required by application */ + +#if DEBUG + LOG(" Parsed: CoAP version: %u, token: 0x%02X%02X, mid: %u\n", + message->version, message->token[0], message->token[1], message->mid); + switch (message->type) { + case COAP_TYPE_CON: + LOG(" type: CON\n"); + break; + case COAP_TYPE_NON: + LOG(" type: NON\n"); + break; + case COAP_TYPE_ACK: + LOG(" type: ACK\n"); + break; + case COAP_TYPE_RST: + LOG(" type: RST\n"); + break; + default: + break; + } +#endif + + /* handle requests */ + if (message->code >= COAP_GET && message->code <= COAP_DELETE) { + +#if DEBUG + switch (message->code) { + case COAP_GET: + LOG(" method: GET\n"); + break; + case COAP_PUT: + LOG(" method: PUT\n"); + break; + case COAP_POST: + LOG(" method: POST\n"); + break; + case COAP_DELETE: + LOG(" method: DELETE\n"); + break; + } + LOG(" URL: %.*s\n", (int) message->uri_path_len, message->uri_path); + LOG(" Payload: %.*s\n", (int) message->payload_len, message->payload); +#endif + /* use transaction buffer for response to confirmable request */ + if ((transaction = coap_new_transaction(message->mid, &msg->endpoint))) { + uint32_t block_num = 0; + uint16_t block_size = COAP_MAX_BLOCK_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)) { + LOG("\tBlockwise: block request %u (%u/%u) @ %u bytes\n", (unsigned int) block_num, + block_size, COAP_MAX_BLOCK_SIZE, (unsigned int) block_offset); + block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE); + new_offset = block_offset; + } + + /* invoke resource handler in RI layer */ + if (oc_ri_invoke_coap_entity_handler( + message, response, + transaction->message->data + COAP_MAX_HEADER_SIZE, block_size, + &new_offset, &msg->endpoint)) { + + 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)) { + LOG("\tBlock1 option 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) { + LOG("\tBlockwise: unaware resource with payload length %u/%u\n", + response->payload_len, block_size); + if (block_offset >= response->payload_len) { + LOG("\t\t: 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 { + LOG("\tBlockwise: blockwise resource, new offset %d\n", + (int) 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) { + LOG("\tBlockwise: no block option for blockwise resource, using " + "block size %u\n", + COAP_MAX_BLOCK_SIZE); + + coap_set_header_block2(response, 0, new_offset != -1, + COAP_MAX_BLOCK_SIZE); + coap_set_payload(response, response->payload, + MIN(response->payload_len, COAP_MAX_BLOCK_SIZE)); + } /* blockwise transfer handling */ + } /* no errors/hooks */ + /* successful service callback */ + /* serialize response */ + } + if (erbium_status_code == NO_ERROR) { + if ((transaction->message->length = coap_serialize_message( + response, transaction->message->data)) == 0) { + erbium_status_code = PACKET_SERIALIZATION_ERROR; + } + } + } else { + erbium_status_code = SERVICE_UNAVAILABLE_5_03; + coap_error_message = "NoFreeTraBuffer"; + } /* if(transaction buffer) */ + + /* handle responses */ + } else { // Fix this + if (message->type == COAP_TYPE_CON) { + erbium_status_code = EMPTY_ACK_RESPONSE; + } else if (message->type == COAP_TYPE_ACK) { + /* transactions are closed through lookup below */ + } else if (message->type == COAP_TYPE_RST) { +#ifdef OC_SERVER + /* cancel possible subscriptions */ + coap_remove_observer_by_mid(&msg->endpoint, message->mid); +#endif + } + + /* Open transaction now cleared for ACK since mid matches */ + if ((transaction = coap_get_transaction_by_mid(message->mid))) { + coap_clear_transaction(transaction); + } + /* if(ACKed transaction) */ + transaction = NULL; + +#ifdef OC_CLIENT // ACKs and RSTs sent to oc_ri.. RSTs cleared, ACKs sent to + // client + oc_ri_invoke_client_cb(message, &msg->endpoint); +#endif + + } /* request or response */ + } /* parsed correctly */ + + /* if(parsed correctly) */ + if (erbium_status_code == NO_ERROR) { + if (transaction) { // Server transactions sent from here + coap_send_transaction(transaction); + } + } else if (erbium_status_code == CLEAR_TRANSACTION) { + LOG("Clearing transaction for manual response"); + coap_clear_transaction(transaction); // used in server for separate response + } +#ifdef OC_CLIENT + else if (erbium_status_code == EMPTY_ACK_RESPONSE) { + coap_init_message(message, COAP_TYPE_ACK, 0, message->mid); + oc_message_t *response = oc_allocate_message(); + if (response) { + memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); + response->length = coap_serialize_message(message, response->data); + coap_send_message(response); + } + } +#endif /* OC_CLIENT */ +#ifdef OC_SERVER + else { // framework errors handled here + coap_message_type_t reply_type = COAP_TYPE_RST; + + coap_clear_transaction(transaction); + + coap_init_message(message, reply_type, SERVICE_UNAVAILABLE_5_03, + message->mid); + + oc_message_t *response = oc_allocate_message(); + if (response) { + memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); + response->length = coap_serialize_message(message, response->data); + coap_send_message(response); + } + } +#endif /* OC_SERVER */ + + /* if(new data) */ + return erbium_status_code; +} +/*---------------------------------------------------------------------------*/ +void +coap_init_engine(void) +{ + coap_register_as_transaction_handler(); +} +/*---------------------------------------------------------------------------*/ +OC_PROCESS_THREAD(coap_engine, ev, data) +{ + OC_PROCESS_BEGIN(); + + coap_register_as_transaction_handler(); + coap_init_connection(); + + while (1) { + OC_PROCESS_YIELD(); + + if (ev == oc_events[INBOUND_RI_EVENT]) { + coap_receive(data); + + oc_message_unref(data); + } else if (ev == OC_PROCESS_EVENT_TIMER) { + coap_check_transactions(); + } + } + + OC_PROCESS_END(); +} + +/*---------------------------------------------------------------------------*/ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/messaging/coap/engine.h ---------------------------------------------------------------------- diff --git a/net/oic/src/messaging/coap/engine.h b/net/oic/src/messaging/coap/engine.h new file mode 100644 index 0000000..781f4f2 --- /dev/null +++ b/net/oic/src/messaging/coap/engine.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * 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. + */ + +#ifndef ENGINE_H +#define ENGINE_H + +#include "coap.h" +#include "observe.h" +#include "separate.h" +#include "transactions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +OC_PROCESS_NAME(coap_engine); + +void coap_init_engine(void); +/*---------------------------------------------------------------------------*/ +int coap_receive(oc_message_t *message); + +#ifdef __cplusplus +} +#endif + +#endif /* ENGINE_H */