commit 86fae9e607668a1768041ac6cf19ee0b41cb7aea
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Thu Jul 19 22:32:28 2012 +0200
Add path selection probabilities to details files.
---
src/org/torproject/onionoo/CurrentNodes.java | 7 +
src/org/torproject/onionoo/DetailDataWriter.java | 137 ++++++++++++++++++++++
src/org/torproject/onionoo/Main.java | 1 +
src/org/torproject/onionoo/Node.java | 36 ++++++
web/index.html | 48 ++++++++
5 files changed, 229 insertions(+), 0 deletions(-)
diff --git a/src/org/torproject/onionoo/CurrentNodes.java b/src/org/torproject/onionoo/CurrentNodes.java
index 7c4bec8..7ef1473 100644
--- a/src/org/torproject/onionoo/CurrentNodes.java
+++ b/src/org/torproject/onionoo/CurrentNodes.java
@@ -250,6 +250,10 @@ public class CurrentNodes {
}
}
+ SortedMap<String, Integer> lastBandwidthWeights = null;
+ public SortedMap<String, Integer> getLastBandwidthWeights() {
+ return this.lastBandwidthWeights;
+ }
private void updateRelayNetworkStatusConsensus(
RelayNetworkStatusConsensus consensus) {
long validAfterMillis = consensus.getValidAfterMillis();
@@ -268,6 +272,9 @@ public class CurrentNodes {
null, validAfterMillis, orPort, dirPort, relayFlags,
consensusWeight, null, null, -1L);
}
+ if (this.lastValidAfterMillis == validAfterMillis) {
+ this.lastBandwidthWeights = consensus.getBandwidthWeights();
+ }
}
public void addRelay(String nickname, String fingerprint,
diff --git a/src/org/torproject/onionoo/DetailDataWriter.java b/src/org/torproject/onionoo/DetailDataWriter.java
index 155c4eb..2961de9 100644
--- a/src/org/torproject/onionoo/DetailDataWriter.java
+++ b/src/org/torproject/onionoo/DetailDataWriter.java
@@ -13,6 +13,7 @@ import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -194,6 +195,115 @@ public class DetailDataWriter {
}
}
+ public void calculatePathSelectionProbabilities(
+ SortedMap<String, Integer> bandwidthWeights) {
+ boolean consensusContainsBandwidthWeights = false;
+ double wgg = 0.0, wgd = 0.0, wmg = 0.0, wmm = 0.0, wme = 0.0,
+ wmd = 0.0, wee = 0.0, wed = 0.0;
+ if (bandwidthWeights != null) {
+ SortedSet<String> weightKeys = new TreeSet<String>(Arrays.asList(
+ "Wgg,Wgd,Wmg,Wmm,Wme,Wmd,Wee,Wed".split(",")));
+ weightKeys.removeAll(bandwidthWeights.keySet());
+ if (weightKeys.isEmpty()) {
+ consensusContainsBandwidthWeights = true;
+ wgg = ((double) bandwidthWeights.get("Wgg")) / 10000.0;
+ wgd = ((double) bandwidthWeights.get("Wgd")) / 10000.0;
+ wmg = ((double) bandwidthWeights.get("Wmg")) / 10000.0;
+ wmm = ((double) bandwidthWeights.get("Wmm")) / 10000.0;
+ wme = ((double) bandwidthWeights.get("Wme")) / 10000.0;
+ wmd = ((double) bandwidthWeights.get("Wmd")) / 10000.0;
+ wee = ((double) bandwidthWeights.get("Wee")) / 10000.0;
+ wed = ((double) bandwidthWeights.get("Wed")) / 10000.0;
+ }
+ }
+ SortedMap<String, Double>
+ advertisedBandwidths = new TreeMap<String, Double>(),
+ consensusWeights = new TreeMap<String, Double>(),
+ guardWeights = new TreeMap<String, Double>(),
+ middleWeights = new TreeMap<String, Double>(),
+ exitWeights = new TreeMap<String, Double>();
+ double totalAdvertisedBandwidth = 0.0;
+ double totalConsensusWeight = 0.0;
+ double totalGuardWeight = 0.0;
+ double totalMiddleWeight = 0.0;
+ double totalExitWeight = 0.0;
+ for (Map.Entry<String, Node> e : this.relays.entrySet()) {
+ String fingerprint = e.getKey();
+ Node relay = e.getValue();
+ if (!relay.getRunning()) {
+ continue;
+ }
+ boolean isExit = relay.getRelayFlags().contains("Exit") &&
+ !relay.getRelayFlags().contains("BadExit");
+ boolean isGuard = relay.getRelayFlags().contains("Guard");
+ if (this.relayServerDescriptors.containsKey(fingerprint)) {
+ ServerDescriptor serverDescriptor =
+ this.relayServerDescriptors.get(fingerprint);
+ double advertisedBandwidth = (double) Math.min(Math.min(
+ serverDescriptor.getBandwidthBurst(),
+ serverDescriptor.getBandwidthObserved()),
+ serverDescriptor.getBandwidthRate());
+ advertisedBandwidths.put(fingerprint, advertisedBandwidth);
+ totalAdvertisedBandwidth += advertisedBandwidth;
+ }
+ double consensusWeight = (double) relay.getConsensusWeight();
+ consensusWeights.put(fingerprint, consensusWeight);
+ totalConsensusWeight += consensusWeight;
+ if (consensusContainsBandwidthWeights) {
+ double guardWeight = consensusWeight,
+ middleWeight = consensusWeight,
+ exitWeight = consensusWeight;
+ if (isGuard && isExit) {
+ guardWeight *= wgd;
+ middleWeight *= wmd;
+ exitWeight *= wed;
+ } else if (isGuard) {
+ guardWeight *= wgg;
+ middleWeight *= wmg;
+ exitWeight = 0.0;
+ } else if (isExit) {
+ guardWeight = 0.0;
+ middleWeight *= wme;
+ exitWeight *= wee;
+ } else {
+ guardWeight = 0.0;
+ middleWeight *= wmm;
+ exitWeight = 0.0;
+ }
+ guardWeights.put(fingerprint, guardWeight);
+ middleWeights.put(fingerprint, middleWeight);
+ exitWeights.put(fingerprint, exitWeight);
+ totalGuardWeight += guardWeight;
+ totalMiddleWeight += middleWeight;
+ totalExitWeight += exitWeight;
+ }
+ }
+ for (Map.Entry<String, Node> e : this.relays.entrySet()) {
+ String fingerprint = e.getKey();
+ Node relay = e.getValue();
+ if (advertisedBandwidths.containsKey(fingerprint)) {
+ relay.setAdvertisedBandwidthFraction(advertisedBandwidths.get(
+ fingerprint) / totalAdvertisedBandwidth);
+ }
+ if (consensusWeights.containsKey(fingerprint)) {
+ relay.setConsensusWeightFraction(consensusWeights.get(fingerprint)
+ / totalConsensusWeight);
+ }
+ if (guardWeights.containsKey(fingerprint)) {
+ relay.setGuardProbability(guardWeights.get(fingerprint)
+ / totalGuardWeight);
+ }
+ if (middleWeights.containsKey(fingerprint)) {
+ relay.setMiddleProbability(middleWeights.get(fingerprint)
+ / totalMiddleWeight);
+ }
+ if (exitWeights.containsKey(fingerprint)) {
+ relay.setExitProbability(exitWeights.get(fingerprint)
+ / totalExitWeight);
+ }
+ }
+ }
+
private long now = System.currentTimeMillis();
private Map<String, Set<ExitListEntry>> exitListEntries =
new HashMap<String, Set<ExitListEntry>>();
@@ -444,6 +554,12 @@ public class DetailDataWriter {
String aSName = entry.getASName();
long consensusWeight = entry.getConsensusWeight();
String hostName = entry.getHostName();
+ double advertisedBandwidthFraction =
+ entry.getAdvertisedBandwidthFraction();
+ double consensusWeightFraction = entry.getConsensusWeightFraction();
+ double guardProbability = entry.getGuardProbability();
+ double middleProbability = entry.getMiddleProbability();
+ double exitProbability = entry.getExitProbability();
StringBuilder sb = new StringBuilder();
sb.append("{\"version\":1,\n"
+ "\"nickname\":\"" + nickname + "\",\n"
@@ -501,6 +617,27 @@ public class DetailDataWriter {
sb.append(",\n\"host_name\":\""
+ escapeJSON(hostName) + "\"");
}
+ if (advertisedBandwidthFraction >= 0.0) {
+ sb.append(String.format(
+ ",\n\"advertised_bandwidth_fraction\":%.9f",
+ advertisedBandwidthFraction));
+ }
+ if (consensusWeightFraction >= 0.0) {
+ sb.append(String.format(",\n\"consensus_weight_fraction\":%.9f",
+ consensusWeightFraction));
+ }
+ if (guardProbability >= 0.0) {
+ sb.append(String.format(",\n\"guard_probability\":%.9f",
+ guardProbability));
+ }
+ if (middleProbability >= 0.0) {
+ sb.append(String.format(",\n\"middle_probability\":%.9f",
+ middleProbability));
+ }
+ if (exitProbability >= 0.0) {
+ sb.append(String.format(",\n\"exit_probability\":%.9f",
+ exitProbability));
+ }
/* Add exit addresses if at least one of them is distinct from the
* onion-routing addresses. */
diff --git a/src/org/torproject/onionoo/Main.java b/src/org/torproject/onionoo/Main.java
index 5cac8de..175176c 100644
--- a/src/org/torproject/onionoo/Main.java
+++ b/src/org/torproject/onionoo/Main.java
@@ -24,6 +24,7 @@ public class Main {
ddw.setCurrentBridges(cn.getCurrentBridges());
ddw.startReverseDomainNameLookups();
ddw.readRelayServerDescriptors();
+ ddw.calculatePathSelectionProbabilities(cn.getLastBandwidthWeights());
ddw.readExitLists();
ddw.readBridgeServerDescriptors();
ddw.readBridgePoolAssignments();
diff --git a/src/org/torproject/onionoo/Node.java b/src/org/torproject/onionoo/Node.java
index 88ca71c..61a26ed 100644
--- a/src/org/torproject/onionoo/Node.java
+++ b/src/org/torproject/onionoo/Node.java
@@ -35,6 +35,11 @@ public class Node {
private boolean running;
private String hostName;
private long lastRdnsLookup = -1L;
+ private double advertisedBandwidthFraction = -1.0;
+ private double consensusWeightFraction = -1.0;
+ private double guardProbability = -1.0;
+ private double middleProbability = -1.0;
+ private double exitProbability = -1.0;
public Node(String nickname, String fingerprint, String address,
SortedSet<String> orAddressesAndPorts,
SortedSet<String> exitAddresses, long lastSeenMillis, int orPort,
@@ -194,5 +199,36 @@ public class Node {
public long getLastRdnsLookup() {
return this.lastRdnsLookup;
}
+ public void setAdvertisedBandwidthFraction(
+ double advertisedBandwidthFraction) {
+ this.advertisedBandwidthFraction = advertisedBandwidthFraction;
+ }
+ public double getAdvertisedBandwidthFraction() {
+ return this.advertisedBandwidthFraction;
+ }
+ public void setConsensusWeightFraction(double consensusWeightFraction) {
+ this.consensusWeightFraction = consensusWeightFraction;
+ }
+ public double getConsensusWeightFraction() {
+ return this.consensusWeightFraction;
+ }
+ public void setGuardProbability(double guardProbability) {
+ this.guardProbability = guardProbability;
+ }
+ public double getGuardProbability() {
+ return this.guardProbability;
+ }
+ public void setMiddleProbability(double middleProbability) {
+ this.middleProbability = middleProbability;
+ }
+ public double getMiddleProbability() {
+ return this.middleProbability;
+ }
+ public void setExitProbability(double exitProbability) {
+ this.exitProbability = exitProbability;
+ }
+ public double getExitProbability() {
+ return this.exitProbability;
+ }
}
diff --git a/web/index.html b/web/index.html
index 5788bf9..0578843 100755
--- a/web/index.html
+++ b/web/index.html
@@ -276,6 +276,54 @@ same family as this relay.
Optional field.
Omitted if empty or if descriptor containing this information cannot be
found.</li>
+<li><b><font color="blue">"advertised_bandwidth_fraction":</font></b>
+Relative advertised bandwidth of this relay compared to the total
+advertised bandwidth in the network.
+If there were no bandwidth authorities, this fraction would be a very
+rough approximation of the probability of this relay to be selected by
+clients.
+Optional field.
+Omitted if the relay is not running, or router descriptor containing this
+information cannot be found.
+<font color="blue">Added field on July 19, 2012.</font></li>
+<li><b><font color="blue">"consensus_weight_fraction":</font></b>
+Fraction of this relay's consensus weight compared to the sum of all
+consensus weights in the network.
+This fraction is a very rough approximation of the probability of this
+relay to be selected by clients.
+Optional field.
+Omitted if the relay is not running.
+<font color="blue">Added field on July 19, 2012.</font></li>
+<li><b><font color="blue">"guard_probability":</font></b>
+Probability of this relay to be selected for the guard position.
+This probability is calculated based on consensus weights, relay flags,
+and bandwidth weights in the consensus.
+Path selection depends on more factors, so that this probability can only
+be an approximation.
+Optional field.
+Omitted if the relay is not running, or the consensus does not contain
+bandwidth weights.
+<font color="blue">Added field on July 19, 2012.</font></li>
+<li><b><font color="blue">"middle_probability":</font></b>
+Probability of this relay to be selected for the middle position.
+This probability is calculated based on consensus weights, relay flags,
+and bandwidth weights in the consensus.
+Path selection depends on more factors, so that this probability can only
+be an approximation.
+Optional field.
+Omitted if the relay is not running, or the consensus does not contain
+bandwidth weights.
+<font color="blue">Added field on July 19, 2012.</font></li>
+<li><b><font color="blue">"exit_probability":</font></b>
+Probability of this relay to be selected for the exit position.
+This probability is calculated based on consensus weights, relay flags,
+and bandwidth weights in the consensus.
+Path selection depends on more factors, so that this probability can only
+be an approximation.
+Optional field.
+Omitted if the relay is not running, or the consensus does not contain
+bandwidth weights.
+<font color="blue">Added field on July 19, 2012.</font></li>
</ul>
</li>
<li><b>"bridges_published":</b> UTC timestamp (YYYY-MM-DD hh:mm:ss) when