summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2007-12-18 23:45:19 +0000
committerNick Mathewson <nickm@torproject.org>2007-12-18 23:45:19 +0000
commit076097281dde078149ed789cf3df0ef6ecce815d (patch)
tree5cbcb59faf2391139c370e916559399f9e8555a1
parent74d05f4b2cf31d6bbda1a60b9a4d589cf62c9a51 (diff)
downloadtor-076097281dde078149ed789cf3df0ef6ecce815d.tar.gz
tor-076097281dde078149ed789cf3df0ef6ecce815d.zip
r17239@catbus: nickm | 2007-12-18 16:57:02 -0500
Sort GeoIP results in descending order of IP counts. svn:r12863
-rw-r--r--src/or/geoip.c48
-rw-r--r--src/or/test.c2
2 files changed, 46 insertions, 4 deletions
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 5ca9f9c2a4..0c82e97ea5 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -294,6 +294,27 @@ geoip_get_history_start(void)
return client_history_starts;
}
+/* Helper type: used to sort results by value. */
+typedef struct c_hist_t {
+ char country[3];
+ unsigned total;
+} c_hist_t;
+
+/** Sorting helper: return -1, 1, or 0 based on comparison of two
+ * geoip_entry_t. Sort in descending order of total, and then by country
+ * code. */
+static int
+_c_hist_compare(const void **_a, const void **_b)
+{
+ const c_hist_t *a = *_a, *b = *_b;
+ if (a->total > b->total)
+ return -1;
+ else if (a->total < b->total)
+ return 1;
+ else
+ return strcmp(a->country, b->country);
+}
+
/** Return a newly allocated comma-separated string containing entries for all
* the countries from which we've seen enough clients connect. The entry
* format is cc=num where num is the number of IPs we've seen connecting from
@@ -308,6 +329,7 @@ geoip_get_client_history(time_t now)
if (client_history_starts < (now - 12*60*60)) {
char buf[32];
smartlist_t *chunks = NULL;
+ smartlist_t *entries = NULL;
int n_countries = geoip_get_n_countries();
int i;
clientmap_entry_t **ent;
@@ -321,19 +343,35 @@ geoip_get_client_history(time_t now)
++counts[country];
++total;
}
+ /* Don't record anything if we haven't seen enough IPs. */
if (total < MIN_IPS_TO_NOTE_ANYTHING)
goto done;
- chunks = smartlist_create();
+ /* Make a list of c_hist_t */
+ entries = smartlist_create();
for (i = 0; i < n_countries; ++i) {
unsigned c = counts[i];
const char *countrycode;
+ c_hist_t *ent;
+ /* Only report a country if it has a minimum number of IPs. */
if (c >= MIN_IPS_TO_NOTE_COUNTRY) {
c -= c % IP_GRANULARITY;
countrycode = geoip_get_country_name(i);
- tor_snprintf(buf, sizeof(buf), "%s=%u", countrycode, c);
- smartlist_add(chunks, tor_strdup(buf));
+ ent = tor_malloc(sizeof(c_hist_t));
+ strlcpy(ent->country, countrycode, sizeof(ent->country));
+ ent->total = c;
+ smartlist_add(entries, ent);
}
}
+ /* Sort entries. Note that we must do this _AFTER_ rounding, or else
+ * the sort order could leak info. */
+ smartlist_sort(entries, _c_hist_compare);
+
+ /* Build the result. */
+ chunks = smartlist_create();
+ SMARTLIST_FOREACH(entries, c_hist_t *, ch, {
+ tor_snprintf(buf, sizeof(buf), "%s=%u", ch->country, ch->total);
+ smartlist_add(chunks, tor_strdup(buf));
+ });
result = smartlist_join_strings(chunks, ",", 0, NULL);
done:
tor_free(counts);
@@ -341,6 +379,10 @@ geoip_get_client_history(time_t now)
SMARTLIST_FOREACH(chunks, char *, c, tor_free(c));
smartlist_free(chunks);
}
+ if (entries) {
+ SMARTLIST_FOREACH(entries, c_hist_t *, c, tor_free(c));
+ smartlist_free(entries);
+ }
}
return result;
}
diff --git a/src/or/test.c b/src/or/test.c
index e3e10763c5..f082221ba4 100644
--- a/src/or/test.c
+++ b/src/or/test.c
@@ -3414,7 +3414,7 @@ test_geoip(void)
geoip_note_client_seen(i, now-7200);
s = geoip_get_client_history(now+5*24*60*60);
test_assert(s);
- test_streq("ab=8,zz=16", s);
+ test_streq("zz=16,ab=8", s);
tor_free(s);
/* Now clear out all the zz observations. */