diff --git a/examples/cord_lc/Makefile b/examples/cord_lc/Makefile new file mode 100644 index 0000000000..d273c20f87 --- /dev/null +++ b/examples/cord_lc/Makefile @@ -0,0 +1,34 @@ +# name of your application +APPLICATION = cord_lc + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +USEMODULE += gnrc_netdev_default +USEMODULE += auto_init_gnrc_netif +USEMODULE += gnrc_ipv6_default +USEMODULE += gnrc_icmpv6_echo + +USEMODULE += cord_lc + +USEMODULE += shell +USEMODULE += shell_commands +USEMODULE += ps + +# The default size of GCOAP_PDU_BUF_SIZE can be too small for the response +# from the RD server. Use a larger value if the client drops response packet +# from RD server. +CFLAGS += -DCONFIG_GCOAP_PDU_BUF_SIZE=512 + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include diff --git a/examples/cord_lc/Makefile.ci b/examples/cord_lc/Makefile.ci new file mode 100644 index 0000000000..4f5b594b69 --- /dev/null +++ b/examples/cord_lc/Makefile.ci @@ -0,0 +1,34 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-mega2560 \ + arduino-nano \ + arduino-uno \ + atmega1284p \ + atmega328p \ + chronos \ + derfmega128 \ + hifive1 \ + hifive1b \ + i-nucleo-lrwan1 \ + im880b \ + mega-xplained \ + microduino-corerf \ + msb-430 \ + msb-430h \ + nucleo-f030r8 \ + nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-f303k8 \ + nucleo-f334r8 \ + nucleo-l031k6 \ + nucleo-l053r8 \ + stm32f030f4-demo \ + stm32f0discovery \ + stm32l0538-disco \ + telosb \ + waspmote-pro \ + wsn430-v1_3b \ + wsn430-v1_4 \ + z1 \ + # diff --git a/examples/cord_lc/README.md b/examples/cord_lc/README.md new file mode 100644 index 0000000000..40fc32e296 --- /dev/null +++ b/examples/cord_lc/README.md @@ -0,0 +1,16 @@ +CoRE Resource Directory: Lookup Example +========================================= + +This example application demonstrates the usage of RIOT's Resource Directory +(RD) lookup module, called `cord_lc`. This module supports the lookup of +resources and endpoints as defined in +[draft-ietf-core-resource-directory-20](https://tools.ietf.org/html/draft-ietf-core-resource-directory-23). +The lookup can be done in two modes: a) raw: result of the lookup is returned +as is. b) pre-parsed: result of the lookup is parsed and only one link is +returned for each call. + +Usage +===== +The examples includes a shell command that you can use to interact with a given +RD, called `cord_lc`. Simply use that shell command without parameters for +more information on its usage. \ No newline at end of file diff --git a/examples/cord_lc/cord_lc_cli.c b/examples/cord_lc/cord_lc_cli.c new file mode 100644 index 0000000000..b07ca26b28 --- /dev/null +++ b/examples/cord_lc/cord_lc_cli.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2018 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief Shell command for the cord_lc module + * + * @author Aiman Ismail + * + * @} + */ + +#include +#include + +#include "net/cord/config.h" +#include "net/cord/lc.h" +#include "net/gcoap.h" +#include "net/sock/util.h" + +static cord_lc_rd_t rd; +static sock_udp_ep_t remote; +static char rdbuf[2 * CONFIG_NANOCOAP_URI_MAX] = {0}; +static unsigned rd_initialized = 0; + +static int make_sock_ep(sock_udp_ep_t *ep, const char *addr) +{ + ep->port = 0; + if (sock_udp_str2ep(ep, addr) < 0) { + return -1; + } + /* if netif not specified in addr */ + if ((ep->netif == SOCK_ADDR_ANY_NETIF) && (gnrc_netif_numof() == 1)) { + /* assign the single interface found in gnrc_netif_numof() */ + ep->netif = (uint16_t)gnrc_netif_iter(NULL)->pid; + } + ep->family = AF_INET6; + if (ep->port == 0) { + ep->port = COAP_PORT; + } + return 0; +} + +/** + * Parses main arguments for filters. + * Returns number of parsed filters + */ +static void _parse_filters(clif_attr_t *filters, size_t filter_count, + char **argv) { + for (unsigned i = 0; i < filter_count; i++) { + clif_attr_t *f = &filters[i]; + f->key = argv[i]; + char *key_end = memchr(argv[i], '=', strlen(argv[i])); + if (!key_end) { + f->key_len = strlen(f->key); + f->value = NULL; + f->value_len = 0; + } + else { + f->key_len = key_end - f->key; + f->value = key_end + 1; + f->value_len = strlen(f->value); + } + } +} + +static void _print_lookup_result(struct cord_lc_result *res) { + printf("Found resource/endpoint\n"); + printf("Target: %.*s\n", res->link.target_len, res->link.target); + for (unsigned i = 0; i < res->link.attrs_len; i++) { + clif_attr_t *p = &(res->link.attrs[i]); + printf("'%.*s': '%.*s'\n", p->key_len, p->key, p->value_len, p->value); + } +} + +static void _print_usage(void) { + puts("usage: cord_lc " + "[-r] { resource | endpoint } [key=value]\n" + "Options:\n" + " -r get raw result\n" + "example: cord_lc [2001:db8:3::dead:beef]:5683 -r resource count=1 page=2\n" + "example: cord_lc [2001:db8:3::dead:beef]:5683 endpoint"); +} + +int cord_lc_cli_cmd(int argc, char **argv) { + char bufpool[1024] = {0}; + int raw_mode = 0; + + raw_mode = argc > 3 && !strcmp(argv[2], "-r"); + if (argc < 3 || (raw_mode && argc < 4)) { + _print_usage(); + return -1; + } + + if (!rd_initialized) { + int ret = make_sock_ep(&remote, argv[1]); + if (ret < 0) { + printf("error: unable to parse address\n"); + return -1; + } + puts("Performing lookup now, this may take a short while..."); + ret = cord_lc_rd_init(&rd, rdbuf, sizeof(rdbuf), &remote); + if (ret < 0) { + printf("error initializing RD server %d", ret); + return -1; + } + rd_initialized = 1; + } + + /* parse filters */ + unsigned filter_start = raw_mode ? 4 : 3; + size_t filter_count = argc - filter_start; + clif_attr_t filter_array[filter_count]; + if (filter_count > 0) { + _parse_filters(filter_array, filter_count, &argv[filter_start]); + } + cord_lc_filter_t filters = { + .array = filter_array, + .len = filter_count, + .next = NULL, + }; + + int retval = 0; + if (raw_mode) { + if (!strcmp(argv[3], "resource")) { + retval = cord_lc_raw(&rd, COAP_FORMAT_LINK, CORD_LC_RES, &filters, + bufpool, sizeof(bufpool)); + } else if (!strcmp(argv[3], "endpoint")) { + retval = cord_lc_raw(&rd, COAP_FORMAT_LINK, CORD_LC_EP, &filters, + bufpool, sizeof(bufpool)); + } else { + _print_usage(); + return -1; + } + if (retval < 0) { + printf("Error during lookup %d\n", retval); + return -1; + } + printf("Lookup result:\n%.*s\n", retval, bufpool); + } else if (!strcmp(argv[2], "resource")) { + cord_lc_res_t resource; + clif_attr_t attrs[5]; + resource.attrs = attrs; + resource.max_attrs = ARRAY_SIZE(attrs); + retval = + cord_lc_res(&rd, &resource, &filters, bufpool, sizeof(bufpool)); + if (retval < 0) { + printf("Error during lookup %d\n", retval); + return -1; + } + _print_lookup_result(&resource); + } else if (!strcmp(argv[2], "endpoint")) { + cord_lc_ep_t endpoint; + clif_attr_t attrs[5]; + endpoint.attrs = attrs; + endpoint.max_attrs = ARRAY_SIZE(attrs); + retval = cord_lc_ep(&rd, &endpoint, &filters, bufpool, sizeof(bufpool)); + if (retval < 0) { + printf("Error during lookup %d\n", retval); + return -1; + } + _print_lookup_result(&endpoint); + } else { + _print_usage(); + return -1; + } + return 0; +} diff --git a/examples/cord_lc/main.c b/examples/cord_lc/main.c new file mode 100644 index 0000000000..f8a8a49ec3 --- /dev/null +++ b/examples/cord_lc/main.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2018 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief CoRE Resource Directory lookup (cord_lc) example + * + * @author Aiman Ismail + * + * @} + */ + +#include + +#include "shell.h" +#include "msg.h" + +#define MAIN_QUEUE_SIZE (8) +static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; + +extern int cord_lc_cli_cmd(int argc, char **argv); + +static const shell_command_t shell_commands[] = { + { "cord_lc", "Cord LC example", cord_lc_cli_cmd }, + { NULL, NULL, NULL }, +}; + +int main(void) +{ + /* we need a message queue for the thread running the shell in order to + * receive potentially fast incoming networking packets */ + msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); + + puts("CoRE RD lookup client example!\n"); + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}