| /* |
| // 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 "os/mynewt.h" |
| |
| #include "oic/port/mynewt/config.h" |
| #ifdef OC_CLIENT |
| #include "oic/oc_client_state.h" |
| #endif /* OC_CLIENT */ |
| |
| #include "oic/messaging/coap/oc_coap.h" |
| #include "oic/oc_api.h" |
| #include "oic/oc_core_res.h" |
| #include "oic/port/mynewt/ip.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; |
| #ifdef OC_SERVER |
| oc_resource_t *resource; |
| #endif |
| 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 |
| for (resource = oc_ri_get_app_resources(); resource; |
| resource = SLIST_NEXT(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 *req, oc_interface_mask_t interface) |
| { |
| char *rt = NULL; |
| int rt_len = 0, matches = 0; |
| char uuid[37]; |
| |
| rt_len = oc_ri_get_query_value(req->query, req->query_len, "rt", &rt); |
| |
| oc_uuid_to_str(oc_core_get_device_id(0), uuid, sizeof(uuid)); |
| |
| 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(req->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) { |
| req->response->response_buffer->response_length = response_length; |
| req->response->response_buffer->code = oc_status_code(OC_STATUS_OK); |
| } else { |
| /* There were rt/if selections and there were no matches, so ignore */ |
| req->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 |
| #if MYNEWT_VAL(OC_CLIENT_DISCOVERY_ENABLE) |
| oc_discovery_flags_t |
| oc_ri_process_discovery_payload(struct coap_packet_rx *rsp, |
| oc_discovery_cb_t *handler, |
| oc_endpoint_t *endpoint) |
| { |
| oc_discovery_flags_t ret = OC_CONTINUE_DISCOVERY; |
| oc_string_t uri = { |
| .os_sz = 0, |
| .os_str = NULL |
| }; |
| oc_string_t di = { |
| .os_sz = 0, |
| .os_str = NULL |
| }; |
| bool secure = false; |
| uint16_t dtls_port = 0, default_port = 0; |
| oc_string_array_t types = {}; |
| oc_interface_mask_t interfaces = 0; |
| oc_server_handle_t handle; |
| uint16_t data_off; |
| struct os_mbuf *m; |
| int len; |
| struct oc_endpoint_ip *ip; |
| |
| memcpy(&handle.endpoint, endpoint, oc_endpoint_size(endpoint)); |
| if (oc_endpoint_is_ip(endpoint)) { |
| default_port = ((struct oc_endpoint_ip *)endpoint)->port; |
| } |
| |
| oc_rep_t *array = 0, *rep; |
| |
| len = coap_get_payload(rsp, &m, &data_off); |
| int s = oc_parse_rep(m, data_off, 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 (default_port) { |
| ip = (struct oc_endpoint_ip *)&handle.endpoint; |
| if (secure) { |
| ip->port = dtls_port; |
| ip->ep.oe_flags |= OC_ENDPOINT_SECURED; |
| } else { |
| ip->port = default_port; |
| ip->ep.oe_flags &= ~OC_ENDPOINT_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_DISCOVERY_ENABLE */ |
| #endif /* OC_CLIENT */ |