diff options
Diffstat (limited to 'hicn-light/src/hicn/cli')
-rw-r--r-- | hicn-light/src/hicn/cli/CMakeLists.txt | 56 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/color.c | 81 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/color.h | 43 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/hicnc.c | 181 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/hicnd.c | 400 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/hicns.c | 216 | ||||
-rw-r--r-- | hicn-light/src/hicn/cli/logo.h | 39 |
7 files changed, 1016 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..3f9906b19 --- /dev/null +++ b/hicn-light/src/hicn/cli/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2017-2020 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) + + list(APPEND CONTROLLER_SRC + color.c + hicnc.c + ) + + build_executable(${HICN_LIGHT_CONTROL} + SOURCES ${CONTROLLER_SRC} +#LINK_LIBRARIES -Wl,--whole-archive ${LIBHICN_LIGHT_STATIC} -Wl,--no-whole-archive ${LIBHICNCTRL_STATIC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) + + list(APPEND SHELL_SRC + color.c + hicns.c + ) + + # XXX here linking to libhicnctrl should be sufficient + build_executable(${HICN_LIGHT_SHELL} + SOURCES ${SHELL_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) + + list(APPEND DAEMON_SRC + color.c + hicnd.c + ) + + build_executable(${HICN_LIGHT_DAEMON} + SOURCES ${DAEMON_SRC} + LINK_LIBRARIES ${LIBHICN_LIGHT_SHARED} ${LIBHICNCTRL_STATIC} + DEPENDS ${LIBHICN_LIGHT_STATIC} + COMPONENT ${HICN_LIGHT} + DEFINITIONS ${COMPILER_DEFINITIONS} + ) +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..2fff2ead6 --- /dev/null +++ b/hicn-light/src/hicn/cli/color.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017-2020 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: + 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..763666f18 --- /dev/null +++ b/hicn-light/src/hicn/cli/color.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017-2020 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..d6c7c4180 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnc.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017-2020 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 "color.h" +#include "../config/parse.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"); +} + +int +main(int argc, char * const * argv) +{ + /* 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; + } + + hc_command_t command; + if (parse(param, &command) < 0) { + fprintf(stderr, "Error parsing command : '%s'\n", param); + goto ERR_PARSE; + } + + + hc_data_t * data; + + 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_url(url); + } else { + s = hc_sock_create(); + } + 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; + } + + /* XXX connection list */ + if (hc_connection_list(s, &data) < 0) { + fprintf(stderr, "Error running command"); + goto ERR_CMD; + } + + 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) { + strncpy(buf, "(Error)", MAXSZ_HC_CONNECTION); + } 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); + exit(EXIT_SUCCESS); + +ERR_CMD: +ERR_CONNECT: + hc_sock_free(s); +ERR_SOCK: +ERR_PARSE: +ERR_PARAM: + exit(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..a989cff25 --- /dev/null +++ b/hicn-light/src/hicn/cli/hicnd.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2017-2019 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/hicn-light/config.h> +#include <hicn/util/log.h> + +#include "logo.h" +#include "../base/loop.h" +#include "../core/forwarder.h" + +static +void +usage(const char * prog) +{ + printf("Usage: %s [--port port]" +#ifndef _WIN32 + " [--daemon]" +#endif + " [--capacity objectStoreSize] [--log facility=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("--port = tcp port for in-bound connections\n"); +#ifndef _WIN32 + printf("--daemon = start as daemon process\n"); +#endif + printf("--objectStoreSize = maximum number of content objects to cache\n"); + printf( + "--log = sets a facility to a given log level. You can have " + "multiple of these.\n"); + printf( + " facilities: all, config, core, io, message, " + "processor\n"); + printf( + " levels: debug, info, notice, warning, error, " + "critical, alert, off\n"); + printf(" example: daemon --log io=debug --log core=off\n"); + printf( + "--log-file = file to write log messages to (required in daemon " + "mode)\n"); + printf("--config = configuration filename\n"); + printf("\n"); +} + +#if 0 +static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END], + LoggerFacility facility, + const char *levelString) { + PARCLogLevel level = parcLogLevel_FromString(levelString); + + if (level < PARCLogLevel_All) { + // we have a good facility and level + logLevelArray[facility] = level; + } else { + printf("Invalid log level string %s\n", levelString); + usage(""); // XXX + exit(EXIT_FAILURE); + } +} + +/** + * string: "facility=level" + * Set the right thing in the logger + */ +static void _setLogLevel(int logLevelArray[LoggerFacility_END], + const char *string) { + char *tofree = parcMemory_StringDuplicate(string, strlen(string)); + char *p = tofree; + + char *facilityString = strtok(p, "="); + if (facilityString) { + char *levelString = strtok(NULL, "="); + + if (strcasecmp(facilityString, "all") == 0) { + for (LoggerFacility facility = 0; facility < LoggerFacility_END; + facility++) { + _setLogLevelToLevel(logLevelArray, facility, levelString); + } + } else { + LoggerFacility facility; + for (facility = 0; facility < LoggerFacility_END; facility++) { + if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) { + break; + } + } + + if (facility < LoggerFacility_END) { + _setLogLevelToLevel(logLevelArray, facility, levelString); + } else { + printf("Invalid facility string %s\n", facilityString); + usage(""); // XXX + exit(EXIT_FAILURE); + } + } + } + + parcMemory_Deallocate((void **)&tofree); +} +#endif + +#ifndef _WIN32 +static +int daemonize(void) +{ + /* 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 */ +#ifdef __ANDROID__ + for (int i = sysconf(_SC_OPEN_MAX); i >= 0; --i) + close(i); +#else + for (int i = getdtablesize(); i >= 0; --i) + 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; + } + + + rc = dup(nullfile); + if (rc != 1) { + ERROR("Error duping fd 1 got %d file: (%d) %s", rc, errno, strerror(errno)); + goto ERR_DUP1; + } + rc = dup(nullfile); + if (rc != 2) { + 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 + +#if 0 +static Logger *_createLogfile(const char *logfile) { +#ifndef _WIN32 + int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR); +#else + int logfd = + _open(logfile, _O_WRONLY | _O_APPEND | _O_CREAT, _S_IWRITE | _S_IREAD); +#endif + if (logfd < 0) { + fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno, + strerror(errno)); + exit(EXIT_FAILURE); + } + +#ifndef _WIN32 + chmod(logfile, S_IRWXU); +#endif + + PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd); + PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos); + PARCLogReporter *reporter = parcLogReporterFile_Create(pos); + + Logger *logger = logger_Create(reporter, parcClock_Wallclock()); + + parcOutputStream_Release(&pos); + parcLogReporter_Release(&reporter); + + return logger; +} +#endif + +int +main(int argc, const char * argv[]) +{ + logo(); + +#ifndef _WIN32 + bool daemon = false; +#else + WSADATA wsaData = {0}; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + + uint16_t port = PORT_NUMBER; + uint16_t configurationPort = 2001; + int capacity = -1; + const char *fn_config = NULL; + + char *logfile = NULL; + + if (argc == 2 && strcasecmp(argv[1], "-h") == 0) { + usage(argv[0]); + exit(EXIT_SUCCESS); // XXX redundant + } + +#if 0 + int logLevelArray[LoggerFacility_END]; + for (int i = 0; i < LoggerFacility_END; i++) + logLevelArray[i] = -1; +#endif + + // XXX use getoptlong ???? + for (int i = 0; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--config") == 0) { + fn_config = argv[i + 1]; + i++; + } else if (strcmp(argv[i], "--port") == 0) { + port = atoi(argv[i + 1]); + i++; +#ifndef _WIN32 + } else if (strcmp(argv[i], "--daemon") == 0) { + daemon = true; +#endif + } else if (strcmp(argv[i], "--capacity") == 0 || + strcmp(argv[i], "-c") == 0) { + capacity = atoi(argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--log") == 0) { + // XXX _setLogLevel(logLevelArray, argv[i + 1]); + i++; + } else if (strcmp(argv[i], "--log-file") == 0) { + if (logfile) { + // error cannot repeat + fprintf(stderr, "Cannot specify --log-file more than once\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + logfile = strndup(argv[i + 1], strlen(argv[i + 1])); + i++; + } else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + } + + // 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() < 0) { + ERROR("Could not daemonize process"); + exit(EXIT_FAILURE); + } +#endif + +#if 0 // XXX use hicn own logging + Logger *logger = NULL; + if (logfile) { + logger = _createLogfile(logfile); + parcMemory_Deallocate((void **)&logfile); + } else { + PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create(); + logger = logger_Create(stdoutReporter, parcClock_Wallclock()); + parcLogReporter_Release(&stdoutReporter); + } + + for (int i = 0; i < LoggerFacility_END; i++) { + if (logLevelArray[i] > -1) { + logger_SetLogLevel(logger, i, logLevelArray[i]); + } + } +#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(); + if (!forwarder) { + ERROR("Forwarder initialization failed. Are you running it with sudo privileges?"); + return -1; + } + + configuration_t * configuration = forwarder_get_configuration(forwarder); + if (capacity > -1) { + configuration_cs_set_size(configuration, capacity); + } + + forwarder_setup_local_listeners(forwarder, port); + if (fn_config) { + forwarder_read_config(forwarder, fn_config); + } + + INFO("%s running port %d configuration-port %d", argv[0], port, + configurationPort); + + /* Main loop */ + if (loop_dispatch(MAIN_LOOP) < 0) { + ERROR("Failed to run main loop"); + return EXIT_FAILURE; + } + + INFO("%s exiting port %d", argv[0], port); + + if (loop_undispatch(MAIN_LOOP) < 0) { + ERROR("Failed to terminate main loop"); + return EXIT_FAILURE; + } + + forwarder_free(forwarder); + + loop_free(MAIN_LOOP); + MAIN_LOOP = NULL; + +#ifdef _WIN32 + WSACleanup(); // XXX why is this needed here ? +#endif + + 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..03e1bd54c --- /dev/null +++ b/hicn-light/src/hicn/cli/hicns.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2017-2020 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 "../config/parse.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; + + prompt(); + while ((nread = getline(&line, &len, stdin)) != -1) { + hc_command_t command; + + char * pos; + if ((pos=strchr(line, '\n')) != NULL) + *pos = '\0'; + + if (strlen(line) == 0) + goto CONTINUE; + + if (strcmp(line, "exit") == 0) + break; + if (strcmp(line, "quit") == 0) + break; + + + if (parse(line, &command) < 0) { + fprintf(stderr, "Unknown command '%s'\n", line); + goto CONTINUE; + } + + /* XXX connection list */ + if (hc_connection_list(s, &data) < 0) { + fprintf(stderr, "Error running command.\n"); + goto CONTINUE; + } + + 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) { + strncpy(buf, "(Error)", MAXSZ_HC_CONNECTION); + } 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_url(url); + } else { + s = hc_sock_create(); + } + 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..1aff32837 --- /dev/null +++ b/hicn-light/src/hicn/cli/logo.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2020 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 */ |