aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/cli/hicnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/cli/hicnc.c')
-rw-r--r--hicn-light/src/hicn/cli/hicnc.c390
1 files changed, 390 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c
new file mode 100644
index 000000000..d14093b6b
--- /dev/null
+++ b/hicn-light/src/hicn/cli/hicnc.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2021 Cisco and/or its affiliates.
+ * 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 <limits.h> // LONG_MAX, LONG_MIN
+#include <signal.h>
+#include <hicn/ctrl.h>
+
+#ifndef _WIN32
+#include <getopt.h>
+#endif
+
+#include "color.h"
+#include "../config/parse.h"
+#include <hicn/util/log.h>
+#include <hicn/util/sstrncpy.h>
+
+#define PORT 9695
+
+static struct option longFormOptions[] = {{"help", no_argument, 0, 'h'},
+ {"server", required_argument, 0, 'S'},
+ {"port", required_argument, 0, 'P'},
+ {0, 0, 0, 0}};
+
+static void usage(char *prog) {
+ printf("%s: portable hICN forwarder\n", prog);
+ printf("\n");
+ printf("Usage: %s COMMAND [PARAMETERS]\n", prog);
+ printf("\n");
+ printf(" %s -h This help screen.\n", prog);
+ printf(" %s help Obtain a list of available commands.\n", prog);
+ printf("\n");
+}
+
+static bool stop = false;
+void signal_handler(int sig) {
+ fprintf(stderr, "Received ^C... quitting !\n");
+ stop = true;
+}
+
+int main(int argc, char *const *argv) {
+ log_conf.log_level = LOG_INFO;
+
+ // Handle termination signal
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = signal_handler;
+ sigaction(SIGINT, &sa, NULL);
+
+ /* Parse commandline */
+ char *server_ip = NULL;
+ uint16_t server_port = 0;
+
+ for (;;) {
+ // getopt_long stores the option index here.
+ int optind = 0;
+
+ int c = getopt_long(argc, argv, "hS:P:", longFormOptions, &optind);
+ if (c == -1) break;
+
+ switch (c) {
+ case 'S':
+ server_ip = optarg;
+ break;
+
+ case 'P': {
+ char *endptr;
+ long val = strtol(optarg, &endptr, 10);
+
+ errno = 0; /* To distinguish success/failure after call */
+
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0)) {
+ perror("strtol");
+ exit(EXIT_FAILURE);
+ }
+
+ if (endptr == optarg) {
+ fprintf(stderr, "No digits were found.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (*endptr != '\0') {
+ fprintf(stderr, "Spurious characters after number: %s.\n", endptr);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((val < 1) || (val > 65535)) {
+ fprintf(stderr, "Invalid port number: %ld.\n", val);
+ exit(EXIT_FAILURE);
+ }
+
+ server_port = val;
+ break;
+ }
+
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+
+ default:
+ fprintf(stderr, "Invalid argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Parse */
+ char *param = argv[optind];
+ for (; optind < argc - 1; optind++) {
+ char *arg = argv[optind];
+ arg[strlen(arg)] = ' ';
+ }
+
+ if (!param) {
+ usage(argv[0]);
+ goto ERR_PARAM;
+ }
+
+ if (strncmp(param, "help", 4) == 0) {
+ if (help(param) < 0) {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+ hc_command_t command = {};
+ if (parse(param, &command) < 0) {
+ fprintf(stderr, "Error parsing command : '%s'\n", param);
+ goto ERR_PARSE;
+ }
+
+ hc_sock_t *s;
+ if (server_ip) {
+ if (server_port == 0) server_port = PORT;
+#define BUFSIZE 255
+ char url[BUFSIZE];
+ snprintf(url, BUFSIZE, "tcp://%s:%d/", server_ip, server_port);
+ s = hc_sock_create_forwarder_url(HICNLIGHT_NG, url);
+ } else {
+ s = hc_sock_create_forwarder(HICNLIGHT_NG);
+ }
+ if (!s) {
+ fprintf(stderr, "Could not create socket.\n");
+ goto ERR_SOCK;
+ }
+
+ if (hc_sock_connect(s) < 0) {
+ fprintf(stderr, "Could not establish connection to forwarder.\n");
+ goto ERR_CONNECT;
+ }
+
+ if (!IS_VALID_OBJECT_TYPE(command.object.type) ||
+ !IS_VALID_ACTION(command.action)) {
+ fprintf(stderr, "Unsupported command");
+ goto ERR_PARAM;
+ }
+
+ int rc = UNSUPPORTED_CMD_ERROR;
+ hc_data_t *data = NULL;
+ char buf_listener[MAXSZ_HC_LISTENER];
+ char buf_connection[MAXSZ_HC_CONNECTION];
+ char buf_route[MAXSZ_HC_ROUTE];
+ char buf[MAX_LEN];
+ switch (command.object.type) {
+ case OBJECT_ROUTE:
+ switch (command.action) {
+ case ACTION_CREATE:
+ rc = hc_route_create(s, &command.object.route);
+ break;
+
+ case ACTION_DELETE:
+ rc = hc_route_delete(s, &command.object.route);
+ break;
+
+ case ACTION_LIST:
+ rc = hc_route_list(s, &data);
+ if (rc < 0) break;
+
+ INFO("Routes:");
+ foreach_route(r, data) {
+ if (hc_route_snprintf(buf_route, MAXSZ_HC_ROUTE, r) >=
+ MAXSZ_HC_ROUTE)
+ ERROR("Display error");
+ INFO("%s", buf_route);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_LISTENER:
+ switch (command.action) {
+ case ACTION_CREATE:
+ rc = hc_listener_create(s, &command.object.listener);
+ break;
+
+ case ACTION_DELETE:
+ rc = hc_listener_delete(s, &command.object.listener);
+ break;
+
+ case ACTION_LIST:
+ rc = hc_listener_list(s, &data);
+ if (rc < 0) break;
+
+ INFO("Listeners:");
+ foreach_listener(l, data) {
+ if (hc_listener_snprintf(buf_listener, MAXSZ_HC_LISTENER + 17, l) >=
+ MAXSZ_HC_LISTENER)
+ ERROR("Display error");
+ INFO("[%d] %s", l->id, buf_listener);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_CONNECTION:
+ switch (command.action) {
+ case ACTION_CREATE:
+ rc = hc_connection_create(s, &command.object.connection);
+ break;
+
+ case ACTION_DELETE:
+ rc = hc_connection_delete(s, &command.object.connection);
+ break;
+
+ case ACTION_LIST:
+ rc = hc_connection_list(s, &data);
+ if (rc < 0) break;
+
+ INFO("Connections:");
+ foreach_connection(c, data) {
+ if (hc_connection_snprintf(buf_connection, MAXSZ_HC_CONNECTION,
+ c) >= MAXSZ_HC_CONNECTION)
+ ERROR("Display error");
+ INFO("[%d] %s", c->id, buf_connection);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_CACHE:
+ switch (command.action) {
+ case ACTION_SERVE:
+ rc = hc_cache_set_serve(s, &command.object.cache);
+ break;
+
+ case ACTION_STORE:
+ rc = hc_cache_set_store(s, &command.object.cache);
+ break;
+
+ case ACTION_CLEAR:
+ rc = hc_cache_clear(s, &command.object.cache);
+ break;
+
+ case ACTION_LIST:
+ rc = hc_cache_list(s, &data);
+ if (rc < 0) break;
+
+ hc_cache_snprintf(buf, MAX_LEN, (hc_cache_info_t *)data->buffer);
+ printf("%s\n", buf);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_STRATEGY:
+ switch (command.action) {
+ case ACTION_SET:
+ rc = hc_strategy_set(s, &command.object.strategy);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_MAPME:
+ switch (command.action) {
+ case ACTION_UPDATE:
+ rc = hc_mapme_send_update(s, &command.object.mapme);
+ break;
+ case ACTION_SET:
+ if (command.object.mapme.target == MAPME_TARGET_ENABLE) {
+ rc = hc_mapme_set(s, &command.object.mapme);
+ } else if (command.object.mapme.target == MAPME_TARGET_DISCOVERY) {
+ rc = hc_mapme_set_discovery(s, &command.object.mapme);
+ } else if (command.object.mapme.target == MAPME_TARGET_TIMESCALE) {
+ rc = hc_mapme_set_timescale(s, &command.object.mapme);
+ } else if (command.object.mapme.target == MAPME_TARGET_RETX) {
+ rc = hc_mapme_set_retx(s, &command.object.mapme);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_LOCAL_PREFIX:
+ switch (command.action) {
+ case ACTION_CREATE:
+ rc = hc_strategy_add_local_prefix(s, &command.object.strategy);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case OBJECT_SUBSCRIPTION:
+ // Disable socket recv timeout
+ hc_sock_set_recv_timeout_ms(s, 0);
+
+ rc = hc_subscription_create(s, &command.object.subscription);
+ if (rc < 0) break;
+ INFO("Subscription sent");
+
+ while (!stop) {
+ int rc = hc_sock_callback(s, &data);
+ if (rc < 0 && !stop) ERROR("Notification error");
+
+ if (!stop) {
+ event_type_t event_type = rc;
+ INFO("Notification recevied %s [%d]", event_str(event_type),
+ event_type);
+
+ if (event_type == EVENT_INTERFACE_UPDATE) {
+ hc_event_interface_update_t *event =
+ (hc_event_interface_update_t *)(data->buffer);
+ INFO("Interface update event received: %u", event->interface_type);
+ }
+ }
+ }
+
+ INFO("Unsubscribing...");
+ rc = hc_subscription_delete(s, &command.object.subscription);
+ break;
+
+ default:
+ break;
+ }
+ hc_data_free(data);
+
+ if (rc < -1) {
+ if (rc == INPUT_ERROR) ERROR("Wrong input parameters");
+ if (rc == UNSUPPORTED_CMD_ERROR) ERROR("Unsupported command");
+ goto ERR_CMD;
+ }
+ if (rc < 0) ERROR("Error executing command");
+
+ // Remove the connection created to send the command
+ command.object.connection.id = 0;
+ rc = strcpy_s(command.object.connection.name,
+ sizeof(command.object.connection.name), "SELF");
+ if (rc != EOK || hc_connection_delete(s, &command.object.connection) < 0)
+ fprintf(stderr, "Error removing local connection to forwarder\n");
+
+ exit(EXIT_SUCCESS);
+
+ERR_CMD:
+ERR_CONNECT:
+ hc_sock_free(s);
+ERR_SOCK:
+ERR_PARSE:
+ERR_PARAM:
+ exit(EXIT_FAILURE);
+}