blob: b00b33c2f5dd5685e3d9e3e204974a2e6c76f4c0 [file] [log] [blame]
/*
// 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 */