From 8acaf8e1872f711898e850687ccf55a196dc1312 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 20 Nov 2004 00:37:00 +0000 Subject: [PATCH] Add "MEMUNIT" and "INTERVAL" types to configuration. Also tweak Accounting setup. More docs needed svn:r2911 --- doc/TODO | 4 +- src/common/compat.h | 2 + src/or/config.c | 185 ++++++++++++++++++++++++++++++++++++++--- src/or/connection.c | 14 ++-- src/or/connection_or.c | 2 +- src/or/hibernate.c | 14 ++-- src/or/or.h | 14 ++-- src/or/router.c | 4 +- 8 files changed, 202 insertions(+), 37 deletions(-) diff --git a/doc/TODO b/doc/TODO index 250320bff0..dc592a6bb1 100644 --- a/doc/TODO +++ b/doc/TODO @@ -11,8 +11,8 @@ ARMA - arma claims X Abandoned Tor 0.0.9rc1: - - Weasel wants to say 50GB rather than 50000000 in config ints. - - Nick wants to say "1 hour" instead of 3600 in config ints. + o Weasel wants to say 50GB rather than 50000000 in config ints. + o Nick wants to say "1 hour" instead of 3600 in config ints. - Better hibernation flexibility - Add hibernation intervals for weeks, days. - Start at a time other than 0:00 GMT. diff --git a/src/common/compat.h b/src/common/compat.h index 32dc7e1725..5b0ed36a0c 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -69,10 +69,12 @@ size_t strlcpy(char *dst, const char *src, size_t siz); #define U64_PRINTF_ARG(a) (a) #define U64_SCANF_ARG(a) (a) #define U64_FORMAT "%I64u" +#define U64_LITERAL(n) (n ## ui64) #else #define U64_PRINTF_ARG(a) ((long long unsigned int)a) #define U64_SCANF_ARG(a) ((long long unsigned int*)a) #define U64_FORMAT "%llu" +#define U64_LITERAL(n) (n ## llu) #endif int tor_snprintf(char *str, size_t size, const char *format, ...) diff --git a/src/or/config.c b/src/or/config.c index cf22ad1f09..05cf0a2f88 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -20,6 +20,10 @@ typedef enum config_type_t { CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */ CONFIG_TYPE_UINT, /**< A non-negative integer less than MAX_INT */ + /* DOCDOC */ + CONFIG_TYPE_INTERVAL, /**< A non-negative integer less than MAX_INT */ + /* DOCDOC */ + CONFIG_TYPE_MEMUNIT, /**< A non-negative integer less than MAX_INT */ CONFIG_TYPE_DOUBLE, /**< A floating-point value */ CONFIG_TYPE_BOOL, /**< A boolean value, expressed as 0 or 1. */ CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and optional @@ -55,8 +59,8 @@ static config_abbrev_t config_abbrevs[] = { PLURAL(RendNode), PLURAL(RendExcludeNode), { "l", "Log", 1}, - { "BandwidthRate", "BandwidthRateBytes", 0}, - { "BandwidthBurst", "BandwidthBurstBytes", 0}, + { "BandwidthRateBytes", "BandwidthRate", 0}, + { "BandwidthBurstBytes", "BandwidthBurst", 0}, { "DirFetchPostPeriod", "DirFetchPeriod", 0}, { NULL, NULL , 0}, }; @@ -89,8 +93,8 @@ static config_var_t config_vars[] = { VAR("Address", STRING, Address, NULL), VAR("AllowUnverifiedNodes",CSV, AllowUnverifiedNodes, "middle,rendezvous"), VAR("AuthoritativeDirectory",BOOL, AuthoritativeDir, "0"), - VAR("BandwidthRateBytes", UINT, BandwidthRateBytes, "800000"), - VAR("BandwidthBurstBytes", UINT, BandwidthBurstBytes, "50000000"), + VAR("BandwidthRate", MEMUNIT, BandwidthRate, "780 KB"), + VAR("BandwidthBurst", MEMUNIT, BandwidthBurst, "48 MB"), VAR("ClientOnly", BOOL, ClientOnly, "0"), VAR("ContactInfo", STRING, ContactInfo, NULL), VAR("ControlPort", UINT, ControlPort, "0"), @@ -99,9 +103,9 @@ static config_var_t config_vars[] = { VAR("DataDirectory", STRING, DataDirectory, NULL), VAR("DirPort", UINT, DirPort, "0"), VAR("DirBindAddress", LINELIST, DirBindAddress, NULL), - VAR("DirFetchPeriod", UINT, DirFetchPeriod, "3600"), - VAR("DirPostPeriod", UINT, DirPostPeriod, "600"), - VAR("RendPostPeriod", UINT, RendPostPeriod, "600"), + VAR("DirFetchPeriod", INTERVAL, DirFetchPeriod, "1 hour"), + VAR("DirPostPeriod", INTERVAL, DirPostPeriod, "10 mintues"), + VAR("RendPostPeriod", INTERVAL, RendPostPeriod, "10 minutes"), VAR("DirPolicy", LINELIST, DirPolicy, NULL), VAR("DirServer", LINELIST, DirServers, NULL), VAR("ExitNodes", STRING, ExitNodes, NULL), @@ -123,7 +127,7 @@ static config_var_t config_vars[] = { VAR("HiddenServiceNodes", LINELIST_S, RendConfigLines, NULL), VAR("HiddenServiceExcludeNodes", LINELIST_S, RendConfigLines, NULL), VAR("IgnoreVersion", BOOL, IgnoreVersion, "0"), - VAR("KeepalivePeriod", UINT, KeepalivePeriod, "300"), + VAR("KeepalivePeriod", INTERVAL, KeepalivePeriod, "5 minutes"), VAR("Log", LINELIST, Logs, NULL), VAR("LogLevel", LINELIST_S, OldLogOptions, NULL), VAR("LogFile", LINELIST_S, OldLogOptions, NULL), @@ -131,9 +135,10 @@ static config_var_t config_vars[] = { VAR("MaxConn", UINT, MaxConn, "1024"), VAR("MaxOnionsPending", UINT, MaxOnionsPending, "100"), VAR("MonthlyAccountingStart",UINT, AccountingStart, "1"), - VAR("AccountingMaxKB", UINT, AccountingMaxKB, "0"), + VAR("AccountingMaxKB", UINT, _AccountingMaxKB, "0"), + VAR("AccountingMax", MEMUNIT, AccountingMax, "0 bytes"), VAR("Nickname", STRING, Nickname, NULL), - VAR("NewCircuitPeriod", UINT, NewCircuitPeriod, "30"), + VAR("NewCircuitPeriod", INTERVAL, NewCircuitPeriod, "30 seconds"), VAR("NumCpus", UINT, NumCpus, "1"), VAR("ORPort", UINT, ORPort, "0"), VAR("ORBindAddress", LINELIST, ORBindAddress, NULL), @@ -150,7 +155,7 @@ static config_var_t config_vars[] = { VAR("SocksPort", UINT, SocksPort, "9050"), VAR("SocksBindAddress", LINELIST, SocksBindAddress, NULL), VAR("SocksPolicy", LINELIST, SocksPolicy, NULL), - VAR("StatusFetchPeriod", UINT, StatusFetchPeriod, "1200"), + VAR("StatusFetchPeriod", INTERVAL, StatusFetchPeriod, "20 minutes"), VAR("SysLog", LINELIST_S, OldLogOptions, NULL), OBSOLETE("TrafficShaping"), VAR("User", STRING, User, NULL), @@ -185,6 +190,9 @@ static int normalize_log_options(or_options_t *options); static int validate_data_directory(or_options_t *options); static int write_configuration_file(const char *fname, or_options_t *options); +static uint64_t config_parse_memunit(const char *s, int *ok); +static int config_parse_interval(const char *s, int *ok); + /* * Functions to read and write the global options pointer. */ @@ -529,6 +537,24 @@ config_assign_line(or_options_t *options, struct config_line_t *c, int reset) *(int *)lvalue = i; break; + case CONFIG_TYPE_INTERVAL: { + i = config_parse_interval(c->value, &ok); + if (!ok) { + return -2; + } + *(int *)lvalue = i; + break; + } + + case CONFIG_TYPE_MEMUNIT: { + uint64_t u64 = config_parse_memunit(c->value, &ok); + if (!ok) { + return -2; + } + *(uint64_t *)lvalue = u64; + break; + } + case CONFIG_TYPE_BOOL: i = tor_parse_long(c->value, 10, 0, 1, &ok, NULL); if (!ok) { @@ -648,12 +674,18 @@ config_get_assigned_option(or_options_t *options, const char *key) return NULL; } break; + case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_UINT: /* This means every or_options_t uint or bool element * needs to be an int. Not, say, a uint16_t or char. */ tor_snprintf(buf, sizeof(buf), "%d", *(int*)value); result->value = tor_strdup(buf); break; + case CONFIG_TYPE_MEMUNIT: + tor_snprintf(buf, sizeof(buf), U64_FORMAT, + U64_PRINTF_ARG(*(uint64_t*)value)); + result->value = tor_strdup(buf); + break; case CONFIG_TYPE_DOUBLE: tor_snprintf(buf, sizeof(buf), "%f", *(double*)value); result->value = tor_strdup(buf); @@ -771,10 +803,14 @@ option_reset(or_options_t *options, config_var_t *var) case CONFIG_TYPE_DOUBLE: *(double*)lvalue = 0.0; break; + case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_UINT: case CONFIG_TYPE_BOOL: *(int*)lvalue = 0; break; + case CONFIG_TYPE_MEMUNIT: + *(uint64_t*)lvalue = 0; + break; case CONFIG_TYPE_CSV: if (*(smartlist_t**)lvalue) { SMARTLIST_FOREACH(*(smartlist_t **)lvalue, char *, cp, tor_free(cp)); @@ -930,6 +966,8 @@ options_free(or_options_t *options) for (i=0; config_vars[i].name; ++i) { lvalue = ((char*)options) + config_vars[i].var_offset; switch(config_vars[i].type) { + case CONFIG_TYPE_MEMUNIT: + case CONFIG_TYPE_INTERVAL: case CONFIG_TYPE_UINT: case CONFIG_TYPE_BOOL: case CONFIG_TYPE_DOUBLE: @@ -1183,6 +1221,12 @@ options_validate(or_options_t *options) result = -1; } + if (options->_AccountingMaxKB) { + log(LOG_WARN, "AccountingMaxKB is deprecated. Say 'AccountingMax %d KB' instead.", options->_AccountingMaxKB); + options->AccountingMax = U64_LITERAL(1024)*options->_AccountingMaxKB; + options->_AccountingMaxKB = 0; + } + if (options->FirewallPorts) { SMARTLIST_FOREACH(options->FirewallPorts, const char *, cp, { @@ -1257,8 +1301,8 @@ options_validate(or_options_t *options) result = -1; } - if (2*options->BandwidthRateBytes >= options->BandwidthBurstBytes) { - log(LOG_WARN,"BandwidthBurstBytes must be more than twice BandwidthRateBytes."); + if (2*options->BandwidthRate >= options->BandwidthBurst) { + log(LOG_WARN,"BandwidthBurst must be more than twice BandwidthRate."); result = -1; } @@ -2161,6 +2205,121 @@ save_current_config(void) return write_configuration_file(fn, get_options()); } +struct unit_table_t { + const char *unit; + uint64_t multiplier; +}; + +static struct unit_table_t memory_units[] = { + { "byte", 1<< 0 }, + { "bytes", 1<< 0 }, + { "k", 1<<10 }, + { "kb", 1<<10 }, + { "kilobyte", 1<<10 }, + { "kilobytes", 1<<10 }, + { "m", 1<<20 }, + { "mb", 1<<20 }, + { "megabyte", 1<<20 }, + { "megabytes", 1<<20 }, + { "g", 1<<30 }, + { "gb", 1<<30 }, + { "gigabyte", 1<<30 }, + { "gigabytes", 1<<30 }, + { "t", U64_LITERAL(1)<<40 }, + { "tb", U64_LITERAL(1)<<40 }, + { "terabyte", U64_LITERAL(1)<<40 }, + { "terabytes", U64_LITERAL(1)<<40 }, + { NULL, 0 }, +}; + +static struct unit_table_t time_units[] = { + { "s", 1 }, + { "sec", 1 }, + { "secs", 1 }, + { "second", 1 }, + { "seconds", 1 }, + { "min", 60 }, + { "mins", 60 }, + { "minute", 60 }, + { "minutes", 60 }, + { "h", 60*60 }, + { "hr", 60*60 }, + { "hrs", 60*60 }, + { "hour", 60*60 }, + { "hours", 60*60 }, + { "day", 24*60*60 }, + { "days", 24*60*60 }, + { "week", 7*24*60*60 }, + { "weeks", 7*24*60*60 }, + { NULL, 0 }, +}; + +/** Parse a string val containing a number, zero or more + * spaces, and an optional unit string. If the unit appears in the + * table u, then multiply the number by the unit multiplier. + * On success, set *ok to 1 and return this product. + * Otherwise, set *ok to 0. + */ +static uint64_t +config_parse_units(const char *val, struct unit_table_t *u, int *ok) +{ + uint64_t v; + char *cp; + + tor_assert(ok); + + v = tor_parse_uint64(val, 10, 0, UINT64_MAX, ok, &cp); + if (!*ok) + return 0; + if (!cp) { + *ok = 1; + return v; + } + while(isspace(*cp)) + ++cp; + for ( ;u->unit;++u) { + if (!strcasecmp(u->unit, cp)) { + v *= u->multiplier; + *ok = 1; + return v; + } + } + log_fn(LOG_WARN, "Unknown unit '%s'.", cp); + *ok = 0; + return 0; +} + +/** Parse a string in the format "number unit", where unit is a unit of + * information (byte, KB, M, etc). On success, set *ok to true + * and return the number of bytes specified. Otherwise, set + * *ok to false and return 0. */ +static uint64_t +config_parse_memunit(const char *s, int *ok) { + return config_parse_units(s, memory_units, ok); +} + +/** Parse a string in the format "number unit", where unit is a unit of time. + * On success, set *ok to true and return the number of seconds in + * the provided interval. Otherwise, set *ok to 0 and return -1. + */ +static int +config_parse_interval(const char *s, int *ok) { + uint64_t r; + r = config_parse_units(s, time_units, ok); + if (!ok) + return -1; + if (r > INT_MAX) { + log_fn(LOG_WARN, "Interval '%s' is too long", s); + *ok = 0; + return -1; + } else if (r<0) { + log_fn(LOG_WARN, "Interval '%s' is negative", s); + *ok = 0; + return -1; + } + return r; +} + /* Local Variables: mode:c diff --git a/src/or/connection.c b/src/or/connection.c index ceadfb6ed5..e2f06cea43 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -718,12 +718,12 @@ static void connection_consider_empty_buckets(connection_t *conn) { } } -/** Initiatialize the global read bucket to options->BandwidthBurstBytes, +/** Initiatialize the global read bucket to options->BandwidthBurst, * and current_time to the current time. */ void connection_bucket_init(void) { or_options_t *options = get_options(); - global_read_bucket = options->BandwidthBurstBytes; /* start it at max traffic */ - global_write_bucket = options->BandwidthBurstBytes; /* start it at max traffic */ + global_read_bucket = options->BandwidthBurst; /* start it at max traffic */ + global_write_bucket = options->BandwidthBurst; /* start it at max traffic */ } /** A second has rolled over; increment buckets appropriately. */ @@ -734,12 +734,12 @@ void connection_bucket_refill(struct timeval *now) { or_options_t *options = get_options(); /* refill the global buckets */ - if(global_read_bucket < options->BandwidthBurstBytes) { - global_read_bucket += options->BandwidthRateBytes; + if(global_read_bucket < options->BandwidthBurst) { + global_read_bucket += options->BandwidthRate; log_fn(LOG_DEBUG,"global_read_bucket now %d.", global_read_bucket); } - if(global_write_bucket < options->BandwidthBurstBytes) { - global_write_bucket += options->BandwidthRateBytes; + if(global_write_bucket < options->BandwidthBurst) { + global_write_bucket += options->BandwidthRate; log_fn(LOG_DEBUG,"global_write_bucket now %d.", global_write_bucket); } diff --git a/src/or/connection_or.c b/src/or/connection_or.c index d96db8d0d2..273867e054 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -136,7 +136,7 @@ connection_or_init_conn_from_address(connection_t *conn, conn->addr = addr; conn->port = port; /* This next part isn't really right, but it's good enough for now. */ - conn->receiver_bucket = conn->bandwidth = options->BandwidthBurstBytes; + conn->receiver_bucket = conn->bandwidth = options->BandwidthBurst; memcpy(conn->identity_digest, id_digest, DIGEST_LEN); /* If we're an authoritative directory server, we may know a * nickname for this router. */ diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 7bff2934d8..054b96e00f 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -95,7 +95,7 @@ static void accounting_set_wakeup_time(void); * hibernate, return 1, else return 0. */ int accounting_is_enabled(or_options_t *options) { - if (options->AccountingMaxKB) + if (options->AccountingMax) return 1; return 0; } @@ -205,13 +205,13 @@ static void update_expected_bandwidth(void) { uint64_t used; - uint32_t max_configured = (get_options()->BandwidthRateBytes * 60); + uint32_t max_configured = (get_options()->BandwidthRate * 60); if (n_seconds_active_in_interval < 1800) { /* If we haven't gotten enough data last interval, guess that * we'll be used at our maximum capacity. This is unlikely to be * so, but it will give us an okay first estimate, and we'll stay - * up until we send MaxKB kilobytes. Next interval, we'll choose + * up until we send Max ytes. Next interval, we'll choose * our starting time based on how much we sent this interval. */ expected_bandwidth_usage = max_configured; @@ -302,7 +302,7 @@ accounting_set_wakeup_time(void) if (expected_bandwidth_usage) n_days_to_exhaust_bw = - (get_options()->AccountingMaxKB/expected_bandwidth_usage)/(24*60); + (get_options()->AccountingMax/expected_bandwidth_usage)/(24*60); else n_days_to_exhaust_bw = 1; @@ -442,7 +442,7 @@ read_bandwidth_usage(void) static int hibernate_hard_limit_reached(void) { - uint64_t hard_limit = get_options()->AccountingMaxKB<<10; + uint64_t hard_limit = get_options()->AccountingMax; if (!hard_limit) return 0; return n_bytes_read_in_interval >= hard_limit @@ -453,7 +453,7 @@ hibernate_hard_limit_reached(void) * to send/receive this interval. */ static int hibernate_soft_limit_reached(void) { - uint64_t soft_limit = (uint64_t) ((get_options()->AccountingMaxKB<<10) * .99); + uint64_t soft_limit = (uint64_t) ((get_options()->AccountingMax) * .99); if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit @@ -582,7 +582,7 @@ hibernate_end_time_elapsed(time_t now) * to start/stop hibernating. */ void consider_hibernation(time_t now) { - int accounting_enabled = get_options()->AccountingMaxKB != 0; + int accounting_enabled = get_options()->AccountingMax != 0; char buf[ISO_TIME_LEN+1]; /* If we're in 'exiting' mode, then we just shut down after the interval diff --git a/src/or/or.h b/src/or/or.h index 223ea4a845..f581291f45 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -937,9 +937,9 @@ typedef struct { * them? */ int NewCircuitPeriod; /**< How long do we use a circuit before building * a new one? */ - int BandwidthRateBytes; /**< How much bandwidth, on average, are we willing to + uint64_t BandwidthRate; /**< How much bandwidth, on average, are we willing to * use in a second? */ - int BandwidthBurstBytes; /**< How much bandwidth, at maximum, are we willing to + uint64_t BandwidthBurst; /**< How much bandwidth, at maximum, are we willing to * use in a second? */ int NumCpus; /**< How many CPUs should we try to use? */ int RunTesting; /**< If true, create testing circuits to measure how well the @@ -963,9 +963,13 @@ typedef struct { int AccountingStart; /**< At what offset within the accounting interval * do we begin measuring? (Currently only day-of-month * is supported.) */ - int AccountingMaxKB; /**< How many KB do we allow per accounting - * interval before hibernation? 0 for "never - * hibernate." */ + uint64_t AccountingMax; /**< How many bytes do we allow per accounting + * interval before hibernation? 0 for "never + * hibernate." */ + int _AccountingMaxKB; /**< How many KB do we allow per accounting + * interval before hibernation? 0 for "never + * hibernate." */ + char *HashedControlPassword; /**< Base64-encoded hash of a password for * the control system. */ int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for diff --git a/src/or/router.c b/src/or/router.c index e2c7fa7deb..a7cb473fc0 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -550,8 +550,8 @@ int router_rebuild_descriptor(int force) { } get_platform_str(platform, sizeof(platform)); ri->platform = tor_strdup(platform); - ri->bandwidthrate = options->BandwidthRateBytes; - ri->bandwidthburst = options->BandwidthBurstBytes; + ri->bandwidthrate = options->BandwidthRate; + ri->bandwidthburst = options->BandwidthBurst; ri->bandwidthcapacity = router_get_bandwidth_capacity(); router_add_exit_policy_from_config(ri); if(desc_routerinfo) /* inherit values */