|
@@ -516,6 +516,13 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
* is the same flag as votes[j]->known_flags[b]. */
|
|
|
int *named_flag; /* Index of the flag "Named" for votes[j] */
|
|
|
int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */
|
|
|
+ int chosen_named_idx, chosen_unnamed_idx;
|
|
|
+
|
|
|
+ strmap_t *name_to_id_map = strmap_new();
|
|
|
+ char conflict[DIGEST_LEN];
|
|
|
+ char unknown[DIGEST_LEN];
|
|
|
+ memset(conflict, 0, sizeof(conflict));
|
|
|
+ memset(unknown, 0xff, sizeof(conflict));
|
|
|
|
|
|
index = tor_malloc_zero(sizeof(int)*smartlist_len(votes));
|
|
|
size = tor_malloc_zero(sizeof(int)*smartlist_len(votes));
|
|
@@ -526,6 +533,10 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
unnamed_flag = tor_malloc_zero(sizeof(int*) * smartlist_len(votes));
|
|
|
for (i = 0; i < smartlist_len(votes); ++i)
|
|
|
unnamed_flag[i] = named_flag[i] = -1;
|
|
|
+ chosen_named_idx = smartlist_string_pos(flags, "Named");
|
|
|
+ chosen_unnamed_idx = smartlist_string_pos(flags, "Unnamed");
|
|
|
+
|
|
|
+ /* Build the flag index. */
|
|
|
SMARTLIST_FOREACH(votes, networkstatus_vote_t *, v,
|
|
|
{
|
|
|
flag_map[v_sl_idx] = tor_malloc_zero(
|
|
@@ -538,13 +549,65 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
++n_flag_voters[p];
|
|
|
if (!strcmp(fl, "Named"))
|
|
|
named_flag[v_sl_idx] = fl_sl_idx;
|
|
|
- if (!strcmp(fl, "Named"))
|
|
|
+ if (!strcmp(fl, "Unnamed"))
|
|
|
unnamed_flag[v_sl_idx] = fl_sl_idx;
|
|
|
});
|
|
|
n_voter_flags[v_sl_idx] = smartlist_len(v->known_flags);
|
|
|
size[v_sl_idx] = smartlist_len(v->routerstatus_list);
|
|
|
});
|
|
|
|
|
|
+ /* Named and Unnamed get treated specially */
|
|
|
+ if (consensus_method >= 2) {
|
|
|
+ SMARTLIST_FOREACH(votes, networkstatus_vote_t *, v,
|
|
|
+ {
|
|
|
+ uint64_t nf;
|
|
|
+ if (named_flag[v_sl_idx]<0)
|
|
|
+ continue;
|
|
|
+ nf = U64_LITERAL(1) << named_flag[v_sl_idx];
|
|
|
+ SMARTLIST_FOREACH(v->routerstatus_list, vote_routerstatus_t *, rs,
|
|
|
+ {
|
|
|
+ if ((rs->flags & nf) != 0) {
|
|
|
+ const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname);
|
|
|
+ if (!d) {
|
|
|
+ /* We have no name officially mapped to this digest. */
|
|
|
+ strmap_set_lc(name_to_id_map, rs->status.nickname,
|
|
|
+ rs->status.identity_digest);
|
|
|
+ } else if (d != conflict &&
|
|
|
+ memcmp(d, rs->status.identity_digest, DIGEST_LEN)) {
|
|
|
+ /* Authorities disagree about this nickname. */
|
|
|
+ strmap_set_lc(name_to_id_map, rs->status.nickname, conflict);
|
|
|
+ } else {
|
|
|
+ /* It's already a conflict, or it's already this ID. */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ SMARTLIST_FOREACH(votes, networkstatus_vote_t *, v,
|
|
|
+ {
|
|
|
+ uint64_t uf;
|
|
|
+ if (unnamed_flag[v_sl_idx]<0)
|
|
|
+ continue;
|
|
|
+ uf = U64_LITERAL(1) << unnamed_flag[v_sl_idx];
|
|
|
+ SMARTLIST_FOREACH(v->routerstatus_list, vote_routerstatus_t *, rs,
|
|
|
+ {
|
|
|
+ if ((rs->flags & uf) != 0) {
|
|
|
+ const char *d = strmap_get_lc(name_to_id_map, rs->status.nickname);
|
|
|
+ if (d == conflict || d == unknown) {
|
|
|
+ /* Leave it alone; we know what it is. */
|
|
|
+ } else if (!d) {
|
|
|
+ /* We have no name officially mapped to this digest. */
|
|
|
+ strmap_set_lc(name_to_id_map, rs->status.nickname, unknown);
|
|
|
+ } else if (!memcmp(d, rs->status.identity_digest, DIGEST_LEN)) {
|
|
|
+ /* Authorities disagree about this nickname. */
|
|
|
+ strmap_set_lc(name_to_id_map, rs->status.nickname, conflict);
|
|
|
+ } else {
|
|
|
+ /* It's mapped to a different name. */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
/* Now go through all the votes */
|
|
|
flag_counts = tor_malloc(sizeof(int) * smartlist_len(flags));
|
|
|
while (1) {
|
|
@@ -553,6 +616,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
const char *lowest_id = NULL;
|
|
|
const char *chosen_version;
|
|
|
const char *chosen_name = NULL;
|
|
|
+ int is_named = 0, is_unnamed = 0;
|
|
|
int naming_conflict = 0;
|
|
|
int n_listing = 0;
|
|
|
int i;
|
|
@@ -605,7 +669,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
}
|
|
|
chosen_name = rs->status.nickname;
|
|
|
}
|
|
|
-
|
|
|
});
|
|
|
|
|
|
/* We don't include this router at all unless more than half of
|
|
@@ -632,16 +695,33 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
strlcpy(rs_out.nickname, rs->status.nickname, sizeof(rs_out.nickname));
|
|
|
}
|
|
|
|
|
|
+ if (consensus_method == 1) {
|
|
|
+ is_named = chosen_named_idx >= 0 &&
|
|
|
+ (!naming_conflict && flag_counts[chosen_named_idx]);
|
|
|
+ } else {
|
|
|
+ const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname);
|
|
|
+ if (!d) {
|
|
|
+ is_named = is_unnamed = 0;
|
|
|
+ } else if (!memcmp(d, lowest_id, DIGEST_LEN)) {
|
|
|
+ is_named = 1; is_unnamed = 0;
|
|
|
+ } else {
|
|
|
+ is_named = 0; is_unnamed = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Set the flags. */
|
|
|
smartlist_add(chosen_flags, (char*)"s"); /* for the start of the line. */
|
|
|
SMARTLIST_FOREACH(flags, const char *, fl,
|
|
|
{
|
|
|
- if (strcmp(fl, "Named")) {
|
|
|
- if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2)
|
|
|
+ if (!strcmp(fl, "Named")) {
|
|
|
+ if (is_named)
|
|
|
+ smartlist_add(chosen_flags, (char*)fl);
|
|
|
+ } else if (!strcmp(fl, "Unnamed") && consensus_method >= 2) {
|
|
|
+ if (is_unnamed)
|
|
|
smartlist_add(chosen_flags, (char*)fl);
|
|
|
} else {
|
|
|
- if (!naming_conflict && flag_counts[fl_sl_idx])
|
|
|
- smartlist_add(chosen_flags, (char*)"Named");
|
|
|
+ if (flag_counts[fl_sl_idx] > n_flag_voters[fl_sl_idx]/2)
|
|
|
+ smartlist_add(chosen_flags, (char*)fl);
|
|
|
}
|
|
|
});
|
|
|
|
|
@@ -680,6 +760,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
|
|
|
tor_free(flag_counts);
|
|
|
tor_free(named_flag);
|
|
|
tor_free(unnamed_flag);
|
|
|
+ strmap_free(name_to_id_map, NULL);
|
|
|
smartlist_free(matching_descs);
|
|
|
smartlist_free(chosen_flags);
|
|
|
smartlist_free(versions);
|