aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/cli
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/cli')
-rw-r--r--hicn-light/src/hicn/cli/CMakeLists.txt93
-rw-r--r--hicn-light/src/hicn/cli/color.c71
-rw-r--r--hicn-light/src/hicn/cli/color.h42
-rw-r--r--hicn-light/src/hicn/cli/hicnc.c237
-rw-r--r--hicn-light/src/hicn/cli/hicnd.c311
-rw-r--r--hicn-light/src/hicn/cli/hicns.c206
-rw-r--r--hicn-light/src/hicn/cli/logo.h37
7 files changed, 997 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/cli/CMakeLists.txt b/hicn-light/src/hicn/cli/CMakeLists.txt
new file mode 100644
index 000000000..39581e6ad
--- /dev/null
+++ b/hicn-light/src/hicn/cli/CMakeLists.txt
@@ -0,0 +1,93 @@
+# Copyright (c) 2021-2022 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.
+
+
+if (NOT DISABLE_EXECUTABLES)
+##############################################################
+# Force libhicn library to whole archive mode
+##############################################################
+ if (APPLE)
+ set(
+ LIBHICN_LIGHT_WHOLE_ARCHIVE
+ "-Wl,-force_load"
+ "${LIBHICN_LIGHT_STATIC}"
+ )
+ else()
+ set(
+ LIBHICN_LIGHT_WHOLE_ARCHIVE
+ "-Wl,--whole-archive"
+ "${LIBHICN_LIGHT_STATIC}"
+ "-Wl,--no-whole-archive"
+ )
+ endif()
+
+##############################################################
+# Sources
+##############################################################
+ list(APPEND CONTROLLER_SRC
+ color.c
+ hicnc.c
+ )
+
+
+##############################################################
+# Build hicn-light-control
+##############################################################
+ build_executable(${HICN_LIGHT_CONTROL}
+ SOURCES ${CONTROLLER_SRC}
+ LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE}
+ DEPENDS ${LIBHICN_LIGHT_STATIC}
+ COMPONENT ${HICN_LIGHT}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+ )
+
+
+##############################################################
+# Build hicn-light-shell
+##############################################################
+ list(APPEND SHELL_SRC
+ color.c
+ hicns.c
+ )
+
+ build_executable(${HICN_LIGHT_SHELL}
+ SOURCES ${SHELL_SRC}
+ LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE}
+ DEPENDS ${LIBHICN_LIGHT_STATIC}
+ COMPONENT ${HICN_LIGHT}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+ )
+
+
+##############################################################
+# Build hicn-light-shell
+##############################################################
+ list(APPEND DAEMON_SRC
+ color.c
+ hicnd.c
+ )
+
+ # hicn-light-daemon does not compile under Android due to bindSocket
+ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ build_executable(${HICN_LIGHT_DAEMON}
+ SOURCES ${DAEMON_SRC}
+ LINK_LIBRARIES ${LIBHICN_LIGHT_WHOLE_ARCHIVE}
+ DEPENDS ${LIBHICN_LIGHT_STATIC}
+ COMPONENT ${HICN_LIGHT}
+ DEFINITIONS ${COMPILER_DEFINITIONS}
+ COMPILE_OPTIONS ${COMPILER_OPTIONS}
+ )
+ endif ()
+endif ()
diff --git a/hicn-light/src/hicn/cli/color.c b/hicn-light/src/hicn/cli/color.c
new file mode 100644
index 000000000..aed22e302
--- /dev/null
+++ b/hicn-light/src/hicn/cli/color.c
@@ -0,0 +1,71 @@
+/*
+ * 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 <stdio.h>
+#include "color.h"
+
+#ifndef _WIN32
+
+void vprintfc(color_t color, const char* fmt, va_list ap) {
+ char* color_s;
+ switch (color) {
+#define _(x, y, z) \
+ case COLOR_##x: \
+ color_s = y; \
+ break;
+ foreach_color
+#undef _
+
+ case COLOR_UNDEFINED : case COLOR_N : default : // XXX
+ color_s = "";
+ break;
+ }
+ printf("%s", color_s);
+ vprintf(fmt, ap);
+}
+#else
+void vprintfc(color_t color, const char* fmt, va_list ap) {
+ int color_id;
+ switch (color) {
+#define _(x, y, z) \
+ case COLOR_##x: \
+ color_id = z; \
+ break;
+ foreach_color
+#undef _
+
+ case COLOR_UNDEFINED : case COLOR_N : color_id = 0;
+ break;
+ }
+ HANDLE hConsole = NULL;
+ WORD currentConsoleAttr;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (GetConsoleScreenBufferInfo(hConsole, &csbi))
+ currentConsoleAttr = csbi.wAttributes;
+ if (color_id != 0) SetConsoleTextAttribute(hConsole, color_id);
+ fprintf("%s", color);
+ vfprintf(fmt, ap);
+ SetConsoleTextAttribute(hConsole, currentConsoleAttr);
+}
+#endif
+
+void printfc(color_t color, const char* fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintfc(color, fmt, ap);
+ va_end(ap);
+}
diff --git a/hicn-light/src/hicn/cli/color.h b/hicn-light/src/hicn/cli/color.h
new file mode 100644
index 000000000..a9b71c047
--- /dev/null
+++ b/hicn-light/src/hicn/cli/color.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef HICNLIGHT_COLOR
+#define HICNLIGHT_COLOR
+
+#include <stdarg.h>
+
+/*
+ * Format : color_name, escape sequence, windows id
+ */
+#define foreach_color \
+ _(RED, "\033[0;31m", 4) \
+ _(WHITE, "\033[0m", 7)
+
+typedef enum {
+ COLOR_UNDEFINED,
+#define _(x, y, z) COLOR_##x,
+ foreach_color
+#undef _
+ COLOR_N,
+} color_t;
+
+#define IS_VALID_COLOR(color) ((color != COLOR_UNDEFINED) && (color != COLOR_N))
+
+void vprintfc(color_t color, const char* fmt, va_list ap);
+
+void printfc(color_t color, const char* fmt, ...);
+
+#endif /* HICNLIGHT_COLOR */
diff --git a/hicn-light/src/hicn/cli/hicnc.c b/hicn-light/src/hicn/cli/hicnc.c
new file mode 100644
index 000000000..ed8d4ed97
--- /dev/null
+++ b/hicn-light/src/hicn/cli/hicnc.c
@@ -0,0 +1,237 @@
+/*
+ * 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 <hicn/ctrl/parse.h>
+#include <hicn/ctrl/hicn-light.h>
+#include <hicn/util/log.h>
+#include <hicn/util/sstrncpy.h>
+
+#define PORT 9695
+
+/*
+ * Duplicated from hicn_light_ng_api.c while is only available as a module in
+ * libhicnctrl
+ */
+const char *command_type_str[] = {
+#define _(l, u) [COMMAND_TYPE_##u] = STRINGIZE(u),
+ foreach_command_type
+#undef _
+};
+
+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, "dhS:P:", longFormOptions, &optind);
+ if (c == -1) break;
+
+ switch (c) {
+ case 'd':
+ log_conf.log_level = LOG_DEBUG;
+ break;
+ 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_TYPE_HICNLIGHT, url);
+ } else {
+ s = hc_sock_create(FORWARDER_TYPE_HICNLIGHT, NULL);
+ }
+ if (!s) {
+ fprintf(stderr, "Could not create socket.\n");
+ goto ERR_SOCKET;
+ }
+
+ 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;
+
+ rc = hc_execute(s, command.action, command.object_type, &command.object,
+ &data);
+
+ if (rc < 0) {
+ switch (rc) {
+ case INPUT_ERROR:
+ ERROR("Wrong input parameters");
+ break;
+ case UNSUPPORTED_CMD_ERROR:
+ ERROR("Unsupported command");
+ break;
+ default:
+ ERROR("Error executing command");
+ break;
+ }
+ goto ERR_COMMAND;
+ }
+
+ if (!data) goto ERR_QUERY;
+ if (!hc_data_get_result(data)) goto ERR_DATA;
+
+ if (command.action == ACTION_LIST) {
+ char buf[MAXSZ_HC_OBJECT];
+ hc_data_foreach(data, obj, {
+ rc = hc_object_snprintf(buf, MAXSZ_HC_OBJECT, command.object_type, obj);
+ if (rc < 0)
+ WARN("Display error");
+ else if (rc >= MAXSZ_HC_OBJECT)
+ WARN("Output truncated");
+ else
+ printf("%s\n", buf);
+ });
+ }
+
+ hc_data_free(data);
+ hc_sock_free(s);
+ return EXIT_SUCCESS;
+
+ERR_DATA:
+ hc_data_free(data);
+ERR_QUERY:
+ERR_COMMAND:
+ERR_CONNECT:
+ hc_sock_free(s);
+ERR_SOCKET:
+ERR_PARSE:
+ERR_PARAM:
+ ERROR("Error");
+ return EXIT_FAILURE;
+}
diff --git a/hicn-light/src/hicn/cli/hicnd.c b/hicn-light/src/hicn/cli/hicnd.c
new file mode 100644
index 000000000..fa1b1c024
--- /dev/null
+++ b/hicn-light/src/hicn/cli/hicnd.c
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <hicn/util/log.h>
+#include <hicn/base/loop.h>
+
+#include "logo.h"
+#include "../core/forwarder.h"
+#include "../config/configuration.h" // XXX needed ?
+#include "../config/configuration_file.h"
+
+static void usage(const char *prog) {
+ printf(
+ "Usage: %s [--port port]"
+#ifndef _WIN32
+ " [--daemon]"
+#endif
+ " [--capacity objectStoreSize] [--log level]"
+ "[--log-file filename] [--config file]\n",
+ prog);
+ printf("\n");
+ printf(
+ "hicn-light run as a daemon is the program to launch the forwarder, "
+ "either as a console program\n");
+ printf(
+ "or a background daemon (detatched from console). Once running, use the "
+ "program controller to\n");
+ printf("configure hicn-light.\n");
+ printf("\n");
+ printf(
+ "The configuration file contains configuration lines as per "
+ "controller\n");
+ printf(
+ "If logging level or content store capacity is set in the configuraiton "
+ "file, it overrides the command_line\n");
+ printf(
+ "When a configuration file is specified, no default listeners on 'port' "
+ "are setup. Only 'add listener' lines\n");
+ printf("in the configuration file matter.\n");
+ printf("\n");
+ printf(
+ "If no configuration file is specified, daemon will listen on TCP and "
+ "UDP ports specified by\n");
+ printf(
+ "the --port flag (or default port). It will listen on both IPv4 and "
+ "IPv6 if available.\n");
+ printf("\n");
+ printf("Options:\n");
+ printf("%-30s = tcp port for in-bound connections\n", "--port <tcp_port>");
+#ifndef _WIN32
+ printf("%-30s = start as daemon process\n", "--daemon");
+#endif
+ printf(
+ "%-30s = maximum number of content objects to cache. To disable the "
+ "cache objectStoreSize must be 0.\n",
+ "--capacity <objectStoreSize>");
+ printf("%-30s Default vaule for objectStoreSize is 100000\n", "");
+ printf(
+ "%-30s = sets the log level. Available levels: trace, debug, info, warn, "
+ "error, fatal\n",
+ "--log <level>");
+ printf("%-30s = file to write log messages to (required in daemon mode)\n",
+ "--log-file <output_logfile>");
+ printf("%-30s = configuration filename\n", "--config <config_path>");
+ printf("\n");
+}
+
+#ifndef _WIN32
+static int daemonize(int logfile_fd) {
+ /* Check whether we already are a daemon */
+ if (getppid() == 1) return 0;
+
+ int rc = fork();
+ if (rc < 0) {
+ ERROR("Fork error");
+ goto ERR_FORK;
+ } else if (rc > 0) {
+ /* Parent exits successfully */
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Child daemon detaches */
+ DEBUG("child continuing, pid = %u\n", getpid());
+
+ /* get a new process group independent from old parent */
+ setsid();
+
+ /* close all descriptors (apart from the logfile) */
+#ifdef __ANDROID__
+ for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) close(i);
+#else
+ for (int i = getdtablesize(); i >= 0; --i) {
+ if (i != logfile_fd) close(i);
+ }
+#endif
+
+ /*
+ * Reset errno because it might be seg to EBADF from the close calls above
+ */
+ errno = 0;
+ /* Redirect stdin and stdout and stderr to /dev/null */
+ const char *devnull = "/dev/null";
+ int nullfile = open(devnull, O_RDWR);
+ if (nullfile < 0) {
+ ERROR("Error opening file '%s': (%d) %s", devnull, errno, strerror(errno));
+ goto ERR_DEVNULL;
+ }
+
+ /* Redirect stdout and stderr to the logfile */
+ rc = dup2(logfile_fd, STDOUT_FILENO);
+ if (rc != STDOUT_FILENO) {
+ ERROR("Error duping fd 1 got %d file: (%d) %s", rc, errno, strerror(errno));
+ goto ERR_DUP1;
+ }
+ rc = dup2(logfile_fd, STDERR_FILENO);
+ if (rc != STDERR_FILENO) {
+ ERROR("Error duping fd 2 got %d file: (%d) %s", rc, errno, strerror(errno));
+ goto ERR_DUP2;
+ }
+
+ /* Forwarder will capture signals */
+ return 0;
+
+ERR_DUP2:
+ERR_DUP1:
+ERR_DEVNULL:
+ERR_FORK:
+ return -1;
+}
+#endif
+
+static void signal_cb(int sig) {
+ switch (sig) {
+ case SIGTERM:
+ case SIGINT:
+ INFO("caught an interrupt signal, exiting cleanly");
+ break;
+#ifndef _WIN32
+ case SIGUSR1:
+ // dump stats
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (loop_break(MAIN_LOOP) < 0) {
+ ERROR("Failed to terminate main loop");
+ _exit(1);
+ }
+}
+
+static void signal_setup() {
+#ifndef _WIN32
+ signal(SIGUSR1, signal_cb);
+
+ /* ignore child */
+ signal(SIGCHLD, SIG_IGN);
+
+ /* ignore tty signals */
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+#endif
+ signal(SIGINT, signal_cb);
+ signal(SIGTERM, signal_cb);
+}
+
+configuration_t *parse_commandline(int argc, const char *argv[]) {
+ if (argc == 2 && strcasecmp(argv[1], "-h") == 0) {
+ usage(argv[0]);
+ exit(EXIT_SUCCESS); // XXX redundant
+ }
+
+ configuration_t *configuration = configuration_create();
+
+ // XXX use getoptlong ????
+ for (int i = 0; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "--config") == 0) {
+ const char *fn_config = argv[i + 1];
+ configuration_set_fn_config(configuration, fn_config);
+ i++;
+ } else if (strcmp(argv[i], "--port") == 0) {
+ uint16_t port = atoi(argv[i + 1]);
+ configuration_set_port(configuration, port);
+ i++;
+#ifndef _WIN32
+ } else if (strcmp(argv[i], "--daemon") == 0) {
+ configuration_set_daemon(configuration, true);
+#endif
+ } else if (strcmp(argv[i], "--capacity") == 0 ||
+ strcmp(argv[i], "-c") == 0) {
+ int capacity = atoi(argv[i + 1]);
+ configuration_set_cs_size(configuration, capacity);
+ i++;
+ } else if (strcmp(argv[i], "--log") == 0) {
+ int loglevel = loglevel_from_str(argv[i + 1]);
+ configuration_set_loglevel(configuration, loglevel);
+ i++;
+ } else if (strcmp(argv[i], "--log-file") == 0) {
+ if (configuration_get_logfile(configuration)) {
+ fprintf(stderr, "Cannot specify --log-file more than once\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ const char *logfile = argv[i + 1];
+ configuration_set_logfile(configuration, logfile);
+ i++;
+ } else {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ return configuration;
+}
+
+int main(int argc, const char *argv[]) {
+ signal_setup();
+ logo();
+
+ configuration_t *configuration = parse_commandline(argc, argv);
+ const char *logfile = configuration_get_logfile(configuration);
+ bool daemon = configuration_get_daemon(configuration);
+
+ // set restrictive umask, in case we create any files
+ umask(027);
+
+#ifndef _WIN32
+ if (daemon && (logfile == NULL)) {
+ fprintf(stderr, "Must specify a logfile when running in daemon mode\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* In daemon mode, parent will exit and child will continue */
+ if (daemon && daemonize(configuration_get_logfile_fd(configuration)) < 0) {
+ ERROR("Could not daemonize process");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ /*
+ * The loop should be created before the forwarder instance as it is needed
+ * for timers
+ */
+ MAIN_LOOP = loop_create();
+
+ forwarder_t *forwarder = forwarder_create(configuration);
+ if (!forwarder) {
+ ERROR(
+ "Forwarder initialization failed. Are you running it with sudo "
+ "privileges?");
+ return -1;
+ }
+
+ forwarder_setup_local_listeners(forwarder,
+ configuration_get_port(configuration));
+
+ /* If specified, process the configuration file */
+ const char *fn_config = configuration_get_fn_config(configuration);
+ if (fn_config) configuration_file_process(forwarder, fn_config);
+ INFO("%s running port %d configuration-port %d", argv[0],
+ configuration_get_port(configuration),
+ configuration_get_configuration_port(configuration));
+
+ /* Main loop */
+ if (loop_dispatch(MAIN_LOOP) < 0) {
+ ERROR("Failed to run main loop");
+ return EXIT_FAILURE;
+ }
+
+ INFO("loop stopped");
+ forwarder_free(forwarder);
+ loop_free(MAIN_LOOP);
+ MAIN_LOOP = NULL;
+
+#ifdef _WIN32
+ WSACleanup(); // XXX why is this needed here ?
+#endif
+
+ configuration_flush_log();
+ return 0;
+}
diff --git a/hicn-light/src/hicn/cli/hicns.c b/hicn-light/src/hicn/cli/hicns.c
new file mode 100644
index 000000000..c03fa8599
--- /dev/null
+++ b/hicn-light/src/hicn/cli/hicns.c
@@ -0,0 +1,206 @@
+/*
+ * 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 <hicn/ctrl.h>
+
+#ifndef _WIN32
+#include <getopt.h>
+#endif
+
+#include "logo.h"
+#include <hicn/ctrl/parse.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: interactive shell for hicn-light\n", prog);
+ printf("\n");
+ printf("Usage: %s", prog);
+ printf("\n");
+ printf(" %s -h This help screen.\n", prog);
+ printf("\n");
+}
+
+void prompt(void) {
+ fputs("hicn> ", stdout);
+ fflush(stdout);
+}
+
+int shell(hc_sock_t *s) {
+ char *line = NULL;
+ size_t len = 0;
+ hc_data_t *data = NULL;
+ ssize_t nread;
+
+ hc_data_t *connections;
+
+ prompt();
+ while ((nread = getline(&line, &len, stdin)) != -1) {
+ hc_command_t command = {0};
+
+ char *pos;
+ if (line != NULL && (pos = strchr(line, '\n')) != NULL) {
+ *pos = '\0';
+ } else {
+ fprintf(stderr, "Error while reading command.\n");
+ goto CONTINUE;
+ }
+
+ if (strlen(line) == 0) goto CONTINUE;
+
+ if (strncmp(line, "exit", 4) == 0) break;
+ if (strncmp(line, "quit", 4) == 0) break;
+
+ if (parse(line, &command) < 0) {
+ fprintf(stderr, "Unknown command '%s'\n", line);
+ goto CONTINUE;
+ }
+
+ /* XXX connection list */
+ if (hc_connection_list(s, &connections) < 0) {
+ fprintf(stderr, "Error running command.\n");
+ goto CONTINUE;
+ }
+ // data = command.object.data;
+
+ char buf[MAXSZ_HC_CONNECTION]; // XXX
+ foreach_connection(c, data) {
+ /* XXX connection print */
+ int rc = hc_connection_snprintf(buf, MAXSZ_HC_CONNECTION, c);
+ if (rc < 0) {
+ strcpy_s(buf, sizeof(buf), "(Error)");
+ } else if (rc >= MAXSZ_HC_CONNECTION) {
+ buf[MAXSZ_HC_CONNECTION - 1] = '\0';
+ buf[MAXSZ_HC_CONNECTION - 2] = '.';
+ buf[MAXSZ_HC_CONNECTION - 3] = '.';
+ buf[MAXSZ_HC_CONNECTION - 4] = '.';
+ }
+ printf("%s\n", buf);
+ }
+
+ hc_data_free(data);
+ CONTINUE:
+ prompt();
+ }
+
+ return 0;
+}
+
+int main(int argc, char *const *argv) {
+ logo();
+ printf("Type 'help' for a list of available commands\n");
+ printf("\n");
+ printf("\n");
+
+ /* 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 = (uint16_t)val;
+ break;
+ }
+
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+
+ default:
+ fprintf(stderr, "Invalid argument.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "Invalid parameters.\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ 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_TYPE_HICNLIGHT, url);
+ } else {
+ s = hc_sock_create(FORWARDER_TYPE_HICNLIGHT, NULL);
+ }
+ 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;
+ }
+
+ int rc = shell(s);
+
+ exit((rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS);
+
+ERR_CONNECT:
+ hc_sock_free(s);
+ERR_SOCK:
+ exit(EXIT_FAILURE);
+}
diff --git a/hicn-light/src/hicn/cli/logo.h b/hicn-light/src/hicn/cli/logo.h
new file mode 100644
index 000000000..a69097f91
--- /dev/null
+++ b/hicn-light/src/hicn/cli/logo.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef HICNLIGHT_LOGO
+#define HICNLIGHT_LOGO
+
+#include "color.h"
+
+static void logo(void) {
+ printfc(COLOR_RED, " ____ ___ _ ");
+ printfc(COLOR_WHITE, " __ _ __ _ __ __\n");
+ printfc(COLOR_RED, " / __// _ \\ (_)___ ");
+ printfc(COLOR_WHITE, " / / (_)____ ___ ____/ /(_)___ _ / / / /_\n");
+ printfc(COLOR_RED, " / _/ / // /_ / // _ \\ ");
+ printfc(COLOR_WHITE, " / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n");
+ printfc(COLOR_RED, "/_/ /____/(_)/_/ \\___/ ");
+ printfc(COLOR_WHITE, "/_//_//_/ \\__//_//_/ /_//_/ \\_, //_//_/\\__/\n");
+ printfc(
+ COLOR_WHITE,
+ " /___/ "
+ "\n");
+ printf("\n");
+}
+
+#endif /* HICNLIGHT_LOGO */