http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_discovery.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_discovery.c b/net/oic/src/api/oc_discovery.c new file mode 100644 index 0000000..e8ca760 --- /dev/null +++ b/net/oic/src/api/oc_discovery.c @@ -0,0 +1,298 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#ifdef OC_CLIENT +#include "oc_client_state.h" +#endif /* OC_CLIENT */ + +#include "messaging/coap/oc_coap.h" +#include "oc_api.h" +#include "oc_core_res.h" + +static bool +filter_resource(oc_resource_t *resource, const char *rt, int rt_len, + CborEncoder *links) +{ + int i; + bool match = true; + if (rt_len > 0) { + match = false; + for (i = 0; i < oc_string_array_get_allocated_size(resource->types); i++) { + int size = oc_string_array_get_item_size(resource->types, i); + const char *t = + (const char *)oc_string_array_get_item(resource->types, i); + if (rt_len == size && strncmp(rt, t, rt_len) == 0) { + match = true; + break; + } + } + } + + if (!match) { + return false; + } + + oc_rep_start_object(*links, res); + + // uri + oc_rep_set_text_string(res, href, oc_string(resource->uri)); + + // rt + oc_rep_set_array(res, rt); + for (i = 0; i < oc_string_array_get_allocated_size(resource->types); i++) { + int size = oc_string_array_get_item_size(resource->types, i); + const char *t = (const char *)oc_string_array_get_item(resource->types, i); + if (size > 0) + oc_rep_add_text_string(rt, t); + } + oc_rep_close_array(res, rt); + + // if + oc_core_encode_interfaces_mask(oc_rep_object(res), resource->interfaces); + + // p + oc_rep_set_object(res, p); + oc_rep_set_uint(p, bm, resource->properties & ~OC_PERIODIC); +#ifdef OC_SECURITY + if (resource->properties & OC_SECURE) { + oc_rep_set_boolean(p, sec, true); + oc_rep_set_uint(p, port, oc_connectivity_get_dtls_port()); + } +#endif /* OC_SECURITY */ + + oc_rep_close_object(res, p); + + oc_rep_end_object(*links, res); + return true; +} + +static int +process_device_object(CborEncoder *device, const char *uuid, const char *rt, + int rt_len) +{ + int dev, matches = 0; + oc_rep_start_object(*device, links); + oc_rep_set_text_string(links, di, uuid); + oc_rep_set_array(links, links); + + if (filter_resource(oc_core_get_resource_by_index(OCF_P), rt, rt_len, + oc_rep_array(links))) + matches++; + + for (dev = 0; dev < oc_core_get_num_devices(); dev++) { + if (filter_resource( + oc_core_get_resource_by_index(NUM_OC_CORE_RESOURCES - 1 - dev), rt, + rt_len, oc_rep_array(links))) + matches++; + } + +#ifdef OC_SERVER + oc_resource_t *resource = oc_ri_get_app_resources(); + for (; resource; resource = resource->next) { + + if (!(resource->properties & OC_DISCOVERABLE)) + continue; + + if (filter_resource(resource, rt, rt_len, oc_rep_array(links))) + matches++; + } +#endif + +#ifdef OC_SECURITY + if (filter_resource(oc_core_get_resource_by_index(OCF_SEC_DOXM), rt, rt_len, + oc_rep_array(links))) + matches++; +#endif + + oc_rep_close_array(links, links); + oc_rep_end_object(*device, links); + + return matches; +} + +static void +oc_core_discovery_handler(oc_request_t *request, oc_interface_mask_t interface) +{ + char *rt = NULL; + int rt_len = 0, matches = 0; + if (request->query_len) { + rt_len = + oc_ri_get_query_value(request->query, request->query_len, "rt", &rt); + } + + char uuid[37]; + oc_uuid_to_str(oc_core_get_device_id(0), uuid, 37); + + switch (interface) { + case OC_IF_LL: { + oc_rep_start_links_array(); + matches = process_device_object(oc_rep_array(links), uuid, rt, rt_len); + oc_rep_end_links_array(); + } break; + case OC_IF_BASELINE: { + oc_rep_start_root_object(); + oc_process_baseline_interface(request->resource); + oc_rep_set_array(root, links); + matches = process_device_object(oc_rep_array(links), uuid, rt, rt_len); + oc_rep_close_array(root, links); + oc_rep_end_root_object(); + } break; + default: + break; + } + + int response_length = oc_rep_finalize(); + + if (matches && response_length > 0) { + request->response->response_buffer->response_length = response_length; + request->response->response_buffer->code = oc_status_code(OC_STATUS_OK); + } else { + /* There were rt/if selections and there were no matches, so ignore */ + request->response->response_buffer->code = OC_IGNORE; + } +} + +void +oc_create_discovery_resource(void) +{ + oc_core_populate_resource(OCF_RES, "/oic/res", "oic.wk.res", + OC_IF_LL | OC_IF_BASELINE, OC_IF_LL, OC_ACTIVE, + oc_core_discovery_handler, 0, 0, 0, 0); +} + +#ifdef OC_CLIENT +oc_discovery_flags_t +oc_ri_process_discovery_payload(uint8_t *payload, int len, + oc_discovery_cb_t *handler, + oc_endpoint_t *endpoint) +{ + oc_discovery_flags_t ret = OC_CONTINUE_DISCOVERY; + oc_string_t uri; + uri.ptr = 0; + oc_string_t di; + di.ptr = 0; + bool secure = false; + uint16_t dtls_port = 0, default_port = endpoint->ipv6_addr.port; + oc_string_array_t types = {}; + oc_interface_mask_t interfaces = 0; + oc_server_handle_t handle; + memcpy(&handle.endpoint, endpoint, sizeof(oc_endpoint_t)); + + oc_rep_t *array = 0, *rep; + int s = oc_parse_rep(payload, len, &rep); + if (s == 0) + array = rep; + while (array != NULL) { + oc_rep_t *device_map = array->value_object; + while (device_map != NULL) { + switch (device_map->type) { + case STRING: + if (oc_string_len(device_map->name) == 2 && + strncmp(oc_string(device_map->name), "di", 2) == 0) + di = device_map->value_string; + break; + default: + break; + } + device_map = device_map->next; + } + device_map = array->value_object; + while (device_map != NULL) { + switch (device_map->type) { + case OBJECT_ARRAY: { + oc_rep_t *links = device_map->value_object_array; + while (links != NULL) { + switch (links->type) { + case OBJECT: { + oc_rep_t *resource_info = links->value_object; + while (resource_info != NULL) { + switch (resource_info->type) { + case STRING: + uri = resource_info->value_string; + break; + case STRING_ARRAY: + if (oc_string_len(resource_info->name) == 2 && + strncmp(oc_string(resource_info->name), "rt", 2) == 0) + types = resource_info->value_array; + else { + interfaces = 0; + int i; + for (i = 0; i < oc_string_array_get_allocated_size( + resource_info->value_array); + i++) { + interfaces |= oc_ri_get_interface_mask( + oc_string_array_get_item(resource_info->value_array, i), + oc_string_array_get_item_size(resource_info->value_array, + i)); + } + } + break; + case OBJECT: { + oc_rep_t *policy_info = resource_info->value_object; + while (policy_info != NULL) { + if (policy_info->type == INT && + oc_string_len(policy_info->name) == 4 && + strncmp(oc_string(policy_info->name), "port", 4) == 0) { + dtls_port = policy_info->value_int; + } + if (policy_info->type == BOOL && + oc_string_len(policy_info->name) == 3 && + strncmp(oc_string(policy_info->name), "sec", 3) == 0 && + policy_info->value_boolean == true) { + secure = true; + } + policy_info = policy_info->next; + } + } break; + default: + break; + } + resource_info = resource_info->next; + } + if (secure) { + handle.endpoint.ipv6_addr.port = dtls_port; + handle.endpoint.flags |= SECURED; + } else { + handle.endpoint.ipv6_addr.port = default_port; + handle.endpoint.flags &= ~SECURED; + } + + if (handler(oc_string(di), oc_string(uri), types, interfaces, + &handle) == OC_STOP_DISCOVERY) { + ret = OC_STOP_DISCOVERY; + goto done; + } + dtls_port = 0; + secure = false; + } break; + default: + break; + } + links = links->next; + } + } break; + default: + break; + } + device_map = device_map->next; + } + array = array->next; + } +done: + oc_free_rep(rep); + return ret; +} +#endif /* OC_CLIENT */
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_events.h ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_events.h b/net/oic/src/api/oc_events.h new file mode 100644 index 0000000..19de52c --- /dev/null +++ b/net/oic/src/api/oc_events.h @@ -0,0 +1,42 @@ +/* + // Copyright (c) 2016 Intel Corporation + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + */ + +#ifndef OC_EVENTS_H +#define OC_EVENTS_H + +#include "util/oc_process.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + INBOUND_NETWORK_EVENT, + UDP_TO_DTLS_EVENT, + INIT_DTLS_CONN_EVENT, + RI_TO_DTLS_EVENT, + INBOUND_RI_EVENT, + OUTBOUND_NETWORK_EVENT, + __NUM_OC_EVENT_TYPES__ +} oc_events_t; + +oc_process_event_t oc_events[__NUM_OC_EVENT_TYPES__]; + +#ifdef __cplusplus +} +#endif + +#endif /* OC_EVENTS_H */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_helpers.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_helpers.c b/net/oic/src/api/oc_helpers.c new file mode 100644 index 0000000..4af8eeb --- /dev/null +++ b/net/oic/src/api/oc_helpers.c @@ -0,0 +1,164 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "oc_helpers.h" +#include "port/oc_assert.h" +#include "port/oc_log.h" +#include <stdbool.h> + +static bool mmem_initialized = false; + +static void +oc_malloc(oc_handle_t *block, uint16_t num_bytes, pool pool_type) +{ + if (!mmem_initialized) { + oc_mmem_init(); + mmem_initialized = true; + } + oc_assert(oc_mmem_alloc(block, num_bytes, pool_type) > 0); +} + +static void +oc_free(oc_handle_t *block, pool pool_type) +{ + oc_mmem_free(block, pool_type); + block->next = 0; + block->ptr = 0; + block->size = 0; +} + +void +oc_new_string(oc_string_t *ocstring, const char str[]) +{ + oc_malloc(ocstring, strlen(str) + 1, BYTE_POOL); + memcpy(oc_string(*ocstring), (const uint8_t *)str, strlen(str)); + memcpy(oc_string(*ocstring) + strlen(str), (const uint8_t *)"", 1); +} + +void +oc_alloc_string(oc_string_t *ocstring, int size) +{ + oc_malloc(ocstring, size, BYTE_POOL); +} + +void +oc_free_string(oc_string_t *ocstring) +{ + oc_free(ocstring, BYTE_POOL); +} + +void +oc_concat_strings(oc_string_t *concat, const char *str1, const char *str2) +{ + size_t len1 = strlen(str1), len2 = strlen(str2); + oc_alloc_string(concat, len1 + len2 + 1); + memcpy(oc_string(*concat), str1, len1); + memcpy(oc_string(*concat) + len1, str2, len2); + memcpy(oc_string(*concat) + len1 + len2, (const char *)"", 1); +} + +void +_oc_new_array(oc_array_t *ocarray, uint8_t size, pool type) +{ + switch (type) { + case INT_POOL: + oc_malloc(ocarray, size * sizeof(int64_t), INT_POOL); + break; + case BYTE_POOL: + oc_malloc(ocarray, size * sizeof(bool), BYTE_POOL); + break; + case DOUBLE_POOL: + oc_malloc(ocarray, size * sizeof(double), DOUBLE_POOL); + break; + default: + break; + } +} + +void +_oc_free_array(oc_array_t *ocarray, pool type) +{ + oc_free(ocarray, type); +} + +void +_oc_alloc_string_array(oc_string_array_t *ocstringarray, uint8_t size) +{ + oc_alloc_string(ocstringarray, size * STRING_ARRAY_ITEM_MAX_LEN); + int i, pos; + for (i = 0; i < size; i++) { + pos = i * STRING_ARRAY_ITEM_MAX_LEN; + memcpy((char *)oc_string(*ocstringarray) + pos, (const char *)"", 1); + } +} + +bool +_oc_copy_string_to_string_array(oc_string_array_t *ocstringarray, + const char str[], uint8_t index) +{ + if (strlen(str) >= STRING_ARRAY_ITEM_MAX_LEN) { + return false; + } + uint8_t pos = index * STRING_ARRAY_ITEM_MAX_LEN; + memcpy(oc_string(*ocstringarray) + pos, (const uint8_t *)str, strlen(str)); + memcpy(oc_string(*ocstringarray) + pos + strlen(str), (const uint8_t *)"", 1); + return true; +} + +bool +_oc_string_array_add_item(oc_string_array_t *ocstringarray, const char str[]) +{ + bool success = false; + int i; + for (i = 0; i < oc_string_array_get_allocated_size(*ocstringarray); i++) { + if (strlen((const char *)oc_string_array_get_item(*ocstringarray, i)) == + 0) { + success = oc_string_array_set_item(*ocstringarray, str, i); + break; + } + } + return success; +} + +void +oc_join_string_array(oc_string_array_t *ocstringarray, oc_string_t *ocstring) +{ + size_t len = 0; + uint8_t i; + for (i = 0; i < oc_string_array_get_allocated_size(*ocstringarray); i++) { + const char *item = + (const char *)oc_string_array_get_item(*ocstringarray, i); + if (strlen(item)) { + len += strlen(item); + len++; + } + } + oc_alloc_string(ocstring, len); + len = 0; + for (i = 0; i < oc_string_array_get_allocated_size(*ocstringarray); i++) { + const char *item = + (const char *)oc_string_array_get_item(*ocstringarray, i); + if (strlen(item)) { + if (len > 0) { + oc_string(*ocstring)[len] = ' '; + len++; + } + strncpy((char *)oc_string(*ocstring) + len, item, strlen(item)); + len += strlen(item); + } + } + strcpy((char *)oc_string(*ocstring) + len, ""); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_main.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_main.c b/net/oic/src/api/oc_main.c new file mode 100644 index 0000000..9086b4e --- /dev/null +++ b/net/oic/src/api/oc_main.c @@ -0,0 +1,119 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include <stdint.h> +#include <stdio.h> + +#include "port/oc_assert.h" +#include "port/oc_clock.h" +#include "port/oc_connectivity.h" + +#include "util/oc_etimer.h" +#include "util/oc_process.h" + +#include "oc_api.h" + +#ifdef OC_SECURITY +#include "security/oc_dtls.h" +#include "security/oc_store.h" +#include "security/oc_svr.h" +#endif /* OC_SECURITY */ + +static bool initialized = false; + +int +oc_main_init(oc_handler_t *handler) +{ + int ret; + extern int oc_stack_errno; + + if (initialized == true) + return 0; + + oc_ri_init(); + +#ifdef OC_SECURITY + handler->get_credentials(); + + oc_sec_load_pstat(); + oc_sec_load_doxm(); + oc_sec_load_cred(); + + oc_sec_dtls_init_context(); +#endif + + oc_network_event_handler_mutex_init(); + ret = oc_connectivity_init(); + if (ret < 0) + goto err; + + handler->init(); + +#ifdef OC_SERVER + handler->register_resources(); +#endif + +#ifdef OC_SECURITY + oc_sec_create_svr(); + oc_sec_load_acl(); +#endif + + if (oc_stack_errno != 0) { + ret = -oc_stack_errno; + goto err; + } + + PRINT("oc_main: Stack successfully initialized\n"); + +#ifdef OC_CLIENT + handler->requests_entry(); +#endif + + initialized = true; + return 0; + +err: + oc_abort("oc_main: Error in stack initialization\n"); + return ret; +} + +oc_clock_time_t +oc_main_poll(void) +{ + oc_clock_time_t ticks_until_next_event = oc_etimer_request_poll(); + while (oc_process_run()) { + ticks_until_next_event = oc_etimer_request_poll(); + } + return ticks_until_next_event; +} + +void +oc_main_shutdown(void) +{ + if (initialized == false) { + PRINT("tiny_ocf is not initialized\n"); + return; + } + + oc_connectivity_shutdown(); + oc_ri_shutdown(); + +#ifdef OC_SECURITY /* fix ensure this gets executed on constraied platforms */ + oc_sec_dump_state(); +#endif + + initialized = false; +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_network_events.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_network_events.c b/net/oic/src/api/oc_network_events.c new file mode 100644 index 0000000..2149bd3 --- /dev/null +++ b/net/oic/src/api/oc_network_events.c @@ -0,0 +1,57 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "oc_network_events.h" +#include "oc_buffer.h" +#include "port/oc_connectivity.h" +#include "port/oc_signal_main_loop.h" +#include "util/oc_list.h" + +OC_LIST(network_events); + +static void +oc_process_network_event(void) +{ + oc_network_event_handler_mutex_lock(); + oc_message_t *head = (oc_message_t *)oc_list_pop(network_events); + while (head != NULL) { + oc_recv_message(head); + head = oc_list_pop(network_events); + } + oc_network_event_handler_mutex_unlock(); +} + +OC_PROCESS(oc_network_events, ""); +OC_PROCESS_THREAD(oc_network_events, ev, data) +{ + OC_PROCESS_POLLHANDLER(oc_process_network_event()); + OC_PROCESS_BEGIN(); + while (oc_process_is_running(&(oc_network_events))) { + OC_PROCESS_YIELD(); + } + OC_PROCESS_END(); +} + +void +oc_network_event(oc_message_t *message) +{ + oc_network_event_handler_mutex_lock(); + oc_list_add(network_events, message); + oc_network_event_handler_mutex_unlock(); + + oc_process_poll(&(oc_network_events)); + oc_signal_main_loop(); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_rep.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_rep.c b/net/oic/src/api/oc_rep.c new file mode 100644 index 0000000..b922e1e --- /dev/null +++ b/net/oic/src/api/oc_rep.c @@ -0,0 +1,301 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "oc_rep.h" +#include "config.h" +#include "port/oc_assert.h" +#include "port/oc_log.h" +#include "util/oc_memb.h" + +OC_MEMB(rep_objects, oc_rep_t, EST_NUM_REP_OBJECTS); +static const CborEncoder g_empty; +static uint8_t *g_buf; +CborEncoder g_encoder, root_map, links_array; +CborError g_err; + +void +oc_rep_new(uint8_t *out_payload, int size) +{ + g_err = CborNoError; + g_buf = out_payload; + cbor_encoder_init(&g_encoder, out_payload, size, 0); +} + +int +oc_rep_finalize(void) +{ + int size = cbor_encoder_get_buffer_size(&g_encoder, g_buf); + oc_rep_reset(); + if (g_err != CborNoError) + return -1; + return size; +} + +void +oc_rep_reset(void) +{ + g_encoder = g_empty; +} + +static oc_rep_t * +_alloc_rep(void) +{ + oc_rep_t *rep = oc_memb_alloc(&rep_objects); +#ifdef DEBUG + oc_assert(rep != NULL); +#endif + return rep; +} + +static void +_free_rep(oc_rep_t *rep_value) +{ + oc_memb_free(&rep_objects, rep_value); +} + +void +oc_free_rep(oc_rep_t *rep) +{ + if (rep == 0) + return; + oc_free_rep(rep->next); + switch (rep->type) { + case BYTE_STRING_ARRAY: + case STRING_ARRAY: + oc_free_string_array(&rep->value_array); + break; + case BOOL_ARRAY: + oc_free_bool_array(&rep->value_array); + break; + case DOUBLE_ARRAY: + oc_free_double_array(&rep->value_array); + break; + case INT_ARRAY: + oc_free_int_array(&rep->value_array); + break; + case BYTE_STRING: + case STRING: + oc_free_string(&rep->value_string); + break; + case OBJECT: + oc_free_rep(rep->value_object); + break; + case OBJECT_ARRAY: + oc_free_rep(rep->value_object_array); + break; + default: + break; + } + oc_free_string(&rep->name); + _free_rep(rep); +} + +/* + An Object is a collection of key-value pairs. + A value_object value points to the first key-value pair, + and subsequent items are accessed via the next pointer. + + An Object Array is a collection of objects, where each object + is a collection of key-value pairs. + A value_object_array value points to the first object in the + array. This object is then traversed via its value_object pointer. + Subsequent objects in the object array are then accessed through + the next pointer of the first object. +*/ + +/* Parse single property */ +static void +oc_parse_rep_value(CborValue *value, oc_rep_t **rep, CborError *err) +{ + size_t k, len; + CborValue map, array; + *rep = _alloc_rep(); + oc_rep_t *cur = *rep, **prev = 0; + cur->next = 0; + cur->value_object_array = 0; + /* key */ + *err |= cbor_value_calculate_string_length(value, &len); + len++; + oc_alloc_string(&cur->name, len); + *err |= cbor_value_copy_text_string(value, (char *)oc_string(cur->name), &len, + NULL); + *err |= cbor_value_advance(value); + /* value */ + switch (value->type) { + case CborIntegerType: + *err |= cbor_value_get_int64(value, &cur->value_int); + cur->type = INT; + break; + case CborBooleanType: + *err |= cbor_value_get_boolean(value, &cur->value_boolean); + cur->type = BOOL; + break; + case CborDoubleType: + *err |= cbor_value_get_double(value, &cur->value_double); + cur->type = DOUBLE; + break; + case CborByteStringType: + *err |= cbor_value_calculate_string_length(value, &len); + len++; + oc_alloc_string(&cur->value_string, len); + *err |= cbor_value_copy_byte_string( + value, oc_cast(cur->value_string, uint8_t), &len, NULL); + cur->type = BYTE_STRING; + break; + case CborTextStringType: + *err |= cbor_value_calculate_string_length(value, &len); + len++; + oc_alloc_string(&cur->value_string, len); + *err |= cbor_value_copy_text_string(value, oc_string(cur->value_string), + &len, NULL); + cur->type = STRING; + break; + case CborMapType: /* when value is a map/object */ { + oc_rep_t **obj = &cur->value_object; // object points to list of properties + *err |= cbor_value_enter_container(value, &map); + while (!cbor_value_at_end(&map)) { + oc_parse_rep_value(&map, obj, err); + (*obj)->next = 0; + obj = &(*obj)->next; + *err |= cbor_value_advance(&map); + } + cur->type = OBJECT; + } break; + case CborArrayType: + *err |= cbor_value_enter_container(value, &array); + len = 0; + cbor_value_get_array_length(value, &len); + if (len == 0) { + CborValue t = array; + while (!cbor_value_at_end(&t)) { + len++; + cbor_value_advance(&t); + } + } + k = 0; + while (!cbor_value_at_end(&array)) { + switch (array.type) { + case CborIntegerType: + if (k == 0) { + oc_new_int_array(&cur->value_array, len); + cur->type = INT | ARRAY; + } + *err |= + cbor_value_get_int64(&array, oc_int_array(cur->value_array) + k); + break; + case CborDoubleType: + if (k == 0) { + oc_new_double_array(&cur->value_array, len); + cur->type = DOUBLE | ARRAY; + } + *err |= + cbor_value_get_double(&array, oc_double_array(cur->value_array) + k); + break; + case CborBooleanType: + if (k == 0) { + oc_new_bool_array(&cur->value_array, len); + cur->type = BOOL | ARRAY; + } + *err |= + cbor_value_get_boolean(&array, oc_bool_array(cur->value_array) + k); + break; + case CborByteStringType: + if (k == 0) { + oc_new_string_array(&cur->value_array, len); + cur->type = BYTE_STRING | ARRAY; + } + *err |= cbor_value_calculate_string_length(&array, &len); + len++; + *err |= cbor_value_copy_byte_string( + &array, (uint8_t *)oc_string_array_get_item(cur->value_array, k), + &len, NULL); + break; + case CborTextStringType: + if (k == 0) { + oc_new_string_array(&cur->value_array, len); + cur->type = STRING | ARRAY; + } + *err |= cbor_value_calculate_string_length(&array, &len); + len++; + *err |= cbor_value_copy_text_string( + &array, (char *)oc_string_array_get_item(cur->value_array, k), &len, + NULL); + break; + case CborMapType: + if (k == 0) { + cur->type = OBJECT | ARRAY; + cur->value_object_array = _alloc_rep(); + prev = &cur->value_object_array; + } else { + (*prev)->next = _alloc_rep(); + prev = &(*prev)->next; + } + (*prev)->type = OBJECT; + (*prev)->next = 0; + oc_rep_t **obj = &(*prev)->value_object; + /* Process a series of properties that make up an object of the array */ + *err |= cbor_value_enter_container(&array, &map); + while (!cbor_value_at_end(&map)) { + oc_parse_rep_value(&map, obj, err); + obj = &(*obj)->next; + *err |= cbor_value_advance(&map); + } + break; + default: + break; + } + k++; + *err |= cbor_value_advance(&array); + } + break; + default: + break; + } +} + +uint16_t +oc_parse_rep(const uint8_t *in_payload, uint16_t payload_size, + oc_rep_t **out_rep) +{ + CborParser parser; + CborValue root_value, cur_value, map; + CborError err = CborNoError; + err |= cbor_parser_init(in_payload, payload_size, 0, &parser, &root_value); + if (cbor_value_is_map(&root_value)) { + err |= cbor_value_enter_container(&root_value, &cur_value); + *out_rep = 0; + oc_rep_t **cur = out_rep; + while (cbor_value_is_valid(&cur_value)) { + oc_parse_rep_value(&cur_value, cur, &err); + err |= cbor_value_advance(&cur_value); + cur = &(*cur)->next; + } + } else if (cbor_value_is_array(&root_value)) { + err |= cbor_value_enter_container(&root_value, &map); + err |= cbor_value_enter_container(&map, &cur_value); + *out_rep = 0; + oc_rep_t **cur = out_rep; + while (cbor_value_is_valid(&cur_value)) { + *cur = _alloc_rep(); + (*cur)->type = OBJECT; + oc_parse_rep_value(&cur_value, &(*cur)->value_object, &err); + err |= cbor_value_advance(&cur_value); + (*cur)->next = 0; + cur = &(*cur)->next; + } + } + return (uint16_t)err; +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_ri.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_ri.c b/net/oic/src/api/oc_ri.c new file mode 100644 index 0000000..7a6df95 --- /dev/null +++ b/net/oic/src/api/oc_ri.c @@ -0,0 +1,1016 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include <stdbool.h> +#include <stddef.h> +#include <strings.h> + +#include "util/oc_etimer.h" +#include "util/oc_list.h" +#include "util/oc_memb.h" +#include "util/oc_process.h" + +#include "messaging/coap/constants.h" +#include "messaging/coap/engine.h" +#include "messaging/coap/oc_coap.h" + +#include "port/oc_random.h" + +#include "oc_buffer.h" +#include "oc_core_res.h" +#include "oc_discovery.h" +#include "oc_events.h" +#include "oc_network_events.h" +#include "oc_ri.h" +#include "oc_uuid.h" + +#ifdef OC_SECURITY +#include "security/oc_acl.h" +#include "security/oc_dtls.h" +#endif /* OC_SECURITY */ + +#ifdef OC_SERVER +OC_LIST(app_resources); +OC_LIST(observe_callbacks); +OC_MEMB(app_resources_s, oc_resource_t, MAX_APP_RESOURCES); +#endif /* OC_SERVER */ + +#ifdef OC_CLIENT +#include "oc_client_state.h" +OC_LIST(client_cbs); +OC_MEMB(client_cbs_s, oc_client_cb_t, MAX_NUM_CONCURRENT_REQUESTS); +#endif /* OC_CLIENT */ + +OC_LIST(timed_callbacks); +OC_MEMB(event_callbacks_s, oc_event_callback_t, NUM_OC_CORE_RESOURCES + + MAX_APP_RESOURCES + + MAX_NUM_CONCURRENT_REQUESTS); + +OC_PROCESS(timed_callback_events, "OC timed callbacks"); + +// TODO: Define and use a complete set of error codes. +int oc_stack_errno; + +static unsigned int oc_coap_status_codes[__NUM_OC_STATUS_CODES__]; + +static void +set_mpro_status_codes(void) +{ + /* OK_200 */ + oc_coap_status_codes[OC_STATUS_OK] = CONTENT_2_05; + /* CREATED_201 */ + oc_coap_status_codes[OC_STATUS_CREATED] = CREATED_2_01; + /* NO_CONTENT_204 */ + oc_coap_status_codes[OC_STATUS_CHANGED] = CHANGED_2_04; + /* NO_CONTENT_204 */ + oc_coap_status_codes[OC_STATUS_DELETED] = DELETED_2_02; + /* NOT_MODIFIED_304 */ + oc_coap_status_codes[OC_STATUS_NOT_MODIFIED] = VALID_2_03; + /* BAD_REQUEST_400 */ + oc_coap_status_codes[OC_STATUS_BAD_REQUEST] = BAD_REQUEST_4_00; + /* UNAUTHORIZED_401 */ + oc_coap_status_codes[OC_STATUS_UNAUTHORIZED] = UNAUTHORIZED_4_01; + /* BAD_REQUEST_400 */ + oc_coap_status_codes[OC_STATUS_BAD_OPTION] = BAD_OPTION_4_02; + /* FORBIDDEN_403 */ + oc_coap_status_codes[OC_STATUS_FORBIDDEN] = FORBIDDEN_4_03; + /* NOT_FOUND_404 */ + oc_coap_status_codes[OC_STATUS_NOT_FOUND] = NOT_FOUND_4_04; + /* METHOD_NOT_ALLOWED_405 */ + oc_coap_status_codes[OC_STATUS_METHOD_NOT_ALLOWED] = METHOD_NOT_ALLOWED_4_05; + /* NOT_ACCEPTABLE_406 */ + oc_coap_status_codes[OC_STATUS_NOT_ACCEPTABLE] = NOT_ACCEPTABLE_4_06; + /* REQUEST_ENTITY_TOO_LARGE_413 */ + oc_coap_status_codes[OC_STATUS_REQUEST_ENTITY_TOO_LARGE] = + REQUEST_ENTITY_TOO_LARGE_4_13; + /* UNSUPPORTED_MEDIA_TYPE_415 */ + oc_coap_status_codes[OC_STATUS_UNSUPPORTED_MEDIA_TYPE] = + UNSUPPORTED_MEDIA_TYPE_4_15; + /* INTERNAL_SERVER_ERROR_500 */ + oc_coap_status_codes[OC_STATUS_INTERNAL_SERVER_ERROR] = + INTERNAL_SERVER_ERROR_5_00; + /* NOT_IMPLEMENTED_501 */ + oc_coap_status_codes[OC_STATUS_NOT_IMPLEMENTED] = NOT_IMPLEMENTED_5_01; + /* BAD_GATEWAY_502 */ + oc_coap_status_codes[OC_STATUS_BAD_GATEWAY] = BAD_GATEWAY_5_02; + /* SERVICE_UNAVAILABLE_503 */ + oc_coap_status_codes[OC_STATUS_SERVICE_UNAVAILABLE] = + SERVICE_UNAVAILABLE_5_03; + /* GATEWAY_TIMEOUT_504 */ + oc_coap_status_codes[OC_STATUS_GATEWAY_TIMEOUT] = GATEWAY_TIMEOUT_5_04; + /* INTERNAL_SERVER_ERROR_500 */ + oc_coap_status_codes[OC_STATUS_PROXYING_NOT_SUPPORTED] = + PROXYING_NOT_SUPPORTED_5_05; +} + +#ifdef OC_SERVER +oc_resource_t * +oc_ri_get_app_resources(void) +{ + return oc_list_head(app_resources); +} +#endif + +int +oc_status_code(oc_status_t key) +{ + return oc_coap_status_codes[key]; +} + +int +oc_ri_get_query_nth_key_value(const char *query, int query_len, char **key, + int *key_len, char **value, int *value_len, int n) +{ + int next_pos = -1; + int i = 0; + char *start = (char *)query, *current, *end = (char *)query + query_len; + current = start; + + while (i < (n - 1) && current != NULL) { + current = memchr(start, '&', end - start); + i++; + start = current + 1; + } + + current = memchr(start, '=', end - start); + if (current != NULL) { + *key_len = current - start; + *key = start; + *value = current + 1; + current = memchr(*value, '&', end - *value); + if (current == NULL) { + *value_len = end - *value; + } else { + *value_len = current - *value; + } + next_pos = *value + *value_len - query + 1; + } + return next_pos; +} + +int +oc_ri_get_query_value(const char *query, int query_len, const char *key, + char **value) +{ + int next_pos = 0, found = -1, kl, vl; + char *k; + while (next_pos < query_len) { + next_pos += oc_ri_get_query_nth_key_value( + query + next_pos, query_len - next_pos, &k, &kl, value, &vl, 1); + if (next_pos == -1) + return -1; + + if (kl == strlen(key) && strncasecmp(key, k, kl) == 0) { + found = vl; + break; + } + } + return found; +} + +static void +allocate_events(void) +{ + int i = 0; + for (i = 0; i < __NUM_OC_EVENT_TYPES__; i++) { + oc_events[i] = oc_process_alloc_event(); + } +} + +static void +start_processes(void) +{ + allocate_events(); + oc_process_start(&oc_etimer_process, NULL); + oc_process_start(&timed_callback_events, NULL); + oc_process_start(&coap_engine, NULL); + oc_process_start(&message_buffer_handler, NULL); + +#ifdef OC_SECURITY + oc_process_start(&oc_dtls_handler, NULL); +#endif + + oc_process_start(&oc_network_events, NULL); +} + +static void +stop_processes(void) +{ + oc_process_exit(&oc_etimer_process); + oc_process_exit(&timed_callback_events); + oc_process_exit(&coap_engine); + +#ifdef OC_SECURITY + oc_process_exit(&oc_dtls_handler); +#endif + + oc_process_exit(&message_buffer_handler); +} + +#ifdef OC_SERVER +oc_resource_t * +oc_ri_get_app_resource_by_uri(const char *uri) +{ + oc_resource_t *res = oc_ri_get_app_resources(); + while (res != NULL) { + if (oc_string_len(res->uri) == strlen(uri) && + strncmp(uri, oc_string(res->uri), strlen(uri)) == 0) + return res; + res = res->next; + } + return res; +} +#endif + +void +oc_ri_init(void) +{ + oc_random_init(0); // Fix: allow user to seed RNG. + oc_clock_init(); + set_mpro_status_codes(); + +#ifdef OC_SERVER + oc_list_init(app_resources); + oc_list_init(observe_callbacks); +#endif + +#ifdef OC_CLIENT + oc_list_init(client_cbs); +#endif + + oc_list_init(timed_callbacks); + start_processes(); + oc_create_discovery_resource(); +} + +void +oc_ri_shutdown(void) +{ + oc_random_destroy(); + stop_processes(); +} + +#ifdef OC_SERVER +oc_resource_t * +oc_ri_alloc_resource(void) +{ + return oc_memb_alloc(&app_resources_s); +} + +void +oc_ri_delete_resource(oc_resource_t *resource) +{ + oc_memb_free(&app_resources_s, resource); +} + +bool +oc_ri_add_resource(oc_resource_t *resource) +{ + bool valid = true; + + if (!resource->get_handler && !resource->put_handler && + !resource->post_handler && !resource->delete_handler) + valid = false; + + if (resource->properties & OC_PERIODIC && + resource->observe_period_seconds == 0) + valid = false; + + if (valid) { + oc_list_add(app_resources, resource); + } + + return valid; +} +#endif /* OC_SERVER */ + +void +oc_ri_remove_timed_event_callback(void *cb_data, oc_trigger_t event_callback) +{ + oc_event_callback_t *event_cb = + (oc_event_callback_t *)oc_list_head(timed_callbacks); + + while (event_cb != NULL) { + if (event_cb->data == cb_data && event_cb->callback == event_callback) { + oc_list_remove(timed_callbacks, event_cb); + oc_memb_free(&event_callbacks_s, event_cb); + break; + } + event_cb = event_cb->next; + } +} + +void +oc_ri_add_timed_event_callback_ticks(void *cb_data, oc_trigger_t event_callback, + oc_clock_time_t ticks) +{ + oc_event_callback_t *event_cb = + (oc_event_callback_t *)oc_memb_alloc(&event_callbacks_s); + + if (event_cb) { + event_cb->data = cb_data; + event_cb->callback = event_callback; + OC_PROCESS_CONTEXT_BEGIN(&timed_callback_events); + oc_etimer_set(&event_cb->timer, ticks); + OC_PROCESS_CONTEXT_END(&timed_callback_events); + oc_list_add(timed_callbacks, event_cb); + } +} + +static void +poll_event_callback_timers(oc_list_t list, struct oc_memb *cb_pool) +{ + oc_event_callback_t *event_cb = (oc_event_callback_t *)oc_list_head(list), + *next; + + while (event_cb != NULL) { + next = event_cb->next; + + if (oc_etimer_expired(&event_cb->timer)) { + if (event_cb->callback(event_cb->data) == DONE) { + oc_list_remove(list, event_cb); + oc_memb_free(cb_pool, event_cb); + } else { + OC_PROCESS_CONTEXT_BEGIN(&timed_callback_events); + oc_etimer_restart(&event_cb->timer); + OC_PROCESS_CONTEXT_END(&timed_callback_events); + } + } + + event_cb = next; + } +} + +static void +check_event_callbacks(void) +{ +#ifdef OC_SERVER + poll_event_callback_timers(observe_callbacks, &event_callbacks_s); +#endif /* OC_SERVER */ + poll_event_callback_timers(timed_callbacks, &event_callbacks_s); +} + +#ifdef OC_SERVER +static oc_event_callback_retval_t +periodic_observe_handler(void *data) +{ + oc_resource_t *resource = (oc_resource_t *)data; + + if (coap_notify_observers(resource, NULL, NULL)) { + return CONTINUE; + } + + return DONE; +} + +static oc_event_callback_t * +get_periodic_observe_callback(oc_resource_t *resource) +{ + oc_event_callback_t *event_cb; + bool found = false; + + for (event_cb = (oc_event_callback_t *)oc_list_head(observe_callbacks); + event_cb; event_cb = event_cb->next) { + if (resource == event_cb->data) { + found = true; + break; + } + } + + if (found) { + return event_cb; + } + + return NULL; +} + +static void +remove_periodic_observe_callback(oc_resource_t *resource) +{ + oc_event_callback_t *event_cb = get_periodic_observe_callback(resource); + + if (event_cb) { + oc_etimer_stop(&event_cb->timer); + oc_list_remove(observe_callbacks, event_cb); + oc_memb_free(&event_callbacks_s, event_cb); + } +} + +static bool +add_periodic_observe_callback(oc_resource_t *resource) +{ + oc_event_callback_t *event_cb = get_periodic_observe_callback(resource); + + if (!event_cb) { + event_cb = (oc_event_callback_t *)oc_memb_alloc(&event_callbacks_s); + + if (!event_cb) + return false; + + event_cb->data = resource; + event_cb->callback = periodic_observe_handler; + OC_PROCESS_CONTEXT_BEGIN(&timed_callback_events); + oc_etimer_set(&event_cb->timer, + resource->observe_period_seconds * OC_CLOCK_SECOND); + OC_PROCESS_CONTEXT_END(&timed_callback_events); + oc_list_add(observe_callbacks, event_cb); + } + + return true; +} +#endif + +oc_interface_mask_t +oc_ri_get_interface_mask(char *iface, int if_len) +{ + oc_interface_mask_t interface = 0; + if (OC_BASELINE_IF_LEN == if_len && + strncmp(iface, OC_RSRVD_IF_BASELINE, if_len) == 0) + interface |= OC_IF_BASELINE; + if (OC_LL_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_LL, if_len) == 0) + interface |= OC_IF_LL; + if (OC_B_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_B, if_len) == 0) + interface |= OC_IF_B; + if (OC_R_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_R, if_len) == 0) + interface |= OC_IF_R; + if (OC_RW_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_RW, if_len) == 0) + interface |= OC_IF_RW; + if (OC_A_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_A, if_len) == 0) + interface |= OC_IF_A; + if (OC_S_IF_LEN == if_len && strncmp(iface, OC_RSRVD_IF_S, if_len) == 0) + interface |= OC_IF_S; + return interface; +} + +static bool +does_interface_support_method(oc_resource_t *resource, + oc_interface_mask_t interface, oc_method_t method) +{ + bool supported = true; + switch (interface) { + /* Per section 7.5.3 of the OCF Core spec, the following three interfaces + * are RETRIEVE-only. + */ + case OC_IF_LL: + case OC_IF_S: + case OC_IF_R: + if (method != OC_GET) + supported = false; + break; + /* Per section 7.5.3 of the OCF Core spec, the following three interfaces + * support RETRIEVE, UPDATE. + * TODO: Refine logic below after adding logic that identifies + * and handles CREATE requests using PUT/POST. + */ + case OC_IF_RW: + case OC_IF_B: + case OC_IF_BASELINE: + /* Per section 7.5.3 of the OCF Core spec, the following interface + * supports CREATE, RETRIEVE and UPDATE. + */ + case OC_IF_A: + break; + } + return supported; +} + +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) +{ + /* Flags that capture status along various stages of processing + * the request. + */ + bool method_impl = true, bad_request = false, success = true; + +#ifdef OC_SECURITY + bool authorized = true; +#endif + + /* Parsed CoAP PDU structure. */ + coap_packet_t *const packet = (coap_packet_t *)request; + + /* This function is a server-side entry point solely for requests. + * Hence, "code" contains the CoAP method code. + */ + oc_method_t method = packet->code; + + /* Initialize request/response objects to be sent up to the app layer. */ + oc_request_t request_obj; + oc_response_buffer_t response_buffer; + oc_response_t response_obj; + + response_buffer.buffer = buffer; + response_buffer.buffer_size = buffer_size; + response_buffer.block_offset = offset; + response_buffer.code = 0; + response_buffer.response_length = 0; + + response_obj.separate_response = 0; + response_obj.response_buffer = &response_buffer; + + request_obj.response = &response_obj; + request_obj.request_payload = 0; + request_obj.query_len = 0; + request_obj.resource = 0; + request_obj.origin = endpoint; + + /* Initialize OCF interface selector. */ + oc_interface_mask_t interface = 0; + + /* Obtain request uri from the CoAP packet. */ + const char *uri_path; + int uri_path_len = coap_get_header_uri_path(request, &uri_path); + + /* Obtain query string from CoAP packet. */ + const char *uri_query; + int uri_query_len = coap_get_header_uri_query(request, &uri_query); + + if (uri_query_len) { + request_obj.query = uri_query; + request_obj.query_len = uri_query_len; + + /* Check if query string includes interface selection. */ + char *iface; + int if_len = oc_ri_get_query_value(uri_query, uri_query_len, "if", &iface); + if (if_len != -1) { + interface |= oc_ri_get_interface_mask(iface, if_len); + } + } + + /* Obtain handle to buffer containing the serialized payload */ + const uint8_t *payload; + int payload_len = coap_get_payload(request, &payload); + if (payload_len) { + /* Attempt to parse request payload using tinyCBOR via oc_rep helper + * functions. The result of this parse is a tree of oc_rep_t structures + * which will reflect the schema of the payload. + * Any failures while parsing the payload is viewed as an erroneous + * request and results in a 4.00 response being sent. + */ + if (oc_parse_rep(payload, payload_len, &request_obj.request_payload) != 0) { + LOG("ocri: error parsing request payload\n"); + bad_request = true; + } + } + + oc_resource_t *resource, *cur_resource = NULL; + + /* If there were no errors thus far, attempt to locate the specific + * resource object that will handle the request using the request uri. + */ + /* Check against list of declared core resources. + */ + if (!bad_request) { + int i; + for (i = 0; i < NUM_OC_CORE_RESOURCES; i++) { + resource = oc_core_get_resource_by_index(i); + if (oc_string_len(resource->uri) == (uri_path_len + 1) && + strncmp((const char *)oc_string(resource->uri) + 1, uri_path, + uri_path_len) == 0) { + request_obj.resource = cur_resource = resource; + break; + } + } + } + +#ifdef OC_SERVER + /* Check against list of declared application resources. + */ + if (!cur_resource && !bad_request) { + for (resource = oc_ri_get_app_resources(); resource; + resource = resource->next) { + if (oc_string_len(resource->uri) == (uri_path_len + 1) && + strncmp((const char *)oc_string(resource->uri) + 1, uri_path, + uri_path_len) == 0) { + request_obj.resource = cur_resource = resource; + break; + } + } + } +#endif + + if (cur_resource) { + /* If there was no interface selection, pick the "default interface". */ + if (interface == 0) + interface = cur_resource->default_interface; + + /* Found the matching resource object. Now verify that: + * 1) the selected interface is one that is supported by + * the resource, and, + * 2) the selected interface supports the request method. + * + * If not, return a 4.00 response. + */ + if (((interface & ~cur_resource->interfaces) != 0) || + !does_interface_support_method(cur_resource, interface, method)) + bad_request = true; + } + + if (cur_resource && !bad_request) { + /* Process a request against a valid resource, request payload, and + * interface. + */ + + /* Initialize oc_rep with a buffer to hold the response payload. "buffer" + * points to memory allocated in the messaging layer for the "CoAP + * Transaction" to service this request. + */ + oc_rep_new(buffer, buffer_size); + +#ifdef OC_SECURITY + /* If cur_resource is a coaps:// resource, then query ACL to check if + * the requestor (the subject) is authorized to issue this request to + * the resource. + */ + if ((cur_resource->properties & OC_SECURE) && + !oc_sec_check_acl(method, cur_resource, endpoint)) { + authorized = false; + } else +#endif + { + /* Invoke a specific request handler for the resource + * based on the request method. If the resource has not + * implemented that method, then return a 4.05 response. + */ + if (method == OC_GET && cur_resource->get_handler) { + cur_resource->get_handler(&request_obj, interface); + } else if (method == OC_POST && cur_resource->post_handler) { + cur_resource->post_handler(&request_obj, interface); + } else if (method == OC_PUT && cur_resource->put_handler) { + cur_resource->put_handler(&request_obj, interface); + } else if (method == OC_DELETE && cur_resource->delete_handler) { + cur_resource->delete_handler(&request_obj, interface); + } else { + method_impl = false; + } + } + } + + if (payload_len) { + /* To the extent that the request payload was parsed, free the + * payload structure (and return its memory to the pool). + */ + oc_free_rep(request_obj.request_payload); + } + + if (bad_request) { + LOG("ocri: Bad request\n"); + /* Return a 4.00 response */ + response_buffer.code = oc_status_code(OC_STATUS_BAD_REQUEST); + success = false; + } else if (!cur_resource) { + LOG("ocri: Could not find resource\n"); + /* Return a 4.04 response if the requested resource was not found */ + response_buffer.response_length = 0; + response_buffer.code = oc_status_code(OC_STATUS_NOT_FOUND); + success = false; + } else if (!method_impl) { + LOG("ocri: Could not find method\n"); + /* Return a 4.05 response if the resource does not implement the + * request method. + */ + response_buffer.response_length = 0; + response_buffer.code = oc_status_code(OC_STATUS_METHOD_NOT_ALLOWED); + success = false; + } +#ifdef OC_SECURITY + else if (!authorized) { + LOG("ocri: Subject not authorized\n"); + /* If the requestor (subject) does not have access granted via an + * access control entry in the ACL, then it is not authorized to + * access the resource. A 4.03 response is sent. + */ + response_buffer.response_length = 0; + response_buffer.code = oc_status_code(OC_STATUS_FORBIDDEN); + success = false; + } +#endif + +#ifdef OC_SERVER + /* If a GET request was successfully processed, then check its + * observe option. + */ + uint32_t observe = 2; + if (success && coap_get_header_observe(request, &observe)) { + /* Check if the resource is OBSERVABLE */ + if (cur_resource->properties & OC_OBSERVABLE) { + /* If the observe option is set to 0, make an attempt to add the + * requesting client as an observer. + */ + if (observe == 0) { + if (coap_observe_handler(request, response, cur_resource, endpoint) == + 0) { + /* If the resource is marked as periodic observable it means + * it must be polled internally for updates (which would lead to + * notifications being sent). If so, add the resource to a list of + * periodic GET callbacks to utilize the framework's internal + * polling mechanism. + */ + bool set_observe_option = true; + if (cur_resource->properties & OC_PERIODIC) { + if (!add_periodic_observe_callback(cur_resource)) { + set_observe_option = false; + coap_remove_observer_by_token(endpoint, packet->token, + packet->token_len); + } + } + + if (set_observe_option) { + coap_set_header_observe(response, 0); + } + } + } + /* If the observe option is set to 1, make an attempt to remove + * the requesting client from the list of observers. In addition, + * remove the resource from the list periodic GET callbacks if it + * is periodic observable. + */ + else if (observe == 1) { + if (coap_observe_handler(request, response, cur_resource, endpoint) > + 0) { + if (cur_resource->properties & OC_PERIODIC) { + remove_periodic_observe_callback(cur_resource); + } + } + } + } + } +#endif + +#ifdef OC_SERVER + /* The presence of a separate response handle here indicates a + * successful handling of the request by a slow resource. + */ + if (response_obj.separate_response != NULL) { + /* Attempt to register a client request to the separate response tracker + * and pass in the observe option (if present) or the value 2 as + * determined by the code block above. Values 0 and 1 result in their + * expected behaviors whereas 2 indicates an absence of an observe + * option and hence a one-off request. + * Following a successful registration, the separate response tracker + * is flagged as "active". In this way, the function that later executes + * out-of-band upon availability of the resource state knows it must + * send out a response with it. + */ + if (coap_separate_accept(request, response_obj.separate_response, endpoint, + observe) == 1) + response_obj.separate_response->active = 1; + } else +#endif + if (response_buffer.code == OC_IGNORE) { + /* If the server-side logic chooses to reject a request, it sends + * below a response code of IGNORE, which results in the messaging + * layer freeing the CoAP transaction associated with the request. + */ + erbium_status_code = CLEAR_TRANSACTION; + } else { +#ifdef OC_SERVER + /* If the recently handled request was a PUT/POST, it conceivably + * altered the resource state, so attempt to notify all observers + * of that resource with the change. + */ + if ((method == OC_PUT || method == OC_POST) && + response_buffer.code < oc_status_code(OC_STATUS_BAD_REQUEST)) + coap_notify_observers(cur_resource, NULL, NULL); +#endif + if (response_buffer.response_length) { + coap_set_payload(response, response_buffer.buffer, + response_buffer.response_length); + coap_set_header_content_format(response, APPLICATION_CBOR); + } + /* response_buffer.code at this point contains a valid CoAP status + * code. + */ + coap_set_status_code(response, response_buffer.code); + } + return success; +} + +#ifdef OC_CLIENT +static void +free_client_cb(oc_client_cb_t *cb) +{ + oc_free_string(&cb->uri); + oc_list_remove(client_cbs, cb); + oc_memb_free(&client_cbs_s, cb); +} + +void +oc_ri_remove_client_cb_by_mid(uint16_t mid) +{ + oc_client_cb_t *cb = (oc_client_cb_t *)oc_list_head(client_cbs); + while (cb != NULL) { + if (cb->mid == mid) + break; + cb = cb->next; + } + if (cb) + free_client_cb(cb); +} + +oc_event_callback_retval_t +oc_ri_remove_client_cb(void *data) +{ + free_client_cb(data); + return DONE; +} + +bool +oc_ri_send_rst(oc_endpoint_t *endpoint, uint8_t *token, uint8_t token_len, + uint16_t mid) +{ + coap_packet_t rst[1]; + coap_init_message(rst, COAP_TYPE_RST, 0, mid); + coap_set_header_observe(rst, 1); + coap_set_token(rst, token, token_len); + oc_message_t *message = oc_allocate_message(); + if (message) { + message->length = coap_serialize_message(rst, message->data); + coap_send_message(message); + return true; + } + return false; +} + +bool +oc_ri_invoke_client_cb(void *response, oc_endpoint_t *endpoint) +{ + uint8_t *payload; + int payload_len; + coap_packet_t *const pkt = (coap_packet_t *)response; + oc_client_cb_t *cb = oc_list_head(client_cbs); + int i; + /* + if con then send ack and process as above + -empty ack sent from below by engine + if ack with piggyback then process as above + -processed below + if ack and empty then it is a separate response, and keep cb + -handled by separate flag + if ack is for block then store data and pass to client + */ + + unsigned int content_format = APPLICATION_CBOR; + coap_get_header_content_format(pkt, &content_format); + + while (cb != NULL) { + if (cb->token_len == pkt->token_len && + memcmp(cb->token, pkt->token, pkt->token_len) == 0) { + + /* If content format is not CBOR, then reject response + and clear callback + If incoming response type is RST, then clear callback + */ + if (content_format != APPLICATION_CBOR || pkt->type == COAP_TYPE_RST) { + free_client_cb(cb); + break; + } + + /* Check code, translate to oc_status_code, store + Check observe option: + if no observe option, set to -1, else store observe seq + */ + oc_client_response_t client_response; + client_response.observe_option = -1; + client_response.payload = 0; + + for (i = 0; i < __NUM_OC_STATUS_CODES__; i++) { + if (oc_coap_status_codes[i] == pkt->code) { + client_response.code = i; + break; + } + } + coap_get_header_observe(pkt, (uint32_t*)&client_response.observe_option); + + bool separate = false; + /* + if payload exists, process payload and save in client response + send client response to callback and return + */ + payload_len = coap_get_payload(response, (const uint8_t **)&payload); + if (payload_len) { + if (cb->discovery) { + if (oc_ri_process_discovery_payload(payload, payload_len, cb->handler, + endpoint) == OC_STOP_DISCOVERY) { + oc_ri_remove_client_cb(cb); + } + } else { + uint16_t err = + oc_parse_rep(payload, payload_len, &client_response.payload); + if (err == 0) { + oc_response_handler_t handler = (oc_response_handler_t)cb->handler; + handler(&client_response); + } + oc_free_rep(client_response.payload); + } + } else { // no payload + if (pkt->type == COAP_TYPE_ACK && pkt->code == 0) { + separate = true; + } else if (!cb->discovery) { + oc_response_handler_t handler = (oc_response_handler_t)cb->handler; + handler(&client_response); + } + } + + /* check observe sequence number: + if -1 then remove cb, else keep cb + if it is an ACK for a separate response, keep cb + if it is a discovery response, keep cb so that it will last + for the entirety of OC_CLIENT_CB_TIMEOUT_SECS + */ + if (client_response.observe_option == -1 && !separate && !cb->discovery) { + oc_ri_remove_timed_event_callback(cb, &oc_ri_remove_client_cb); + free_client_cb(cb); + } else + cb->observe_seq = client_response.observe_option; + + break; + } + cb = cb->next; + } + + return true; +} + +oc_client_cb_t * +oc_ri_get_client_cb(const char *uri, oc_server_handle_t *server, + oc_method_t method) +{ + oc_client_cb_t *cb = (oc_client_cb_t *)oc_list_head(client_cbs); + + while (cb != NULL) { + if (oc_string_len(cb->uri) == strlen(uri) && + strncmp(oc_string(cb->uri), uri, strlen(uri)) == 0 && + memcmp(&cb->server.endpoint, &server->endpoint, + sizeof(oc_endpoint_t)) == 0 && + cb->method == method) + return cb; + + cb = cb->next; + } + + return cb; +} + +oc_client_cb_t * +oc_ri_alloc_client_cb(const char *uri, oc_server_handle_t *server, + oc_method_t method, void *handler, oc_qos_t qos) +{ + oc_client_cb_t *cb = oc_memb_alloc(&client_cbs_s); + if (!cb) + return cb; + + cb->mid = coap_get_mid(); + oc_new_string(&cb->uri, uri); + cb->method = method; + cb->qos = qos; + cb->handler = handler; + cb->token_len = 8; + int i = 0; + uint16_t r; + while (i < cb->token_len) { + r = oc_random_rand(); + memcpy(cb->token + i, &r, sizeof(r)); + i += sizeof(r); + } + cb->discovery = false; + cb->timestamp = oc_clock_time(); + cb->observe_seq = -1; + memcpy(&cb->server, server, sizeof(oc_server_handle_t)); + + oc_list_add(client_cbs, cb); + return cb; +} +#endif /* OC_CLIENT */ + +OC_PROCESS_THREAD(timed_callback_events, ev, data) +{ + OC_PROCESS_BEGIN(); + while (1) { + OC_PROCESS_YIELD(); + if (ev == OC_PROCESS_EVENT_TIMER) { + check_event_callbacks(); + } + } + OC_PROCESS_END(); +} + +// TODO: +// resource collections +// if method accepted by interface selection +// resources for presence based discovery http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_server_api.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_server_api.c b/net/oic/src/api/oc_server_api.c new file mode 100644 index 0000000..054a91c --- /dev/null +++ b/net/oic/src/api/oc_server_api.c @@ -0,0 +1,291 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "messaging/coap/engine.h" +#include "messaging/coap/oc_coap.h" +#include "messaging/coap/separate.h" +#include "oc_api.h" +#include "oc_constants.h" +#include "oc_core_res.h" + +extern int oc_stack_errno; +// TODO: +// 0x01: Couldnt add platform +// 0x02: Couldnt add device +// 0x03: CBOR error + +void +oc_add_device(const char *uri, const char *rt, const char *name, + const char *spec_version, const char *data_model_version, + oc_add_device_cb_t add_device_cb, void *data) +{ + oc_string_t *payload; + + payload = oc_core_add_new_device(uri, rt, name, spec_version, + data_model_version, add_device_cb, data); + if (!payload) + oc_stack_errno |= 0x02; +} + +void +oc_init_platform(const char *mfg_name, oc_init_platform_cb_t init_platform_cb, + void *data) +{ + oc_string_t *payload; + + payload = oc_core_init_platform(mfg_name, init_platform_cb, data); + if (!payload) + oc_stack_errno |= 0x01; +} + +int +oc_get_query_value(oc_request_t *request, const char *key, char **value) +{ + return oc_ri_get_query_value(request->query, request->query_len, key, value); +} + +static int +response_length(void) +{ + int size = oc_rep_finalize(); + return (size <= 2) ? 0 : size; +} + +void +oc_send_response(oc_request_t *request, oc_status_t response_code) +{ + // FIX:: set errno if CBOR encoding failed. + request->response->response_buffer->response_length = response_length(); + request->response->response_buffer->code = oc_status_code(response_code); +} + +void +oc_ignore_request(oc_request_t *request) +{ + request->response->response_buffer->code = OC_IGNORE; +} + +void +oc_set_delayed_callback(void *cb_data, oc_trigger_t callback, uint16_t seconds) +{ + oc_ri_add_timed_event_callback_seconds(cb_data, callback, seconds); +} + +void +oc_remove_delayed_callback(void *cb_data, oc_trigger_t callback) +{ + oc_ri_remove_timed_event_callback(cb_data, callback); +} + +void +oc_process_baseline_interface(oc_resource_t *resource) +{ + oc_rep_set_string_array(root, rt, resource->types); + oc_core_encode_interfaces_mask(oc_rep_object(root), resource->interfaces); + oc_rep_set_uint(root, p, resource->properties & ~OC_PERIODIC); +} + +#ifdef OC_SERVER +static int query_iterator; + +// FIX: validate uri +oc_resource_t * +oc_new_resource(const char *uri, uint8_t num_resource_types, int device) +{ + oc_resource_t *resource = oc_ri_alloc_resource(); + const char *start = uri; + size_t end = strlen(uri); + oc_alloc_string(&resource->uri, end + 1); + strncpy((char *)oc_string(resource->uri), start, end); + strcpy((char *)oc_string(resource->uri) + end, (const char *)""); + oc_new_string_array(&resource->types, num_resource_types); + resource->interfaces = OC_IF_BASELINE; + resource->default_interface = OC_IF_BASELINE; + resource->observe_period_seconds = 0; + resource->properties = OC_ACTIVE; + resource->num_observers = 0; + resource->device = device; + return resource; +} + +void +oc_resource_bind_resource_interface(oc_resource_t *resource, uint8_t interface) +{ + resource->interfaces |= interface; +} + +void +oc_resource_set_default_interface(oc_resource_t *resource, + oc_interface_mask_t interface) +{ + resource->default_interface = interface; +} + +void +oc_resource_bind_resource_type(oc_resource_t *resource, const char *type) +{ + oc_string_array_add_item(resource->types, (char *)type); +} + +#ifdef OC_SECURITY +void +oc_resource_make_secure(oc_resource_t *resource) +{ + resource->properties |= OC_SECURE; +} +#endif /* OC_SECURITY */ + +void +oc_resource_set_discoverable(oc_resource_t *resource) +{ + resource->properties |= OC_DISCOVERABLE; +} + +void +oc_resource_set_observable(oc_resource_t *resource) +{ + resource->properties |= OC_OBSERVABLE; +} + +void +oc_resource_set_periodic_observable(oc_resource_t *resource, uint16_t seconds) +{ + resource->properties |= OC_OBSERVABLE | OC_PERIODIC; + resource->observe_period_seconds = seconds; +} + +void +oc_deactivate_resource(oc_resource_t *resource) +{ + resource->properties ^= OC_ACTIVE; +} + +void +oc_resource_set_request_handler(oc_resource_t *resource, oc_method_t method, + oc_request_handler_t handler) +{ + switch (method) { + case OC_GET: + resource->get_handler = handler; + break; + case OC_POST: + resource->post_handler = handler; + break; + case OC_PUT: + resource->put_handler = handler; + break; + case OC_DELETE: + resource->delete_handler = handler; + break; + default: + break; + } +} + +bool +oc_add_resource(oc_resource_t *resource) +{ + return oc_ri_add_resource(resource); +} + +void +oc_delete_resource(oc_resource_t *resource) +{ + oc_ri_delete_resource(resource); +} + +void +oc_init_query_iterator(oc_request_t *request) +{ + query_iterator = 0; +} + +int +oc_interate_query(oc_request_t *request, char **key, int *key_len, char **value, + int *value_len) +{ + if (query_iterator >= request->query_len) + return -1; + query_iterator += oc_ri_get_query_nth_key_value( + request->query + query_iterator, request->query_len - query_iterator, key, + key_len, value, value_len, 1); + return 1; +} + +void +oc_indicate_separate_response(oc_request_t *request, + oc_separate_response_t *response) +{ + request->response->separate_response = response; + oc_send_response(request, OC_STATUS_OK); +} + +void +oc_set_separate_response_buffer(oc_separate_response_t *handle) +{ + oc_rep_new(handle->buffer, COAP_MAX_BLOCK_SIZE); // check +} + +void +oc_send_separate_response(oc_separate_response_t *handle, + oc_status_t response_code) +{ + oc_response_buffer_t response_buffer; + response_buffer.buffer = handle->buffer; + response_buffer.response_length = response_length(); + response_buffer.code = oc_status_code(response_code); + + coap_separate_t *cur = oc_list_head(handle->requests), *next = NULL; + coap_packet_t response[1]; + + while (cur != NULL) { + next = cur->next; + if (cur->observe > 0) { + coap_transaction_t *t = + coap_new_transaction(coap_get_mid(), &cur->endpoint); + if (t) { + coap_separate_resume(response, cur, oc_status_code(response_code), + t->mid); + coap_set_header_content_format(response, APPLICATION_CBOR); + if (cur->observe == 1) { + coap_set_header_observe(response, 1); + } + if (response_buffer.response_length > 0) { + coap_set_payload(response, handle->buffer, + response_buffer.response_length); + } + t->message->length = coap_serialize_message(response, t->message->data); + coap_send_transaction(t); + } + coap_separate_clear(handle, cur); + } else { + if (coap_notify_observers(NULL, &response_buffer, &cur->endpoint) == 0) { + coap_separate_clear(handle, cur); + } + } + cur = next; + } + if (oc_list_length(handle->requests) == 0) { + handle->active = 0; + } +} + +int +oc_notify_observers(oc_resource_t *resource) +{ + return coap_notify_observers(resource, NULL, NULL); +} +#endif /* OC_SERVER */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f88168c2/net/oic/src/api/oc_uuid.c ---------------------------------------------------------------------- diff --git a/net/oic/src/api/oc_uuid.c b/net/oic/src/api/oc_uuid.c new file mode 100644 index 0000000..2ceaf7a --- /dev/null +++ b/net/oic/src/api/oc_uuid.c @@ -0,0 +1,119 @@ +/* +// Copyright (c) 2016 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "oc_uuid.h" +#include "port/oc_random.h" +#include <ctype.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +void +oc_str_to_uuid(const char *str, oc_uuid_t *uuid) +{ + int i, j = 0, k = 1; + uint8_t c = 0; + + for (i = 0; i < strlen(str); i++) { + if (str[i] == '-') + continue; + else if (isalpha(str[i])) { + switch (str[i]) { + case 65: + case 97: + c |= 0x0a; + break; + case 66: + case 98: + c |= 0x0b; + break; + case 67: + case 99: + c |= 0x0c; + break; + case 68: + case 100: + c |= 0x0d; + break; + case 69: + case 101: + c |= 0x0e; + break; + case 70: + case 102: + c |= 0x0f; + break; + } + } else + c |= str[i] - 48; + if ((j + 1) * 2 == k) { + uuid->id[j++] = c; + c = 0; + } else + c = c << 4; + k++; + } +} + +void +oc_uuid_to_str(const oc_uuid_t *uuid, char *buffer, int buflen) +{ + int i, j = 0; + if (buflen < 37) + return; + for (i = 0; i < 16; i++) { + switch (i) { + case 4: + case 6: + case 8: + case 10: + snprintf(&buffer[j], 2, "-"); + j++; + break; + } + snprintf(&buffer[j], 3, "%02x", uuid->id[i]); + j += 2; + } +} + +void +oc_gen_uuid(oc_uuid_t *uuid) +{ + int i; + uint16_t r; + + for (i = 0; i < 8; i++) { + r = oc_random_rand(); + memcpy((uint8_t *)&uuid->id[i * 2], (uint8_t *)&r, sizeof(r)); + } + + /* From RFC 4122 + Set the two most significant bits of the + clock_seq_hi_and_reserved (8th octect) to + zero and one, respectively. + */ + uuid->id[8] &= 0x3f; + uuid->id[8] |= 0x40; + + /* From RFC 4122 + Set the four most significant bits of the + time_hi_and_version field (6th octect) to the + 4-bit version number from (0 1 0 0 => type 4) + Section 4.1.3. + */ + uuid->id[6] &= 0x0f; + uuid->id[6] |= 0x40; +}