123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- /* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
- /* See LICENSE for licensing information */
- /* $Id$ */
- #include "or.h"
- /* enumeration of types which option values can take */
- #define CONFIG_TYPE_STRING 0
- #define CONFIG_TYPE_CHAR 1
- #define CONFIG_TYPE_INT 2
- #define CONFIG_TYPE_LONG 3
- #define CONFIG_TYPE_DOUBLE 4
- #define CONFIG_TYPE_BOOL 5
- #define CONFIG_LINE_MAXLEN 1024
- struct config_line {
- char *key;
- char *value;
- struct config_line *next;
- };
- static FILE *config_open(const unsigned char *filename);
- static int config_close(FILE *f);
- static struct config_line *config_get_commandlines(int argc, char **argv);
- static struct config_line *config_get_lines(FILE *f);
- static void config_free_lines(struct config_line *front);
- static int config_compare(struct config_line *c, char *key, int type, void *arg);
- static void config_assign(or_options_t *options, struct config_line *list);
- /* open configuration file for reading */
- static FILE *config_open(const unsigned char *filename) {
- assert(filename);
- if (strspn(filename,CONFIG_LEGAL_FILENAME_CHARACTERS) != strlen(filename)) {
- /* filename has illegal letters */
- return NULL;
- }
- return fopen(filename, "r");
- }
- /* close configuration file */
- static int config_close(FILE *f) {
- assert(f);
- return fclose(f);
- }
- static struct config_line *config_get_commandlines(int argc, char **argv) {
- struct config_line *new;
- struct config_line *front = NULL;
- char *s;
- int i = 1;
- while(i < argc-1) {
- if(!strcmp(argv[i],"-f")) {
- // log(LOG_DEBUG,"Commandline: skipping over -f.");
- i+=2; /* this is the config file option. ignore it. */
- continue;
- }
- new = tor_malloc(sizeof(struct config_line));
- s = argv[i];
- while(*s == '-')
- s++;
- new->key = tor_strdup(s);
- new->value = tor_strdup(argv[i+1]);
- log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
- new->key, new->value);
- new->next = front;
- front = new;
- i += 2;
- }
- return front;
- }
- /* parse the config file and strdup into key/value strings. Return list,
- * or NULL if parsing the file failed.
- * Warn and ignore mangled lines. */
- static struct config_line *config_get_lines(FILE *f) {
- struct config_line *new;
- struct config_line *front = NULL;
- char line[CONFIG_LINE_MAXLEN];
- int result;
- char *key, *value;
- while( (result=parse_line_from_file(line,sizeof(line),f,&key,&value)) > 0) {
- new = tor_malloc(sizeof(struct config_line));
- new->key = tor_strdup(key);
- new->value = tor_strdup(value);
- new->next = front;
- front = new;
- }
- if(result < 0)
- return NULL;
- return front;
- }
- static void config_free_lines(struct config_line *front) {
- struct config_line *tmp;
- while(front) {
- tmp = front;
- front = tmp->next;
- free(tmp->key);
- free(tmp->value);
- free(tmp);
- }
- }
- static int config_compare(struct config_line *c, char *key, int type, void *arg) {
- int i;
- if(strncasecmp(c->key,key,strlen(c->key)))
- return 0;
- /* it's a match. cast and assign. */
- log_fn(LOG_DEBUG,"Recognized keyword '%s' as %s, using value '%s'.",c->key,key,c->value);
- switch(type) {
- case CONFIG_TYPE_INT:
- *(int *)arg = atoi(c->value);
- break;
- case CONFIG_TYPE_BOOL:
- i = atoi(c->value);
- if (i != 0 && i != 1) {
- log(LOG_WARNING, "Boolean keyword '%s' expects 0 or 1", c->key);
- return 0;
- }
- *(int *)arg = i;
- break;
- case CONFIG_TYPE_STRING:
- *(char **)arg = tor_strdup(c->value);
- break;
- case CONFIG_TYPE_DOUBLE:
- *(double *)arg = atof(c->value);
- break;
- }
- return 1;
- }
- static void config_assign(or_options_t *options, struct config_line *list) {
- /* iterate through list. for each item convert as appropriate and assign to 'options'. */
- while(list) {
- if(
- /* order matters here! abbreviated arguments use the first match. */
- /* string options */
- config_compare(list, "LogLevel", CONFIG_TYPE_STRING, &options->LogLevel) ||
- config_compare(list, "DataDirectory", CONFIG_TYPE_STRING, &options->DataDirectory) ||
- config_compare(list, "RouterFile", CONFIG_TYPE_STRING, &options->RouterFile) ||
- config_compare(list, "Nickname", CONFIG_TYPE_STRING, &options->Nickname) ||
- config_compare(list, "Address", CONFIG_TYPE_STRING, &options->Address) ||
- /* int options */
- config_compare(list, "MaxConn", CONFIG_TYPE_INT, &options->MaxConn) ||
- config_compare(list, "APPort", CONFIG_TYPE_INT, &options->APPort) ||
- config_compare(list, "ORPort", CONFIG_TYPE_INT, &options->ORPort) ||
- config_compare(list, "DirPort", CONFIG_TYPE_INT, &options->DirPort) ||
- config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_INT, &options->DirFetchPostPeriod) ||
- config_compare(list, "KeepalivePeriod", CONFIG_TYPE_INT, &options->KeepalivePeriod) ||
- config_compare(list, "MaxOnionsPending",CONFIG_TYPE_INT, &options->MaxOnionsPending) ||
- config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_INT, &options->NewCircuitPeriod) ||
- config_compare(list, "TotalBandwidth", CONFIG_TYPE_INT, &options->TotalBandwidth) ||
- config_compare(list, "NumCpus", CONFIG_TYPE_INT, &options->NumCpus) ||
- config_compare(list, "OnionRouter", CONFIG_TYPE_BOOL, &options->OnionRouter) ||
- config_compare(list, "Daemon", CONFIG_TYPE_BOOL, &options->Daemon) ||
- config_compare(list, "TrafficShaping", CONFIG_TYPE_BOOL, &options->TrafficShaping) ||
- config_compare(list, "LinkPadding", CONFIG_TYPE_BOOL, &options->LinkPadding) ||
- config_compare(list, "IgnoreVersion", CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
- /* float options */
- config_compare(list, "CoinWeight", CONFIG_TYPE_DOUBLE, &options->CoinWeight)
- ) {
- /* then we're ok. it matched something. */
- } else {
- log_fn(LOG_WARNING,"Ignoring unknown keyword '%s'.",list->key);
- }
- list = list->next;
- }
- }
- /* return 0 if success, <0 if failure. */
- int getconfig(int argc, char **argv, or_options_t *options) {
- struct config_line *cl;
- FILE *cf;
- char *fname;
- int i;
- int result = 0;
- /* give reasonable values for each option. Defaults to zero. */
- memset(options,0,sizeof(or_options_t));
- options->LogLevel = "info";
- options->loglevel = LOG_DEBUG;
- options->DataDirectory = NULL;
- options->CoinWeight = 0.1;
- options->MaxConn = 900;
- options->DirFetchPostPeriod = 600;
- options->KeepalivePeriod = 300;
- options->MaxOnionsPending = 10;
- options->NewCircuitPeriod = 60; /* once a minute */
- options->TotalBandwidth = 800000; /* at most 800kB/s total sustained incoming */
- options->NumCpus = 1;
- /* learn config file name, get config lines, assign them */
- i = 1;
- while(i < argc-1 && strcmp(argv[i],"-f")) {
- i++;
- }
- if(i < argc-1) { /* we found one */
- fname = argv[i+1];
- } else { /* didn't find one, try /etc/torrc */
- fname = "/etc/torrc";
- }
- log(LOG_DEBUG,"Opening config file '%s'",fname);
- cf = config_open(fname);
- if(!cf) {
- log(LOG_WARNING, "Unable to open configuration file '%s'.",fname);
- return -1;
- }
- cl = config_get_lines(cf);
- if(!cl) return -1;
- config_assign(options,cl);
- config_free_lines(cl);
- config_close(cf);
-
- /* go through command-line variables too */
- cl = config_get_commandlines(argc,argv);
- config_assign(options,cl);
- config_free_lines(cl);
- /* Validate options */
- if(options->LogLevel) {
- if(!strcmp(options->LogLevel,"err"))
- options->loglevel = LOG_ERR;
- else if(!strncmp(options->LogLevel,"warn",4))
- options->loglevel = LOG_WARNING;
- else if(!strcmp(options->LogLevel,"info"))
- options->loglevel = LOG_INFO;
- else if(!strcmp(options->LogLevel,"debug"))
- options->loglevel = LOG_DEBUG;
- else {
- log(LOG_WARNING,"LogLevel must be one of err|warning|info|debug.");
- result = -1;
- }
- }
- if(options->RouterFile == NULL) {
- log(LOG_WARNING,"RouterFile option required, but not found.");
- result = -1;
- }
- if(options->ORPort < 0) {
- log(LOG_WARNING,"ORPort option can't be negative.");
- result = -1;
- }
- if(options->OnionRouter && options->ORPort == 0) {
- log(LOG_WARNING,"If OnionRouter is set, then ORPort must be positive.");
- result = -1;
- }
- if(options->OnionRouter && options->DataDirectory == NULL) {
- log(LOG_WARNING,"DataDirectory option required for OnionRouter, but not found.");
- result = -1;
- }
- if(options->OnionRouter && options->Nickname == NULL) {
- log_fn(LOG_WARNING,"Nickname required for OnionRouter, but not found.");
- result = -1;
- }
- if(options->APPort < 0) {
- log(LOG_WARNING,"APPort option can't be negative.");
- result = -1;
- }
- if(options->DirPort < 0) {
- log(LOG_WARNING,"DirPort option can't be negative.");
- result = -1;
- }
- if(options->APPort > 1 &&
- (options->CoinWeight < 0.0 || options->CoinWeight >= 1.0)) {
- log(LOG_WARNING,"CoinWeight option must be >=0.0 and <1.0.");
- result = -1;
- }
- if(options->MaxConn < 1) {
- log(LOG_WARNING,"MaxConn option must be a non-zero positive integer.");
- result = -1;
- }
- if(options->MaxConn >= MAXCONNECTIONS) {
- log(LOG_WARNING,"MaxConn option must be less than %d.", MAXCONNECTIONS);
- result = -1;
- }
- if(options->DirFetchPostPeriod < 1) {
- log(LOG_WARNING,"DirFetchPostPeriod option must be positive.");
- result = -1;
- }
- if(options->KeepalivePeriod < 1) {
- log(LOG_WARNING,"KeepalivePeriod option must be positive.");
- result = -1;
- }
- return result;
- }
- /*
- Local Variables:
- mode:c
- indent-tabs-mode:nil
- c-basic-offset:2
- End:
- */
|