[tor-commits] [onionoo/master] Add path selection probabilities to details files.

karsten at torproject.org karsten at torproject.org
Fri Jul 20 07:42:04 UTC 2012


commit 86fae9e607668a1768041ac6cf19ee0b41cb7aea
Author: Karsten Loesing <karsten.loesing at 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



More information about the tor-commits mailing list