From 91920268e0f3ce0f31afe307a7768990f224fec3 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Wed, 22 Jan 2020 09:35:53 -0500 Subject: [PATCH] net: remove sample implementing NATS A sample implementing NATS protocol that is not part of the Zephyr networking subsystem. The implementation is not maintained and only served as a proof of concept. Related to #20017 Signed-off-by: Anas Nashif --- samples/net/nats/CMakeLists.txt | 8 - samples/net/nats/README.rst | 163 -------- samples/net/nats/prj.conf | 23 -- samples/net/nats/sample.yaml | 7 - samples/net/nats/src/main.c | 330 ----------------- samples/net/nats/src/nats.c | 632 -------------------------------- samples/net/nats/src/nats.h | 47 --- 7 files changed, 1210 deletions(-) delete mode 100644 samples/net/nats/CMakeLists.txt delete mode 100644 samples/net/nats/README.rst delete mode 100644 samples/net/nats/prj.conf delete mode 100644 samples/net/nats/sample.yaml delete mode 100644 samples/net/nats/src/main.c delete mode 100644 samples/net/nats/src/nats.c delete mode 100644 samples/net/nats/src/nats.h diff --git a/samples/net/nats/CMakeLists.txt b/samples/net/nats/CMakeLists.txt deleted file mode 100644 index 0eff05642af..00000000000 --- a/samples/net/nats/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.13.1) -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) -project(nats) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) diff --git a/samples/net/nats/README.rst b/samples/net/nats/README.rst deleted file mode 100644 index 3b82cc0973e..00000000000 --- a/samples/net/nats/README.rst +++ /dev/null @@ -1,163 +0,0 @@ -.. _NATS_Client_Sample: - - -NATS Client Implementation Sample -################################# - - -Overview -******** - -`NATS `__ is a -publisher/subscriber protocol implemented on top of TCP. It is specified in -`NATS Protocol documentation `__, -and this is a sample implementation for Zephyr using the new IP stack. -The API is loosely based off of the `Golang API -`__. - -With this sample, it's possible to subscribe/unsubscribe to a given subject, -and be notified of changes asynchronously. In order to conserve resources, -the implementation does not keep track of subscribed subjects; that -must be performed by the application itself, so it can ignore unknown/undesired -subjects. - -TLS is not supported yet, although basic authentication is. The client will indicate -if it supports username/password if a certain callback is set in the ``struct -nats``. This callback will then be called, and the user must copy the -username/password to the supplied user/pass buffers. - -Content might be also published for a given subject. - -The sample application lets one observe the subject "led0", and turn it -"on", "off", or "toggle" its value. Changing the value will, if supported, -act on a status LED on the development board. The new status will be -published. - -Also worth noting is that most of the networking and GPIO boilerplate has -been shamelessly copied from the IRC bot example. (Curiously, both -protocols are similar.) - -Requirements -************ - -To test the sample, build the Zephyr application for your platform. This -has only been tested with the QEMU emulator as provided by the Zephyr SDK, -but it should work with other supported hardware as long as they have enough -memory, the network stack has TCP enabled, and the connectivity hardware is -supported. - -As far as the software goes, this has been tested with the official `gnatsd -`__ for the server, and the official -`go-nats `__ client library. Both the -server and clients were set up as per instructions found in their respective -``README.md`` files. - -The client was a one-off test that is basically the same code provided in -the `Basic Usage -`__ -section as found in the ``go-nats`` README file, however, subscribing to the -topic used in this sample: ``led0``, and publishing values as described -above (``on``, ``off``, and ``toggle``). - -Library Usage -************* - -Allocate enough space for a ``struct nats``, setting a few callbacks so -that you're notified as events happen: - -:: - - struct nats nats_ctx = { - .on_auth_required = on_auth_required, - .on_message = on_message - }; - -The ``on_auth_required()`` and ``on_message()`` functions are part of -your application, and each must have these signatures: - -:: - - int on_auth_required(struct nats *nats, char **user, char **pass); - int on_message(struct nats *nats, struct nats_msg *msg); - -Both functions should return 0 to signal that they could successfully -handle their role, and a negative value, if they couldn't for any -reason. It's recommended to use a negative integer as provided by -errno.h in order to ease debugging. - -The first function, ``on_auth_required()``, is called if the server -notifies that it requires authentication. It's not going to be called if -that's not the case, so it is optional. However, if the server asks for -credentials and this function is not provided, the connection will be -closed and an error will be returned by ``nats_connect()``. - -The second function, ``on_message()``, will be called whenever the -server has been notified of a value change. The ``struct nats_msg`` has the -following fields: - -:: - - struct nats_msg { - const char *subject; - const char *sid; - const char *reply_to; - }; - -The field ``reply_to`` may be passed directly to ``nats_publish()``, -in order to publish a reply to this message. If it's ``NULL`` (no -reply-to field in the message from the server), the -``nats_publish()`` function will not reply to a specific mailbox and -will just update the topic value. - -In order to manage topic subscription, these functions can be used: - -:: - - int nats_subscribe(struct nats *nats, const char *subject, - const char *queue_group, const char *sid); - -``subject`` and ``sid`` are validated so that they're actually valid -per the protocol rules. ``-EINVAL`` is returned if they're not. - -If ``queue_group`` is NULL, it's not sent to the server. - -:: - - int nats_unsubscribe(struct nats *nats, const char *sid, - size_t max_msgs); - -``sid`` is validated so it's actually valid per the protocol rules. --EINVAL is returned if it's not. - -``max_msgs`` specifies the number of messages that the server will -send before actually unsubscribing the message. Can be 0 to -immediately unsubscribe. (See note below.) - -Both of these functions will return ``-ENOMEM`` if they couldn't build -the message to transmit to the server. They can also return any error -that ``net_context_send()`` can return. - -Note: In order to conserve resources, the library implementation will not -make note of subscribed topics. Both ``nats_subscribe()`` and -``nats_unsubscribe()`` functions will only notify the server that the client -is either interested or uninterested in a particular topic. The -``on_message()`` callback may be called to notify of changes in topics that -have not been subscribed to (or have been recently unsubscribed). It's up -to the application to decide to ignore the message. - -Topics can be published by using the following function: - -:: - - int nats_publish(struct nats *nats, const char *subject, - const char *reply_to, const char *payload, - size_t payload_len); - -As usual, ``subject`` is validated and ``-EINVAL`` will be returned if -it's in an invalid format. The ``reply_to`` field can be ``NULL``, in -which case, subscribers to this topic won't receive this information as -well. - -As ``net_subscribe()`` and ``net_unsubscribe()``, this function can -return ``-ENOMEM`` or any other errors that ``net_context_send()`` -returns. diff --git a/samples/net/nats/prj.conf b/samples/net/nats/prj.conf deleted file mode 100644 index a261719d773..00000000000 --- a/samples/net/nats/prj.conf +++ /dev/null @@ -1,23 +0,0 @@ -CONFIG_INIT_STACKS=y - -CONFIG_NET_DHCPV4=y -CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3 -CONFIG_NET_IPV6=y -CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3 -CONFIG_NET_LOG=y -CONFIG_NET_MAX_CONTEXTS=10 -CONFIG_NET_SHELL=y -CONFIG_NET_STATISTICS=y -CONFIG_NET_TCP=y -CONFIG_NETWORKING=y -CONFIG_DNS_RESOLVER=n - -CONFIG_PRINTK=y - -CONFIG_NET_CONFIG_SETTINGS=y -CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2" - -CONFIG_TEST_RANDOM_GENERATOR=y - -CONFIG_JSON_LIBRARY=y diff --git a/samples/net/nats/sample.yaml b/samples/net/nats/sample.yaml deleted file mode 100644 index 1bb1c5c43d1..00000000000 --- a/samples/net/nats/sample.yaml +++ /dev/null @@ -1,7 +0,0 @@ -sample: - name: NATS Client -tests: - sample.net.nats: - harness: net - depends_on: netif - tags: net nats diff --git a/samples/net/nats/src/main.c b/samples/net/nats/src/main.c deleted file mode 100644 index 1c75ed68cf1..00000000000 --- a/samples/net/nats/src/main.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_REGISTER(net_nats_sample, LOG_LEVEL_DBG); - -#include -#include -#include -#include -#include - -#include "nats.h" - -/* LED */ -#ifndef DT_ALIAS_LED0_GPIOS_CONTROLLER -#ifdef LED0_GPIO_PORT -#define DT_ALIAS_LED0_GPIOS_CONTROLLER LED0_GPIO_PORT -#else -#define DT_ALIAS_LED0_GPIOS_CONTROLLER "(fail)" -#define DT_ALIAS_LED0_GPIOS_PIN 0 -#endif -#endif - -#define LED_GPIO_NAME DT_ALIAS_LED0_GPIOS_CONTROLLER -#define LED_PIN DT_ALIAS_LED0_GPIOS_PIN - -static struct device *led0; -static bool fake_led; - -/* Network Config */ - -#if defined(CONFIG_NET_IPV6) - -#define NATS_AF_INET AF_INET6 -#define NATS_SOCKADDR_IN sockaddr_in6 - -#if defined(CONFIG_NET_CONFIG_MY_IPV6_ADDR) -#define NATS_LOCAL_IP_ADDR CONFIG_NET_CONFIG_MY_IPV6_ADDR -#else -#define NATS_LOCAL_IP_ADDR "2001:db8::1" -#endif /* CONFIG_NET_CONFIG_MY_IPV6_ADDR */ - -#if defined(CONFIG_NET_CONFIG_PEER_IPV6_ADDR) -#define NATS_PEER_IP_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR -#else -#define NATS_PEER_IP_ADDR "2001:db8::2" -#endif /* CONFIG_NET_CONFIG_PEER_IPV6_ADDR */ - -#else /* CONFIG_NET_IPV4 */ - -#define NATS_AF_INET AF_INET -#define NATS_SOCKADDR_IN sockaddr_in - -#if defined(CONFIG_NET_CONFIG_MY_IPV4_ADDR) -#define NATS_LOCAL_IP_ADDR CONFIG_NET_CONFIG_MY_IPV4_ADDR -#else -#define NATS_LOCAL_IP_ADDR "192.168.0.1" -#endif /* CONFIG_NET_CONFIG_MY_IPV4_ADDR */ - -#if defined(CONFIG_NET_CONFIG_PEER_IPV4_ADDR) -#define NATS_PEER_IP_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR -#else -#define NATS_PEER_IP_ADDR "192.168.0.2" -#endif /* CONFIG_NET_CONFIG_PEER_IPV4_ADDR */ - -#endif - -/* DNS API */ -#define DNS_PORT 53 -#define DNS_SLEEP_MSECS 400 - -/* Default server */ -#define DEFAULT_PORT 4222 - -static void panic(const char *msg) -{ - LOG_ERR("Panic: %s", msg); - for (;;) { - k_sleep(K_FOREVER); - } -} - -static int in_addr_set(sa_family_t family, - const char *ip_addr, - int port, - struct sockaddr *_sockaddr) -{ - int rc = 0; - - _sockaddr->sa_family = family; - - if (ip_addr) { - if (family == AF_INET6) { - rc = net_addr_pton(family, - ip_addr, - &net_sin6(_sockaddr)->sin6_addr); - } else { - rc = net_addr_pton(family, - ip_addr, - &net_sin(_sockaddr)->sin_addr); - } - - if (rc < 0) { - LOG_ERR("Invalid IP address: %s", log_strdup(ip_addr)); - return -EINVAL; - } - } - - if (port >= 0) { - if (family == AF_INET6) { - net_sin6(_sockaddr)->sin6_port = htons(port); - } else { - net_sin(_sockaddr)->sin_port = htons(port); - } - } - - return rc; -} - -static void initialize_network(void) -{ - struct net_if *iface; - - LOG_INF("Initializing network"); - - iface = net_if_get_default(); - if (!iface) { - panic("No default network interface"); - } - - /* TODO: IPV6 DHCP */ -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4) - net_dhcpv4_start(iface); - - /* delay so DHCPv4 can assign IP */ - /* TODO: add a timeout/retry */ - LOG_INF("Waiting for DHCP ..."); - do { - k_sleep(K_SECONDS(1)); - } while (net_ipv4_is_addr_unspecified(&iface->dhcpv4.requested_ip)); - - LOG_INF("Done!"); - - /* TODO: add a timeout */ - LOG_INF("Waiting for IP assginment ..."); - do { - k_sleep(K_SECONDS(1)); - } while (!net_ipv4_is_my_addr(&iface->dhcpv4.requested_ip)); - - LOG_INF("Done!"); -#else - struct sockaddr addr; - - if (in_addr_set(NATS_AF_INET, NATS_LOCAL_IP_ADDR, 0, - &addr) < 0) { - LOG_ERR("Invalid IP address: %s", - NATS_LOCAL_IP_ADDR); - } - -#if defined(CONFIG_NET_IPV6) - net_if_ipv6_addr_add(iface, - &net_sin6(&addr)->sin6_addr, - NET_ADDR_MANUAL, 0); -#else - net_if_ipv4_addr_add(iface, - &net_sin(&addr)->sin_addr, - NET_ADDR_MANUAL, 0); -#endif -#endif /* CONFIG_NET_IPV4 && CONFIG_NET_DHCPV4 */ -} - -static bool read_led(void) -{ - u32_t led = 0U; - int r; - - if (!led0) { - return fake_led; - } - - r = gpio_pin_read(led0, LED_PIN, &led); - if (r < 0) { - return false; - } - - return !led; -} - -static void write_led(const struct nats *nats, - const struct nats_msg *msg, - bool state) -{ - char *pubstate; - int ret; - - if (!led0) { - fake_led = state; - } else { - gpio_pin_write(led0, LED_PIN, !state); - } - - pubstate = state ? "on" : "off"; - ret = nats_publish(nats, "led0", 0, msg->reply_to, 0, - pubstate, strlen(pubstate)); - if (ret < 0) { - printk("Failed to publish: %d\n", ret); - } else { - printk("*** Turning LED %s\n", pubstate); - } -} - -static int on_msg_received(const struct nats *nats, - const struct nats_msg *msg) -{ - if (!strcmp(msg->subject, "led0")) { - if (msg->payload_len == 2 && !strcmp(msg->payload, "on")) { - write_led(nats, msg, true); - return 0; - } - - if (msg->payload_len == 3 && !strcmp(msg->payload, "off")) { - write_led(nats, msg, false); - return 0; - } - - if (msg->payload_len == 6 && !strcmp(msg->payload, "toggle")) { - write_led(nats, msg, !read_led()); - return 0; - } - - return -EINVAL; - } - - return -ENOENT; -} - -static void initialize_hardware(void) -{ - LOG_INF("Initializing hardware"); - - led0 = device_get_binding(LED_GPIO_NAME); - if (led0) { - gpio_pin_configure(led0, LED_PIN, GPIO_DIR_OUT); - } -} - -static int connect(struct nats *nats, u16_t port) -{ -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4) - struct net_if *iface; -#endif - struct sockaddr dst_addr, src_addr; - int ret; - - LOG_INF("Connecting..."); - - ret = net_context_get(NATS_AF_INET, SOCK_STREAM, IPPROTO_TCP, - &nats->conn); - if (ret < 0) { - LOG_DBG("Could not get new context: %d", ret); - return ret; - } - - /* TODO: IPV6 DHCP */ -#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_DHCPV4) - iface = net_if_get_default(); - - net_ipaddr_copy(&net_sin(&src_addr)->sin_addr, - &iface->dhcpv4.requested_ip); - ret = in_addr_set(NATS_AF_INET, NULL, 0, &src_addr); -#else - ret = in_addr_set(NATS_AF_INET, NATS_LOCAL_IP_ADDR, - 0, &src_addr); - if (ret < 0) { - goto connect_exit; - } -#endif - - ret = in_addr_set(NATS_AF_INET, NATS_PEER_IP_ADDR, - port, &dst_addr); - if (ret < 0) { - goto connect_exit; - } - - ret = net_context_bind(nats->conn, &src_addr, - sizeof(struct NATS_SOCKADDR_IN)); - if (ret < 0) { - LOG_DBG("Could not bind to local address: %d", -ret); - goto connect_exit; - } - - ret = nats_connect(nats, &dst_addr, sizeof(struct NATS_SOCKADDR_IN)); - if (!ret) { - return 0; - } - -connect_exit: - net_context_put(nats->conn); - return ret; -} - -static void nats_client(void) -{ - struct nats nats = { - .on_message = on_msg_received - }; - - LOG_INF("NATS Client Sample"); - - initialize_network(); - initialize_hardware(); - - if (connect(&nats, DEFAULT_PORT) < 0) { - panic("Could not connect to NATS server"); - } - - if (nats_subscribe(&nats, "led0", 0, NULL, 0, - "sub132984012384098", 0) < 0) { - panic("Could not subscribe to `led0` topic"); - } -} - -void main(void) -{ - nats_client(); -} diff --git a/samples/net/nats/src/nats.c b/samples/net/nats/src/nats.c deleted file mode 100644 index 37daaacc736..00000000000 --- a/samples/net/nats/src/nats.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -LOG_MODULE_DECLARE(net_nats_sample, LOG_LEVEL_DBG); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nats.h" - -#define CMD_BUF_LEN 256 - -struct nats_info { - const char *server_id; - const char *version; - const char *go; - const char *host; - size_t max_payload; - u16_t port; - bool ssl_required; - bool auth_required; -}; - -struct io_vec { - const void *base; - size_t len; -}; - -static bool is_subject_valid(const char *subject, size_t len) -{ - size_t pos; - char last = '\0'; - - if (!subject) { - return false; - } - - for (pos = 0; pos < len; last = subject[pos++]) { - switch (subject[pos]) { - case '>': - if (subject[pos + 1] != '\0') { - return false; - } - - break; - case '.': - case '*': - if (last == subject[pos]) { - return false; - } - - break; - default: - if (isalnum((unsigned char)subject[pos])) { - continue; - } - - return false; - } - } - - return true; -} - -static bool is_sid_valid(const char *sid, size_t len) -{ - size_t pos; - - if (!sid) { - return false; - } - - for (pos = 0; pos < len; pos++) { - if (!isalnum((unsigned char)sid[pos])) { - return false; - } - } - - return true; -} - -#define TRANSMITV_LITERAL(lit_) { .base = lit_, .len = sizeof(lit_) - 1 } - -static int transmitv(struct net_context *conn, int iovcnt, - struct io_vec *iov) -{ - u8_t buf[1024]; - int i, pos; - - for (i = 0, pos = 0; i < iovcnt; pos += iov[i].len, i++) { - memcpy(&buf[pos], iov[i].base, iov[i].len); - } - - return net_context_send(conn, buf, pos, NULL, K_NO_WAIT, NULL); -} - -static inline int transmit(struct net_context *conn, const char buffer[], - size_t len) -{ - return transmitv(conn, 1, (struct io_vec[]) { - { .base = buffer, .len = len }, - }); -} - -#define FIELD(struct_, member_, type_) { \ - .field_name = #member_, \ - .field_name_len = sizeof(#member_) - 1, \ - .offset = offsetof(struct_, member_), \ - .type = type_ \ -} -static int handle_server_info(struct nats *nats, char *payload, size_t len, - struct net_buf *buf, u16_t offset) -{ - static const struct json_obj_descr descr[] = { - FIELD(struct nats_info, server_id, JSON_TOK_STRING), - FIELD(struct nats_info, version, JSON_TOK_STRING), - FIELD(struct nats_info, go, JSON_TOK_STRING), - FIELD(struct nats_info, host, JSON_TOK_STRING), - FIELD(struct nats_info, port, JSON_TOK_NUMBER), - FIELD(struct nats_info, auth_required, JSON_TOK_TRUE), - FIELD(struct nats_info, ssl_required, JSON_TOK_TRUE), - FIELD(struct nats_info, max_payload, JSON_TOK_NUMBER), - }; - struct nats_info info = {}; - char user[32], pass[64]; - size_t user_len = sizeof(user), pass_len = sizeof(pass); - int ret; - - ret = json_obj_parse(payload, len, descr, ARRAY_SIZE(descr), &info); - if (ret < 0) { - return -EINVAL; - } - - if (info.ssl_required) { - return -ENOTSUP; - } - - if (!info.auth_required) { - return 0; - } - - if (!nats->on_auth_required) { - return -EPERM; - } - - ret = nats->on_auth_required(nats, user, &user_len, pass, &pass_len); - if (ret < 0) { - return ret; - } - - ret = json_escape(user, &user_len, sizeof(user)); - if (ret < 0) { - return ret; - } - - ret = json_escape(pass, &pass_len, sizeof(pass)); - if (ret < 0) { - return ret; - } - - return transmitv(nats->conn, 5, (struct io_vec[]) { - TRANSMITV_LITERAL("CONNECT {\"user\":\""), - { .base = user, .len = user_len }, - TRANSMITV_LITERAL("\",\"pass\":\""), - { .base = pass, .len = pass_len }, - TRANSMITV_LITERAL("\"}\r\n"), - }); -} -#undef FIELD - -static bool char_in_set(char chr, const char *set) -{ - const char *ptr; - - for (ptr = set; *ptr; ptr++) { - if (*ptr == chr) { - return true; - } - } - - return false; -} - -static char *strsep(char *strp, const char *delims) -{ - const char *delim; - char *ptr; - - if (!strp) { - return NULL; - } - - for (delim = delims; *delim; delim++) { - ptr = strchr(strp, *delim); - if (ptr) { - *ptr = '\0'; - - for (ptr++; *ptr; ptr++) { - if (!char_in_set(*ptr, delims)) { - break; - } - } - - return ptr; - } - } - - return NULL; -} - -static int copy_pkt_to_buf(struct net_buf *src, u16_t offset, - char *dst, size_t dst_size, size_t n_bytes) -{ - u16_t to_copy; - u16_t copied; - - if (dst_size < n_bytes) { - return -ENOMEM; - } - - while (src && offset >= src->len) { - offset -= src->len; - src = src->frags; - } - - for (copied = 0U; src && n_bytes > 0; offset = 0U) { - to_copy = MIN(n_bytes, src->len - offset); - - memcpy(dst + copied, (char *)src->data + offset, to_copy); - copied += to_copy; - - n_bytes -= to_copy; - src = src->frags; - } - - if (n_bytes > 0) { - return -ENOMEM; - } - - return 0; -} - -static int handle_server_msg(struct nats *nats, char *payload, size_t len, - struct net_buf *buf, u16_t offset) -{ - char *subject, *sid, *reply_to, *bytes, *end_ptr; - char prev_end = payload[len]; - size_t payload_size; - - /* strsep() uses strchr(), ensure payload is NUL-terminated */ - payload[len] = '\0'; - - /* Slice the tokens */ - subject = payload; - sid = strsep(subject, " \t"); - reply_to = strsep(sid, " \t"); - bytes = strsep(reply_to, " \t"); - - if (!bytes) { - if (!reply_to) { - return -EINVAL; - } - - bytes = reply_to; - reply_to = NULL; - } - - /* Parse the payload size */ - errno = 0; - payload_size = strtoul(bytes, &end_ptr, 10); - payload[len] = prev_end; - if (errno != 0) { - return -errno; - } - - if (!end_ptr) { - return -EINVAL; - } - - if (payload_size >= CMD_BUF_LEN - len) { - return -ENOMEM; - } - - if (copy_pkt_to_buf(buf, offset, end_ptr, CMD_BUF_LEN - len, - payload_size) < 0) { - return -ENOMEM; - } - end_ptr[payload_size] = '\0'; - - return nats->on_message(nats, &(struct nats_msg) { - .subject = subject, - .sid = sid, - .reply_to = reply_to, - .payload = end_ptr, - .payload_len = payload_size, - }); -} - -static int handle_server_ping(struct nats *nats, char *payload, size_t len, - struct net_buf *buf, u16_t offset) -{ - static const char pong[] = "PONG\r\n"; - - return transmit(nats->conn, pong, sizeof(pong) - 1); -} - -static int ignore(struct nats *nats, char *payload, size_t len, - struct net_buf *buf, u16_t offset) -{ - /* FIXME: Notify user of success/errors. This would require - * maintaining information of what was the last sent command in - * order to provide the best error information for the user. - * Without VERBOSE set, these won't be sent -- but be cautious and - * ignore them just in case. - */ - return 0; -} - -#define CMD(cmd_, handler_) { \ - .op = cmd_, \ - .len = sizeof(cmd_) - 1, \ - .handle = handler_ \ -} -static int handle_server_cmd(struct nats *nats, char *cmd, size_t len, - struct net_buf *buf, u16_t offset) -{ - static const struct { - const char *op; - size_t len; - int (*handle)(struct nats *nats, char *payload, size_t len, - struct net_buf *buf, u16_t offset); - } cmds[] = { - CMD("INFO", handle_server_info), - CMD("MSG", handle_server_msg), - CMD("PING", handle_server_ping), - CMD("+OK", ignore), - CMD("-ERR", ignore), - }; - size_t i; - char *payload; - size_t payload_len; - - payload = strsep(cmd, " \t"); - if (!payload) { - payload = strsep(cmd, "\r"); - if (!payload) { - return -EINVAL; - } - } - payload_len = len - (size_t)(payload - cmd); - len = (size_t)(payload - cmd - 1); - - for (i = 0; i < ARRAY_SIZE(cmds); i++) { - if (len != cmds[i].len) { - continue; - } - - if (!strncmp(cmds[i].op, cmd, len)) { - return cmds[i].handle(nats, payload, payload_len, - buf, offset); - } - } - - return -ENOENT; -} -#undef CMD - -int nats_subscribe(const struct nats *nats, - const char *subject, size_t subject_len, - const char *queue_group, size_t queue_group_len, - const char *sid, size_t sid_len) -{ - if (!is_subject_valid(subject, subject_len)) { - return -EINVAL; - } - - if (!is_sid_valid(sid, sid_len)) { - return -EINVAL; - } - - if (queue_group) { - return transmitv(nats->conn, 7, (struct io_vec[]) { - TRANSMITV_LITERAL("SUB "), - { - .base = subject, - .len = subject_len ? - subject_len : strlen(subject) - }, - TRANSMITV_LITERAL(" "), - { - .base = queue_group, - .len = queue_group_len ? - queue_group_len : strlen(queue_group) - }, - TRANSMITV_LITERAL(" "), - { - .base = sid, - .len = sid_len ? sid_len : strlen(sid) - }, - TRANSMITV_LITERAL("\r\n") - }); - } - - return transmitv(nats->conn, 5, (struct io_vec[]) { - TRANSMITV_LITERAL("SUB "), - { - .base = subject, - .len = subject_len ? subject_len : strlen(subject) - }, - TRANSMITV_LITERAL(" "), - { - .base = sid, - .len = sid_len ? sid_len : strlen(sid) - }, - TRANSMITV_LITERAL("\r\n") - }); -} - -int nats_unsubscribe(const struct nats *nats, - const char *sid, size_t sid_len, size_t max_msgs) -{ - if (!is_sid_valid(sid, sid_len)) { - return -EINVAL; - } - - if (max_msgs) { - char max_msgs_str[3 * sizeof(size_t)]; - int ret; - - ret = snprintk(max_msgs_str, sizeof(max_msgs_str), - "%zu", max_msgs); - if (ret < 0 || ret >= (int)sizeof(max_msgs_str)) { - return -ENOMEM; - } - - return transmitv(nats->conn, 5, (struct io_vec[]) { - TRANSMITV_LITERAL("UNSUB "), - { - .base = sid, - .len = sid_len ? sid_len : strlen(sid) - }, - TRANSMITV_LITERAL(" "), - { .base = max_msgs_str, .len = ret }, - TRANSMITV_LITERAL("\r\n"), - }); - } - - return transmitv(nats->conn, 3, (struct io_vec[]) { - TRANSMITV_LITERAL("UNSUB "), - { - .base = sid, - .len = sid_len ? sid_len : strlen(sid) - }, - TRANSMITV_LITERAL("\r\n") - }); -} - -int nats_publish(const struct nats *nats, - const char *subject, size_t subject_len, - const char *reply_to, size_t reply_to_len, - const char *payload, size_t payload_len) -{ - char payload_len_str[3 * sizeof(size_t)]; - int ret; - - if (!is_subject_valid(subject, subject_len)) { - return -EINVAL; - } - - ret = snprintk(payload_len_str, sizeof(payload_len_str), "%zu", - payload_len); - if (ret < 0 || ret >= (int)sizeof(payload_len_str)) { - return -ENOMEM; - } - - if (reply_to) { - return transmitv(nats->conn, 9, (struct io_vec[]) { - TRANSMITV_LITERAL("PUB "), - { - .base = subject, - .len = subject_len ? - subject_len : strlen(subject) - }, - TRANSMITV_LITERAL(" "), - { - .base = reply_to, - .len = reply_to_len ? - reply_to_len : strlen(reply_to) - }, - TRANSMITV_LITERAL(" "), - { .base = payload_len_str, .len = ret }, - TRANSMITV_LITERAL("\r\n"), - { .base = payload, .len = payload_len }, - TRANSMITV_LITERAL("\r\n"), - }); - } - - return transmitv(nats->conn, 7, (struct io_vec[]) { - TRANSMITV_LITERAL("PUB "), - { - .base = subject, - .len = subject_len ? subject_len : strlen(subject) - }, - TRANSMITV_LITERAL(" "), - { .base = payload_len_str, .len = ret }, - TRANSMITV_LITERAL("\r\n"), - { .base = payload, .len = payload_len }, - TRANSMITV_LITERAL("\r\n"), - }); -} - -static void receive_cb(struct net_context *ctx, - struct net_pkt *pkt, - union net_ip_header *ip_hdr, - union net_proto_header *proto_hdr, - int status, - void *user_data) -{ - struct nats *nats = user_data; - char cmd_buf[CMD_BUF_LEN]; - struct net_buf *tmp; - u16_t pos = 0U, cmd_len = 0U; - size_t len; - u8_t *end_of_line; - - if (!pkt) { - /* FIXME: How to handle disconnection? */ - return; - } - - if (status) { - /* FIXME: How to handle connectio error? */ - net_pkt_unref(pkt); - return; - } - - tmp = pkt->cursor.buf; - if (!tmp) { - net_pkt_unref(pkt); - return; - } - - pos = pkt->cursor.pos - tmp->data; - - while (tmp) { - len = tmp->len - pos; - - end_of_line = memchr((u8_t *)tmp->data + pos, '\n', len); - if (end_of_line) { - len = end_of_line - ((u8_t *)tmp->data + pos); - } - - if (cmd_len + len > sizeof(cmd_buf)) { - break; - } - - if (net_pkt_read(pkt, (u8_t *)(cmd_buf + cmd_len), len)) { - break; - } - - cmd_len += len; - - if (end_of_line) { - u8_t dummy; - int ret; - - if (net_pkt_read_u8(pkt, &dummy)) { - break; - } - - cmd_buf[cmd_len] = '\0'; - - ret = handle_server_cmd(nats, cmd_buf, cmd_len, - tmp, pos); - if (ret < 0) { - /* FIXME: What to do with unhandled messages? */ - break; - } - - cmd_len = 0U; - } - - tmp = pkt->cursor.buf; - pos = pkt->cursor.pos - tmp->data; - } - - net_pkt_unref(pkt); -} - -int nats_connect(struct nats *nats, struct sockaddr *addr, socklen_t addrlen) -{ - int ret; - - ret = net_context_connect(nats->conn, addr, addrlen, - NULL, K_FOREVER, NULL); - if (ret < 0) { - return ret; - } - - return net_context_recv(nats->conn, receive_cb, K_NO_WAIT, nats); -} - -int nats_disconnect(struct nats *nats) -{ - int ret; - - ret = net_context_put(nats->conn); - if (ret < 0) { - return ret; - } - - nats->conn = NULL; - - return 0; -} diff --git a/samples/net/nats/src/nats.h b/samples/net/nats/src/nats.h deleted file mode 100644 index 9bc860132ea..00000000000 --- a/samples/net/nats/src/nats.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __NATS_H -#define __NATS_H - -#include -#include - -struct nats_msg { - const char *subject; - const char *sid; - const char *reply_to; - const char *payload; - size_t payload_len; -}; - -struct nats { - struct net_context *conn; - - int (*on_auth_required)(const struct nats *nats, - char *user, size_t *user_len, - char *pass, size_t *pass_len); - int (*on_message)(const struct nats *nats, - const struct nats_msg *msg); -}; - -int nats_connect(struct nats *nats, struct sockaddr *addr, socklen_t addrlen); -int nats_disconnect(struct nats *nats); - -int nats_subscribe(const struct nats *nats, - const char *subject, size_t subject_len, - const char *queue_group, size_t queue_group_len, - const char *sid, size_t sid_len); -int nats_unsubscribe(const struct nats *nats, - const char *sid, size_t sid_len, - size_t max_msgs); - -int nats_publish(const struct nats *nats, - const char *subject, size_t subject_len, - const char *reply_to, size_t reply_to_len, - const char *payload, size_t payload_len); - -#endif /* __NATS_H */