Write extra-info bridge-ip-transports lines.

This commit is contained in:
George Kadianakis 2013-02-11 20:52:28 +01:00 committed by Nick Mathewson
parent e765d6ed84
commit 05306ad74f
2 changed files with 123 additions and 3 deletions

View File

@ -782,6 +782,107 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
}
}
/** Return the bridge-ip-transports string that should be inserted in
* our extra-info descriptor. Return NULL if the bridge-ip-transports
* line should be empty. */
char *
geoip_get_transport_history(void)
{
unsigned granularity = IP_GRANULARITY;
/** String hash table <name of transport> -> <number of users>. */
strmap_t *transport_counts = strmap_new();
void *ptr;
intptr_t val;
/** Smartlist that contains copies of the names of the transports
that have been used. */
smartlist_t *transports_used = smartlist_new();
/* Special string to signify that no transport was used for this
connection. Pluggable transport names can't have symbols in their
names, so this string will never collide with a real transport. */
static const char* no_transport_str = "<OR>";
clientmap_entry_t **ent;
const char *transport_name = NULL;
smartlist_t *string_chunks = smartlist_new();
char *the_string = NULL;
int i = 0;
/* If we haven't seen any clients yet, return NULL. */
if (HT_EMPTY(&client_history))
goto done;
/** We do the following steps to form the transport history string:
* a) Foreach client that uses a pluggable transport, we increase the
* times that transport was used by one. If the client did not use
* a transport, we increase the number of times someone connected
* without obfuscation.
* b) Foreach transport we observed, we write its transport history
* string and push it to string_chunks. So, for example, if we've
* seen 665 obfs2 clients, we write "obfs2=665".
* c) We concatenate string_chunks to form the final string.
*/
log_debug(LD_GENERAL,"Starting iteration for transport history. %d clients.",
HT_SIZE(&client_history));
/* Loop through all clients. */
HT_FOREACH(ent, clientmap, &client_history) {
transport_name = (*ent)->transport_name;
if (!transport_name)
transport_name = no_transport_str;
/* Increase the count for this transport name. */
ptr = strmap_get(transport_counts, transport_name);
val = (intptr_t)ptr;
val++;
ptr = (void*)val;
strmap_set(transport_counts, transport_name, ptr);
/* If it's the first time we see this transport, note it. */
if (!smartlist_contains_string(transports_used, transport_name))
smartlist_add(transports_used, tor_strdup(transport_name));
log_debug(LD_GENERAL, "Client from '%s' with transport '%s'. "
"I've now seen %d clients.",
safe_str_client(fmt_addr(&(*ent)->addr)),
transport_name ? transport_name : "<no transport>",
(int)val);
}
/* Sort the transport names (helps with unit testing). */
smartlist_sort_strings(transports_used);
/* Loop through all seen transports. */
SMARTLIST_FOREACH_BEGIN(transports_used, const char *, transport_name) {
void *transport_count_ptr = strmap_get(transport_counts, transport_name);
unsigned int transport_count = (uintptr_t) transport_count_ptr;
i++; /* counter so that we don't add a comma if it's the last transport. */
log_debug(LD_GENERAL, "We got %u clients with transport '%s'.",
transport_count, transport_name);
smartlist_add_asprintf(string_chunks, "%s=%u%s",
transport_name,
round_to_next_multiple_of(transport_count, granularity),
i != smartlist_len(transports_used) ? "," : "");
} SMARTLIST_FOREACH_END(transport_name);
the_string = smartlist_join_strings(string_chunks, "", 0, NULL);
log_debug(LD_GENERAL, "Final bridge-ip-transports string: '%s'", the_string);
done:
strmap_free(transport_counts, NULL);
SMARTLIST_FOREACH(transports_used, char *, s, tor_free(s));
smartlist_free(transports_used);
SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
smartlist_free(string_chunks);
return the_string;
}
/** Return a newly allocated comma-separated string containing statistics
* on network status downloads. The string contains the number of completed
* requests, timeouts, and still running requests as well as the download
@ -1202,6 +1303,8 @@ validate_bridge_stats(const char *stats_str, time_t now)
const char *BRIDGE_STATS_END = "bridge-stats-end ";
const char *BRIDGE_IPS = "bridge-ips ";
const char *BRIDGE_IPS_EMPTY_LINE = "bridge-ips\n";
const char *BRIDGE_TRANSPORTS = "bridge-ip-transports ";
const char *BRIDGE_TRANSPORTS_EMPTY_LINE = "bridge-ip-transports\n";
const char *tmp;
time_t stats_end_time;
int seconds;
@ -1236,6 +1339,16 @@ validate_bridge_stats(const char *stats_str, time_t now)
return 0;
}
/* Parse: "bridge-ip-transports PT=N,PT=N,..." */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS);
if (!tmp) {
/* Look if there is an empty "bridge-ip-transports" line */
tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS_EMPTY_LINE);
if (!tmp)
return 0;
}
return 1;
}
@ -1249,7 +1362,8 @@ static char *bridge_stats_extrainfo = NULL;
char *
geoip_format_bridge_stats(time_t now)
{
char *out = NULL, *country_data = NULL, *ipver_data = NULL;
char *out = NULL;
char *country_data = NULL, *ipver_data = NULL, *transport_data = NULL;
long duration = now - start_of_bridge_stats_interval;
char written[ISO_TIME_LEN+1];
@ -1260,16 +1374,20 @@ geoip_format_bridge_stats(time_t now)
format_iso_time(written, now);
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
transport_data = geoip_get_transport_history();
tor_asprintf(&out,
"bridge-stats-end %s (%ld s)\n"
"bridge-ips %s\n"
"bridge-ip-versions %s\n",
"bridge-ip-versions %s\n"
"bridge-ip-transports %s\n",
written, duration,
country_data ? country_data : "",
ipver_data ? ipver_data : "");
ipver_data ? ipver_data : "",
transport_data ? transport_data : "");
tor_free(country_data);
tor_free(ipver_data);
tor_free(transport_data);
return out;
}
@ -1544,5 +1662,6 @@ geoip_free_all(void)
}
clear_geoip_db();
tor_free(bridge_stats_extrainfo);
}

View File

@ -34,6 +34,7 @@ void geoip_note_client_seen(geoip_client_action_t action,
void geoip_remove_old_clients(time_t cutoff);
void geoip_note_ns_response(geoip_ns_response_t response);
char *geoip_get_transport_history(void);
int geoip_get_client_history(geoip_client_action_t action,
char **country_str, char **ipver_str);
char *geoip_get_request_history(void);