X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafs-config.c;fp=src%2Fafs-config.c;h=80504d05b46c7271d01b3b60f374afd82a652b89;hb=ac7a95223a6314cca6250495ea59c3cf7e46e89e;hp=0000000000000000000000000000000000000000;hpb=fc460fb90672bc80d1f140a8f6cf72d7ad95353a;p=src%2Fapp-framework-binder.git diff --git a/src/afs-config.c b/src/afs-config.c new file mode 100644 index 00000000..80504d05 --- /dev/null +++ b/src/afs-config.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2015, 2016, 2017 "IoT.bzh" + * Author José Bollo + * + * 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. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "verbose.h" +#include "afs-config.h" + +#if !defined(AFB_VERSION) +#error "you should define AFB_VERSION" +#endif + +// default +#define DEFLT_CNTX_TIMEOUT 32000000 // default Client Connection + // Timeout: few more than one year +#define DEFLT_API_TIMEOUT 20 // default Plugin API Timeout [0=NoLimit + // for Debug Only] +#define DEFLT_CACHE_TIMEOUT 100000 // default Static File Chache + // [Client Side Cache + // 100000~=1day] +#define CTX_NBCLIENTS 10 // allow a default of 10 authenticated + // clients + + +// Define command line option +#define SET_ROOT_DIR 6 +#define SET_ROOT_BASE 7 +#define SET_ROOT_API 8 + +#define SET_CACHE_TIMEOUT 10 +#define SET_SESSION_DIR 11 + +#define SET_APITIMEOUT 14 +#define SET_CNTXTIMEOUT 15 + +#define SET_SESSIONMAX 23 + +#define SET_ROOT_HTTP 26 + +#define DISPLAY_HELP 'h' +#define SET_NAME 'n' +#define SET_TCP_PORT 'p' +#define SET_QUIET 'q' +#define SET_AUTH_TOKEN 't' +#define SET_UPLOAD_DIR 'u' +#define DISPLAY_VERSION 'V' +#define SET_VERBOSE 'v' +#define SET_WORK_DIR 'w' + +const char shortopts[] = + "hn:p:qrt:u:Vvw:" +; + +// Command line structure hold cli --command + help text +typedef struct { + int val; // command number within application + int has_arg; // command number within application + char *name; // command as used in --xxxx cli + char *help; // help text +} AFB_options; + +// Supported option +static AFB_options cliOptions[] = { +/* *INDENT-OFF* */ + {SET_VERBOSE, 0, "verbose", "Verbose Mode, repeat to increase verbosity"}, + {SET_QUIET, 0, "quiet", "Quiet Mode, repeat to decrease verbosity"}, + + {SET_NAME, 1, "name", "Set the visible name"}, + + {SET_TCP_PORT, 1, "port", "HTTP listening TCP port [default 1234]"}, + {SET_ROOT_HTTP, 1, "roothttp", "HTTP Root Directory [default no root http (files not served but apis still available)]"}, + {SET_ROOT_BASE, 1, "rootbase", "Angular Base Root URL [default /opa]"}, + {SET_ROOT_API, 1, "rootapi", "HTML Root API URL [default /api]"}, + + {SET_APITIMEOUT, 1, "apitimeout", "Binding API timeout in seconds [default 10]"}, + {SET_CNTXTIMEOUT, 1, "cntxtimeout", "Client Session Context Timeout [default 900]"}, + {SET_CACHE_TIMEOUT, 1, "cache-eol", "Client cache end of live [default 3600]"}, + + {SET_WORK_DIR, 1, "workdir", "Set the working directory [default: $PWD or current working directory]"}, + {SET_UPLOAD_DIR, 1, "uploaddir", "Directory for uploading files [default: workdir]"}, + {SET_ROOT_DIR, 1, "rootdir", "Root Directory of the application [default: workdir]"}, + {SET_SESSION_DIR, 1, "sessiondir", "OBSOLETE (was: Sessions file path)"}, + + {SET_AUTH_TOKEN, 1, "token", "Initial Secret [default=random, use --token="" to allow any token]"}, + + {DISPLAY_VERSION, 0, "version", "Display version and copyright"}, + {DISPLAY_HELP, 0, "help", "Display this help"}, + + {SET_SESSIONMAX, 1, "session-max", "Max count of session simultaneously [default 10]"}, + + {0, 0, NULL, NULL} +/* *INDENT-ON* */ +}; + + +struct enumdesc +{ + const char *name; + int value; +}; + +/*---------------------------------------------------------- + | printversion + | print version and copyright + +--------------------------------------------------------- */ +static void printVersion(FILE * file) +{ + static const char version[] = + "\n" + " afs-supervisor [Application Framework Supervisor] version="AFB_VERSION"\n" + "\n" + " Copyright (C) 2015-2018 \"IoT.bzh\"\n" + " afs-supervisor comes with ABSOLUTELY NO WARRANTY.\n" + " Licence Apache 2\n" + "\n"; + + fprintf(file, "%s", version); +} + +/*---------------------------------------------------------- + | printHelp + | print information from long option array + +--------------------------------------------------------- */ + +static void printHelp(FILE * file, const char *name) +{ + int ind; + char command[50]; + + fprintf(file, "%s:\nallowed options\n", name); + for (ind = 0; cliOptions[ind].name != NULL; ind++) { + strcpy(command, cliOptions[ind].name); + if (cliOptions[ind].has_arg) + strcat(command, "=xxxx"); + fprintf(file, " --%-15s %s\n", command, cliOptions[ind].help); + } + fprintf(file, + "Example:\n %s --verbose --port=1234 --token='azerty'\n", + name); +} + + +/*--------------------------------------------------------- + | helpers for argument scanning + +--------------------------------------------------------- */ + +static const char *name_of_option(int optc) +{ + AFB_options *o = cliOptions; + while (o->name && o->val != optc) + o++; + return o->name ? : ""; +} + +static const char *current_argument(int optc) +{ + if (optarg == 0) { + ERROR("option [--%s] needs a value i.e. --%s=xxx", + name_of_option(optc), name_of_option(optc)); + exit(1); + } + return optarg; +} + +static char *argvalstr(int optc) +{ + char *result = strdup(current_argument(optc)); + if (result == NULL) { + ERROR("can't alloc memory"); + exit(1); + } + return result; +} + +static int argvalint(int optc, int mini, int maxi, int base) +{ + const char *beg, *end; + long int val; + beg = current_argument(optc); + val = strtol(beg, (char**)&end, base); + if (*end || end == beg) { + ERROR("option [--%s] requires a valid integer (found %s)", + name_of_option(optc), beg); + exit(1); + } + if (val < (long int)mini || val > (long int)maxi) { + ERROR("option [--%s] value out of bounds (not %d<=%ld<=%d)", + name_of_option(optc), mini, val, maxi); + exit(1); + } + return (int)val; +} + +static int argvalintdec(int optc, int mini, int maxi) +{ + return argvalint(optc, mini, maxi, 10); +} + +static void noarg(int optc) +{ + if (optarg != 0) { + ERROR("option [--%s] need no value (found %s)", name_of_option(optc), optarg); + exit(1); + } +} + +/*--------------------------------------------------------- + | Parse option and launch action + +--------------------------------------------------------- */ + +static void parse_arguments(int argc, char **argv, struct afs_config *config) +{ + char *programName = argv[0]; + int optc, ind; + int nbcmd; + struct option *gnuOptions; + + // ------------------ Process Command Line ----------------------- + + // build GNU getopt info from cliOptions + nbcmd = sizeof(cliOptions) / sizeof(AFB_options); + gnuOptions = malloc(sizeof(*gnuOptions) * (unsigned)nbcmd); + for (ind = 0; ind < nbcmd; ind++) { + gnuOptions[ind].name = cliOptions[ind].name; + gnuOptions[ind].has_arg = cliOptions[ind].has_arg; + gnuOptions[ind].flag = 0; + gnuOptions[ind].val = cliOptions[ind].val; + } + + // get all options from command line + while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) { + switch (optc) { + case SET_VERBOSE: + verbosity++; + break; + + case SET_QUIET: + verbosity--; + break; + + case SET_TCP_PORT: + config->httpdPort = argvalintdec(optc, 1024, 32767); + break; + + case SET_APITIMEOUT: + config->apiTimeout = argvalintdec(optc, 0, INT_MAX); + break; + + case SET_CNTXTIMEOUT: + config->cntxTimeout = argvalintdec(optc, 0, INT_MAX); + break; + + case SET_ROOT_DIR: + config->rootdir = argvalstr(optc); + INFO("Forcing Rootdir=%s", config->rootdir); + break; + + case SET_ROOT_HTTP: + config->roothttp = argvalstr(optc); + INFO("Forcing Root HTTP=%s", config->roothttp); + break; + + case SET_ROOT_BASE: + config->rootbase = argvalstr(optc); + INFO("Forcing Rootbase=%s", config->rootbase); + break; + + case SET_ROOT_API: + config->rootapi = argvalstr(optc); + INFO("Forcing Rootapi=%s", config->rootapi); + break; + + case SET_AUTH_TOKEN: + config->token = argvalstr(optc); + break; + + case SET_UPLOAD_DIR: + config->uploaddir = argvalstr(optc); + break; + + case SET_WORK_DIR: + config->workdir = argvalstr(optc); + break; + + case SET_CACHE_TIMEOUT: + config->cacheTimeout = argvalintdec(optc, 0, INT_MAX); + break; + + case SET_SESSIONMAX: + config->nbSessionMax = argvalintdec(optc, 1, INT_MAX); + break; + + case SET_NAME: + config->name = argvalstr(optc); + break; + + case DISPLAY_VERSION: + noarg(optc); + printVersion(stdout); + exit(0); + + case DISPLAY_HELP: + printHelp(stdout, programName); + exit(0); + + default: + exit(1); + } + } + free(gnuOptions); +} + +static void fulfill_config(struct afs_config *config) +{ + // default HTTP port + if (config->httpdPort == 0) + config->httpdPort = 1234; + + // default binding API timeout + if (config->apiTimeout == 0) + config->apiTimeout = DEFLT_API_TIMEOUT; + + // cache timeout default one hour + if (config->cacheTimeout == 0) + config->cacheTimeout = DEFLT_CACHE_TIMEOUT; + + // cache timeout default one hour + if (config->cntxTimeout == 0) + config->cntxTimeout = DEFLT_CNTX_TIMEOUT; + + // max count of sessions + if (config->nbSessionMax == 0) + config->nbSessionMax = CTX_NBCLIENTS; + + /* set directories */ + if (config->workdir == NULL) + config->workdir = "."; + + if (config->rootdir == NULL) + config->rootdir = "."; + + if (config->uploaddir == NULL) + config->uploaddir = "."; + + // if no Angular/HTML5 rootbase let's try '/' as default + if (config->rootbase == NULL) + config->rootbase = "/opa"; + + if (config->rootapi == NULL) + config->rootapi = "/api"; +} + +void afs_config_dump(struct afs_config *config) +{ +#define NN(x) (x)?:"" +#define P(...) fprintf(stderr, __VA_ARGS__) +#define PF(x) P("-- %15s: ", #x) +#define PE P("\n") +#define S(x) PF(x);P("%s",NN(config->x));PE; +#define D(x) PF(x);P("%d",config->x);PE; + + P("---BEGIN-OF-CONFIG---\n"); + S(rootdir) + S(roothttp) + S(rootbase) + S(rootapi) + S(workdir) + S(uploaddir) + S(token) + S(name) + + D(httpdPort) + D(cacheTimeout) + D(apiTimeout) + D(cntxTimeout) + D(nbSessionMax) + P("---END-OF-CONFIG---\n"); + +#undef V +#undef E +#undef L +#undef B +#undef D +#undef S +#undef PE +#undef PF +#undef P +#undef NN +} + +static void parse_environment(struct afs_config *config) +{ +} + +struct afs_config *afs_config_parse_arguments(int argc, char **argv) +{ + struct afs_config *result; + + result = calloc(1, sizeof *result); + + parse_environment(result); + parse_arguments(argc, argv, result); + fulfill_config(result); + if (verbosity >= 3) + afs_config_dump(result); + return result; +} +