aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2011-04-07 11:55:17 -0400
committerNick Mathewson <nickm@torproject.org>2011-04-07 11:55:17 -0400
commit07ab483e62457ee56187037304f25ec50cb0850a (patch)
treedc11e627e0c2ef4ce9338b6468e901815e87039d /src/or
parent09759a66eae044e640f477ebe96b1c3edbb98c94 (diff)
parent118d8ffdcb74137a36d22928ce6f46897809391e (diff)
downloadtor-07ab483e62457ee56187037304f25ec50cb0850a.tar
tor-07ab483e62457ee56187037304f25ec50cb0850a.tar.gz
Merge remote-tracking branch 'origin/maint-0.2.2'
Diffstat (limited to 'src/or')
-rw-r--r--src/or/control.c4
-rw-r--r--src/or/geoip.c172
-rw-r--r--src/or/geoip.h2
3 files changed, 97 insertions, 81 deletions
diff --git a/src/or/control.c b/src/or/control.c
index d9d1dfeb5..a3504ffd9 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1851,12 +1851,12 @@ getinfo_helper_events(control_connection_t *control_conn,
"information", question);
}
} else if (!strcmp(question, "status/clients-seen")) {
- const char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL));
+ char *bridge_stats = geoip_get_bridge_stats_controller(time(NULL));
if (!bridge_stats) {
*errmsg = "No bridge-client stats available";
return -1;
}
- *answer = tor_strdup(bridge_stats);
+ *answer = bridge_stats;
} else {
return 0;
}
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 04289f312..03e5b523b 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -1103,14 +1103,14 @@ geoip_bridge_stats_term(void)
start_of_bridge_stats_interval = 0;
}
-/** Parse the bridge statistics as they are written to extra-info
- * descriptors for being returned to controller clients. Return the
- * controller string if successful, or NULL otherwise. */
-static char *
-parse_bridge_stats_controller(const char *stats_str, time_t now)
+/** Validate a bridge statistics string as it would be written to a
+ * current extra-info descriptor. Return 1 if the string is valid and
+ * recent enough, or 0 otherwise. */
+static int
+validate_bridge_stats(const char *stats_str, time_t now)
{
char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1],
- *controller_str, *eos, *eol, *summary;
+ *eos;
const char *BRIDGE_STATS_END = "bridge-stats-end ";
const char *BRIDGE_IPS = "bridge-ips ";
@@ -1124,63 +1124,90 @@ parse_bridge_stats_controller(const char *stats_str, time_t now)
"bridge-stats-end YYYY-MM-DD HH:MM:SS (N s)" */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_STATS_END);
if (!tmp)
- return NULL;
+ return 0;
tmp += strlen(BRIDGE_STATS_END);
if (strlen(tmp) < ISO_TIME_LEN + 6)
- return NULL;
+ return 0;
strlcpy(stats_end_str, tmp, sizeof(stats_end_str));
if (parse_iso_time(stats_end_str, &stats_end_time) < 0)
- return NULL;
+ return 0;
if (stats_end_time < now - (25*60*60) ||
stats_end_time > now + (1*60*60))
- return NULL;
+ return 0;
seconds = (int)strtol(tmp + ISO_TIME_LEN + 2, &eos, 10);
if (!eos || seconds < 23*60*60)
- return NULL;
+ return 0;
format_iso_time(stats_start_str, stats_end_time - seconds);
/* Parse: "bridge-ips CC=N,CC=N,..." */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS);
- if (tmp) {
- tmp += strlen(BRIDGE_IPS);
- tmp = eat_whitespace_no_nl(tmp);
- eol = strchr(tmp, '\n');
- if (eol)
- summary = tor_strndup(tmp, eol-tmp);
- else
- summary = tor_strdup(tmp);
- } else {
+ if (!tmp) {
/* Look if there is an empty "bridge-ips" line */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_IPS_EMPTY_LINE);
if (!tmp)
- return NULL;
- summary = tor_strdup("");
+ return 0;
}
- tor_asprintf(&controller_str,
- "TimeStarted=\"%s\" CountrySummary=%s",
- stats_start_str, summary);
- tor_free(summary);
- return controller_str;
+ return 1;
}
/** Most recent bridge statistics formatted to be written to extra-info
* descriptors. */
static char *bridge_stats_extrainfo = NULL;
-/** Most recent bridge statistics formatted to be returned to controller
- * clients. */
-static char *bridge_stats_controller = NULL;
+/** Return a newly allocated string holding our bridge usage stats by country
+ * in a format suitable for inclusion in an extrainfo document. Return NULL on
+ * failure. */
+static char *
+format_bridge_stats_extrainfo(time_t now)
+{
+ char *out = NULL, *data = NULL;
+ long duration = now - start_of_bridge_stats_interval;
+ char written[ISO_TIME_LEN+1];
+
+ if (duration < 0)
+ return NULL;
+
+ format_iso_time(written, now);
+ data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+
+ tor_asprintf(&out,
+ "bridge-stats-end %s (%ld s)\n"
+ "bridge-ips %s\n",
+ written, duration,
+ data ? data : "");
+ tor_free(data);
+
+ return out;
+}
+
+/** Return a newly allocated string holding our bridge usage stats by country
+ * in a format suitable for the answer to a controller request. Return NULL on
+ * failure. */
+static char *
+format_bridge_stats_controller(time_t now)
+{
+ char *out = NULL, *data = NULL;
+ char started[ISO_TIME_LEN+1];
+ (void) now;
+
+ format_iso_time(started, start_of_bridge_stats_interval);
+ data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+
+ tor_asprintf(&out,
+ "TimeStarted=\"%s\" CountrySummary=%s",
+ started, data ? data : "");
+ tor_free(data);
+ return out;
+}
/** Write bridge statistics to $DATADIR/stats/bridge-stats and return
* when we should next try to write statistics. */
time_t
geoip_bridge_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *data = NULL,
- written[ISO_TIME_LEN+1], *out = NULL, *controller_str;
- size_t len;
+ char *filename = NULL, *val = NULL, *statsdir = NULL;
/* Check if 24 hours have passed since starting measurements. */
if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL)
@@ -1189,64 +1216,54 @@ geoip_bridge_stats_write(time_t now)
/* Discard all items in the client history that are too old. */
geoip_remove_old_clients(start_of_bridge_stats_interval);
+ /* Generate formatted string */
+ val = format_bridge_stats_extrainfo(now);
+ if (val == NULL)
+ goto done;
+
+ /* Update the stored value. */
+ tor_free(bridge_stats_extrainfo);
+ bridge_stats_extrainfo = val;
+ start_of_bridge_stats_interval = now;
+
+ /* Write it to disk. */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE) < 0)
goto done;
filename = get_datadir_fname2("stats", "bridge-stats");
- data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
- format_iso_time(written, now);
- len = strlen("bridge-stats-end (999999 s)\nbridge-ips \n") +
- ISO_TIME_LEN + (data ? strlen(data) : 0) + 42;
- out = tor_malloc(len);
- if (tor_snprintf(out, len, "bridge-stats-end %s (%u s)\nbridge-ips %s\n",
- written, (unsigned) (now - start_of_bridge_stats_interval),
- data ? data : "") < 0)
- goto done;
- write_str_to_file(filename, out, 0);
- controller_str = parse_bridge_stats_controller(out, now);
- if (!controller_str)
- goto done;
- start_of_bridge_stats_interval = now;
- tor_free(bridge_stats_extrainfo);
- tor_free(bridge_stats_controller);
- bridge_stats_extrainfo = out;
- out = NULL;
- bridge_stats_controller = controller_str;
- control_event_clients_seen(controller_str);
+
+ write_str_to_file(filename, bridge_stats_extrainfo, 0);
+
+ /* Tell the controller, "hey, there are clients!" */
+ {
+ char *controller_str = format_bridge_stats_controller(now);
+ if (controller_str)
+ control_event_clients_seen(controller_str);
+ tor_free(controller_str);
+ }
done:
tor_free(filename);
tor_free(statsdir);
- tor_free(data);
- tor_free(out);
- return start_of_bridge_stats_interval +
- WRITE_STATS_INTERVAL;
+
+ return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
}
/** Try to load the most recent bridge statistics from disk, unless we
- * have finished a measurement interval lately. */
+ * have finished a measurement interval lately, and check whether they
+ * are still recent enough. */
static void
load_bridge_stats(time_t now)
{
- char *statsdir, *fname=NULL, *contents, *controller_str;
+ char *fname, *contents;
if (bridge_stats_extrainfo)
return;
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE) < 0)
- goto done;
+
fname = get_datadir_fname2("stats", "bridge-stats");
contents = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
- if (contents) {
- controller_str = parse_bridge_stats_controller(contents, now);
- if (controller_str) {
- bridge_stats_extrainfo = contents;
- bridge_stats_controller = controller_str;
- } else {
- tor_free(contents);
- }
- }
- done:
+ if (contents && validate_bridge_stats(contents, now))
+ bridge_stats_extrainfo = contents;
+
tor_free(fname);
- tor_free(statsdir);
}
/** Return most recent bridge statistics for inclusion in extra-info
@@ -1258,13 +1275,12 @@ geoip_get_bridge_stats_extrainfo(time_t now)
return bridge_stats_extrainfo;
}
-/** Return most recent bridge statistics to be returned to controller
- * clients, or NULL if we don't have recent bridge statistics. */
-const char *
+/** Return a new string containing the recent bridge statistics to be returned
+ * to controller clients, or NULL if we don't have any bridge statistics. */
+char *
geoip_get_bridge_stats_controller(time_t now)
{
- load_bridge_stats(now);
- return bridge_stats_controller;
+ return format_bridge_stats_controller(now);
}
/** Start time of entry stats or 0 if we're not collecting entry
diff --git a/src/or/geoip.h b/src/or/geoip.h
index 1a8baae41..02228eab3 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -52,7 +52,7 @@ void geoip_bridge_stats_init(time_t now);
time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
-const char *geoip_get_bridge_stats_controller(time_t);
+char *geoip_get_bridge_stats_controller(time_t);
#endif