/* * Copyright (c) 2018 Ken Bannister. All rights reserved. * * 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 tests * @{ * * @file * @brief nanocoap test CLI client * * @author Ken Bannister * * @} */ #include #include #include #include #include "net/coap.h" #include "net/nanocoap.h" #include "net/nanocoap_sock.h" #include "net/sock/udp.h" #include "od.h" static ssize_t _send(coap_pkt_t *pkt, size_t len, char *addr_str, char *port_str) { ipv6_addr_t addr; sock_udp_ep_t remote; remote.family = AF_INET6; /* parse for interface */ char *iface = ipv6_addr_split_iface(addr_str); if (!iface) { if (gnrc_netif_numof() == 1) { /* assign the single interface found in gnrc_netif_numof() */ remote.netif = (uint16_t)gnrc_netif_iter(NULL)->pid; } else { remote.netif = SOCK_ADDR_ANY_NETIF; } } else { int pid = atoi(iface); if (gnrc_netif_get_by_pid(pid) == NULL) { puts("nanocli: interface not valid"); return 0; } remote.netif = pid; } /* parse destination address */ if (ipv6_addr_from_str(&addr, addr_str) == NULL) { puts("nanocli: unable to parse destination address"); return 0; } if ((remote.netif == SOCK_ADDR_ANY_NETIF) && ipv6_addr_is_link_local(&addr)) { puts("nanocli: must specify interface for link local target"); return 0; } memcpy(&remote.addr.ipv6[0], &addr.u8[0], sizeof(addr.u8)); /* parse port */ remote.port = atoi(port_str); if (remote.port == 0) { puts("nanocli: unable to parse destination port"); return 0; } return nanocoap_request(pkt, NULL, &remote, len); } int nanotest_client_cmd(int argc, char **argv) { /* Ordered like the RFC method code numbers, but off by 1. GET is code 0. */ char *method_codes[] = {"get", "post", "put"}; unsigned buflen = 128; uint8_t buf[buflen]; coap_pkt_t pkt; size_t len; uint8_t token[2] = {0xDA, 0xEC}; if (argc == 1) { /* show help for commands */ goto end; } int code_pos = -1; for (size_t i = 0; i < ARRAY_SIZE(method_codes); i++) { if (strcmp(argv[1], method_codes[i]) == 0) { code_pos = i; } } if (code_pos == -1) { goto end; } pkt.hdr = (coap_hdr_t *)buf; /* parse options */ if (argc == 5 || argc == 6) { ssize_t hdrlen = coap_build_hdr(pkt.hdr, COAP_TYPE_CON, &token[0], 2, code_pos+1, 1); coap_pkt_init(&pkt, &buf[0], buflen, hdrlen); coap_opt_add_string(&pkt, COAP_OPT_URI_PATH, argv[4], '/'); if (argc == 6) { coap_opt_add_uint(&pkt, COAP_OPT_CONTENT_FORMAT, COAP_FORMAT_TEXT); len = coap_opt_finish(&pkt, COAP_OPT_FINISH_PAYLOAD); pkt.payload_len = strlen(argv[5]); memcpy(pkt.payload, argv[5], pkt.payload_len); len += pkt.payload_len; } else { len = coap_opt_finish(&pkt, COAP_OPT_FINISH_NONE); } printf("nanocli: sending msg ID %u, %u bytes\n", coap_get_id(&pkt), (unsigned) len); ssize_t res = _send(&pkt, buflen, argv[2], argv[3]); if (res < 0) { printf("nanocli: msg send failed: %d\n", (int)res); } else { char *class_str = (coap_get_code_class(&pkt) == COAP_CLASS_SUCCESS) ? "Success" : "Error"; printf("nanocli: response %s, code %1u.%02u", class_str, coap_get_code_class(&pkt), coap_get_code_detail(&pkt)); if (pkt.payload_len) { unsigned format = coap_get_content_type(&pkt); if (format == COAP_FORMAT_TEXT || format == COAP_FORMAT_LINK || coap_get_code_class(&pkt) == COAP_CLASS_CLIENT_FAILURE || coap_get_code_class(&pkt) == COAP_CLASS_SERVER_FAILURE) { /* Expecting diagnostic payload in failure cases */ printf(", %u bytes\n%.*s\n", pkt.payload_len, pkt.payload_len, (char *)pkt.payload); } else { printf(", %u bytes\n", pkt.payload_len); od_hex_dump(pkt.payload, pkt.payload_len, OD_WIDTH_DEFAULT); } } else { printf(", empty payload\n"); } } return 0; } end: printf("usage: %s [%%iface] [data]\n", argv[0]); return 1; }