[tor-commits] [metrics-lib/master] Parse flag thresholds in bridge network statuses.
karsten at torproject.org
karsten at torproject.org
Thu Dec 10 18:58:35 UTC 2015
commit d5b32d86245a323e0e6b6fde0899d14557438490
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date: Sat Nov 21 20:46:08 2015 +0100
Parse flag thresholds in bridge network statuses.
Also parse the "ignoring-advertised-bws" flag threshold in votes that was
added while we were not looking.
Implements #17617.
---
CHANGELOG.md | 8 ++
.../torproject/descriptor/BridgeNetworkStatus.java | 47 ++++++
.../descriptor/RelayNetworkStatusVote.java | 6 +
.../descriptor/impl/BridgeNetworkStatusImpl.java | 102 +++++++++++++
.../impl/RelayNetworkStatusVoteImpl.java | 8 ++
.../descriptor/impl/BridgeNetworkStatusTest.java | 151 ++++++++++++++++++++
6 files changed, 322 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 437f2e6..d9eba21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# Changes in version 1.x.x - 201x-xx-xx
+
+ * Medium changes
+ - Parse flag thresholds in bridge network statuses, and parse the
+ "ignoring-advertised-bws" flag threshold in relay network status
+ votes.
+
+
# Changes in version 1.0.0 - 2015-12-05
* Major changes
diff --git a/src/org/torproject/descriptor/BridgeNetworkStatus.java b/src/org/torproject/descriptor/BridgeNetworkStatus.java
index 296cd22..1a28ebf 100644
--- a/src/org/torproject/descriptor/BridgeNetworkStatus.java
+++ b/src/org/torproject/descriptor/BridgeNetworkStatus.java
@@ -9,6 +9,53 @@ public interface BridgeNetworkStatus extends Descriptor {
/* Return the published time in milliseconds. */
public long getPublishedMillis();
+ /* Return the minimum uptime in seconds that this authority requires for
+ * assigning the Stable flag, or -1 if the authority doesn't report this
+ * value. */
+ public long getStableUptime();
+
+ /* Return the minimum MTBF (mean time between failure) that this
+ * authority requires for assigning the Stable flag, or -1 if the
+ * authority doesn't report this value. */
+ public long getStableMtbf();
+
+ /* Return the minimum bandwidth that this authority requires for
+ * assigning the Fast flag, or -1 if the authority doesn't report this
+ * value. */
+ public long getFastBandwidth();
+
+ /* Return the minimum WFU (weighted fractional uptime) in percent that
+ * this authority requires for assigning the Guard flag, or -1.0 if the
+ * authority doesn't report this value. */
+ public double getGuardWfu();
+
+ /* Return the minimum weighted time in seconds that this authority needs
+ * to know about a relay before assigning the Guard flag, or -1 if the
+ * authority doesn't report this information. */
+ public long getGuardTk();
+
+ /* Return the minimum bandwidth that this authority requires for
+ * assigning the Guard flag if exits can be guards, or -1 if the
+ * authority doesn't report this value. */
+ public long getGuardBandwidthIncludingExits();
+
+ /* Return the minimum bandwidth that this authority requires for
+ * assigning the Guard flag if exits can not be guards, or -1 if the
+ * authority doesn't report this value. */
+ public long getGuardBandwidthExcludingExits();
+
+ /* Return 1 if the authority has measured enough MTBF info to use the
+ * MTBF requirement instead of the uptime requirement for assigning the
+ * Stable flag, 0 if not, or -1 if the authority doesn't report this
+ * information. */
+ public int getEnoughMtbfInfo();
+
+ /* Return 1 if the authority has enough measured bandwidths that it'll
+ * ignore the advertised bandwidth claims of routers without measured
+ * bandwidth, 0 if not, or -1 if the authority doesn't report this
+ * information. */
+ public int getIgnoringAdvertisedBws();
+
/* Return status entries, one for each contained bridge. */
public SortedMap<String, NetworkStatusEntry> getStatusEntries();
}
diff --git a/src/org/torproject/descriptor/RelayNetworkStatusVote.java b/src/org/torproject/descriptor/RelayNetworkStatusVote.java
index aeab268..bf4ea6b 100644
--- a/src/org/torproject/descriptor/RelayNetworkStatusVote.java
+++ b/src/org/torproject/descriptor/RelayNetworkStatusVote.java
@@ -85,6 +85,12 @@ public interface RelayNetworkStatusVote extends Descriptor {
* information. */
public int getEnoughMtbfInfo();
+ /* Return 1 if the authority has enough measured bandwidths that it'll
+ * ignore the advertised bandwidth claims of routers without measured
+ * bandwidth, 0 if not, or -1 if the authority doesn't report this
+ * information. */
+ public int getIgnoringAdvertisedBws();
+
/* Return consensus parameters. */
public SortedMap<String, Integer> getConsensusParams();
diff --git a/src/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java b/src/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
index 5935c86..bddf5ab 100644
--- a/src/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
+++ b/src/org/torproject/descriptor/impl/BridgeNetworkStatusImpl.java
@@ -6,7 +6,9 @@ import org.torproject.descriptor.DescriptorParseException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Map;
import java.util.Scanner;
+import java.util.SortedMap;
import java.util.TimeZone;
import org.torproject.descriptor.BridgeNetworkStatus;
@@ -52,6 +54,20 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
protected void parseHeader(byte[] headerBytes)
throws DescriptorParseException {
+ /* Initialize flag-thresholds values here for the case that the status
+ * doesn't contain those values. Initializing them in the constructor
+ * or when declaring variables wouldn't work, because those parts are
+ * evaluated later and would overwrite everything we parse here. */
+ this.stableUptime = -1L;
+ this.stableMtbf = -1L;
+ this.fastBandwidth = -1L;
+ this.guardWfu = -1.0;
+ this.guardTk = -1L;
+ this.guardBandwidthIncludingExits = -1L;
+ this.guardBandwidthExcludingExits = -1L;
+ this.enoughMtbfInfo = -1;
+ this.ignoringAdvertisedBws = -1;
+
Scanner s = new Scanner(new String(headerBytes)).useDelimiter("\n");
while (s.hasNext()) {
String line = s.next();
@@ -59,6 +75,8 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
String keyword = parts[0];
if (keyword.equals("published")) {
this.parsePublishedLine(line, parts);
+ } else if (keyword.equals("flag-thresholds")) {
+ this.parseFlagThresholdsLine(line, parts);
} else if (this.failUnrecognizedDescriptorLines) {
throw new DescriptorParseException("Unrecognized line '" + line
+ "' in bridge network status.");
@@ -77,6 +95,45 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
1, 2);
}
+ private void parseFlagThresholdsLine(String line, String[] parts)
+ throws DescriptorParseException {
+ if (parts.length < 2) {
+ throw new DescriptorParseException("No flag thresholds in line '"
+ + line + "'.");
+ }
+ SortedMap<String, String> flagThresholds =
+ ParseHelper.parseKeyValueStringPairs(line, parts, 1, "=");
+ try {
+ for (Map.Entry<String, String> e : flagThresholds.entrySet()) {
+ if (e.getKey().equals("stable-uptime")) {
+ this.stableUptime = Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("stable-mtbf")) {
+ this.stableMtbf = Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("fast-speed")) {
+ this.fastBandwidth = Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("guard-wfu")) {
+ this.guardWfu = Double.parseDouble(e.getValue().
+ replaceAll("%", ""));
+ } else if (e.getKey().equals("guard-tk")) {
+ this.guardTk = Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("guard-bw-inc-exits")) {
+ this.guardBandwidthIncludingExits =
+ Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("guard-bw-exc-exits")) {
+ this.guardBandwidthExcludingExits =
+ Long.parseLong(e.getValue());
+ } else if (e.getKey().equals("enough-mtbf")) {
+ this.enoughMtbfInfo = Integer.parseInt(e.getValue());
+ } else if (e.getKey().equals("ignoring-advertised-bws")) {
+ this.ignoringAdvertisedBws = Integer.parseInt(e.getValue());
+ }
+ }
+ } catch (NumberFormatException ex) {
+ throw new DescriptorParseException("Illegal value in line '"
+ + line + "'.");
+ }
+ }
+
protected void parseDirSource(byte[] dirSourceBytes)
throws DescriptorParseException {
throw new DescriptorParseException("No directory source expected in "
@@ -99,5 +156,50 @@ public class BridgeNetworkStatusImpl extends NetworkStatusImpl
public long getPublishedMillis() {
return this.publishedMillis;
}
+
+ private long stableUptime;
+ public long getStableUptime() {
+ return this.stableUptime;
+ }
+
+ private long stableMtbf;
+ public long getStableMtbf() {
+ return this.stableMtbf;
+ }
+
+ private long fastBandwidth;
+ public long getFastBandwidth() {
+ return this.fastBandwidth;
+ }
+
+ private double guardWfu;
+ public double getGuardWfu() {
+ return this.guardWfu;
+ }
+
+ private long guardTk;
+ public long getGuardTk() {
+ return this.guardTk;
+ }
+
+ private long guardBandwidthIncludingExits;
+ public long getGuardBandwidthIncludingExits() {
+ return this.guardBandwidthIncludingExits;
+ }
+
+ private long guardBandwidthExcludingExits;
+ public long getGuardBandwidthExcludingExits() {
+ return this.guardBandwidthExcludingExits;
+ }
+
+ private int enoughMtbfInfo;
+ public int getEnoughMtbfInfo() {
+ return this.enoughMtbfInfo;
+ }
+
+ private int ignoringAdvertisedBws;
+ public int getIgnoringAdvertisedBws() {
+ return this.ignoringAdvertisedBws;
+ }
}
diff --git a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
index f43733e..410c2f1 100644
--- a/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
+++ b/src/org/torproject/descriptor/impl/RelayNetworkStatusVoteImpl.java
@@ -72,6 +72,7 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
this.guardBandwidthIncludingExits = -1L;
this.guardBandwidthExcludingExits = -1L;
this.enoughMtbfInfo = -1;
+ this.ignoringAdvertisedBws = -1;
Scanner s = new Scanner(new String(headerBytes)).useDelimiter("\n");
boolean skipCrypto = false; /* TODO Parse crypto parts. */
@@ -276,6 +277,8 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
Long.parseLong(e.getValue());
} else if (e.getKey().equals("enough-mtbf")) {
this.enoughMtbfInfo = Integer.parseInt(e.getValue());
+ } else if (e.getKey().equals("ignoring-advertised-bws")) {
+ this.ignoringAdvertisedBws = Integer.parseInt(e.getValue());
}
}
} catch (NumberFormatException ex) {
@@ -542,6 +545,11 @@ public class RelayNetworkStatusVoteImpl extends NetworkStatusImpl
return this.enoughMtbfInfo;
}
+ private int ignoringAdvertisedBws;
+ public int getIgnoringAdvertisedBws() {
+ return this.ignoringAdvertisedBws;
+ }
+
private SortedMap<String, Integer> consensusParams;
public SortedMap<String, Integer> getConsensusParams() {
return this.consensusParams == null ? null:
diff --git a/test/org/torproject/descriptor/impl/BridgeNetworkStatusTest.java b/test/org/torproject/descriptor/impl/BridgeNetworkStatusTest.java
new file mode 100644
index 0000000..c8e95bf
--- /dev/null
+++ b/test/org/torproject/descriptor/impl/BridgeNetworkStatusTest.java
@@ -0,0 +1,151 @@
+/* Copyright 2015 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.descriptor.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.torproject.descriptor.BridgeNetworkStatus;
+import org.torproject.descriptor.DescriptorParseException;
+
+/* Test parsing of bridge network statuses. Some of the parsing code is
+ * already tested in the consensus/vote-parsing tests. */
+public class BridgeNetworkStatusTest {
+
+ /* Helper class to build a bridge network status based on default data
+ * and modifications requested by test methods. */
+ private static class StatusBuilder {
+ private String fileName = "20151121-173936-"
+ + "4A0CCD2DDC7995083D73F5D667100C8A5831F16D";
+ private static BridgeNetworkStatus
+ createWithFileName(String fileName)
+ throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ sb.fileName = fileName;
+ return new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName,
+ true);
+ }
+ private String publishedLine = "published 2015-11-21 17:39:36";
+ private static BridgeNetworkStatus
+ createWithPublishedLine(String line)
+ throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ sb.publishedLine = line;
+ return new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName,
+ true);
+ }
+ private String flagThresholdsLine = "flag-thresholds "
+ + "stable-uptime=3105080 stable-mtbf=2450615 fast-speed=55000 "
+ + "guard-wfu=98.000% guard-tk=691200 guard-bw-inc-exits=337000 "
+ + "guard-bw-exc-exits=339000 enough-mtbf=1 "
+ + "ignoring-advertised-bws=0";
+ private static BridgeNetworkStatus
+ createWithFlagThresholdsLine(String line)
+ throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ sb.flagThresholdsLine = line;
+ return new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName,
+ true);
+ }
+ private List<String> statusEntries = new ArrayList<String>();
+ private String unrecognizedHeaderLine = null;
+ protected static BridgeNetworkStatus
+ createWithUnrecognizedHeaderLine(String line,
+ boolean failUnrecognizedDescriptorLines)
+ throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ sb.unrecognizedHeaderLine = line;
+ return new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName,
+ failUnrecognizedDescriptorLines);
+ }
+ private String unrecognizedStatusEntryLine = null;
+ protected static BridgeNetworkStatus
+ createWithUnrecognizedStatusEntryLine(String line,
+ boolean failUnrecognizedDescriptorLines)
+ throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ sb.unrecognizedStatusEntryLine = line;
+ return new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName,
+ failUnrecognizedDescriptorLines);
+ }
+
+ private StatusBuilder() {
+ this.statusEntries.add("r Unnamed ABk0wg4j6BLCdZKleVtmNrfzJGI "
+ + "bh7gVU1Cz6+JG+7j4qGsF4prDi8 2015-11-21 15:46:25 "
+ + "10.153.163.200 443 0\ns Fast Running Stable Valid\n"
+ + "w Bandwidth=264\np reject 1-65535");
+ }
+ private byte[] buildStatus() {
+ StringBuilder sb = new StringBuilder();
+ this.appendHeader(sb);
+ this.appendStatusEntries(sb);
+ return sb.toString().getBytes();
+ }
+ private void appendHeader(StringBuilder sb) {
+ if (this.publishedLine != null) {
+ sb.append(this.publishedLine + "\n");
+ }
+ if (this.flagThresholdsLine != null) {
+ sb.append(this.flagThresholdsLine + "\n");
+ }
+ if (this.unrecognizedHeaderLine != null) {
+ sb.append(this.unrecognizedHeaderLine + "\n");
+ }
+ }
+ private void appendStatusEntries(StringBuilder sb) {
+ for (String statusEntry : this.statusEntries) {
+ sb.append(statusEntry + "\n");
+ }
+ if (this.unrecognizedStatusEntryLine != null) {
+ sb.append(this.unrecognizedStatusEntryLine + "\n");
+ }
+ }
+ }
+
+ @Test()
+ public void testSampleStatus() throws DescriptorParseException {
+ StatusBuilder sb = new StatusBuilder();
+ BridgeNetworkStatus status =
+ new BridgeNetworkStatusImpl(sb.buildStatus(), sb.fileName, true);
+ assertEquals(1448127576000L, status.getPublishedMillis());
+ assertEquals(3105080L, status.getStableUptime());
+ assertEquals(2450615L, status.getStableMtbf());
+ assertEquals(55000L, status.getFastBandwidth());
+ assertEquals(98.0, status.getGuardWfu(), 0.001);
+ assertEquals(691200L, status.getGuardTk());
+ assertEquals(337000L, status.getGuardBandwidthIncludingExits());
+ assertEquals(339000L, status.getGuardBandwidthExcludingExits());
+ assertEquals(1, status.getEnoughMtbfInfo());
+ assertEquals(0, status.getIgnoringAdvertisedBws());
+ assertEquals(264, status.getStatusEntries().get(
+ "001934C20E23E812C27592A5795B6636B7F32462").getBandwidth());
+ assertTrue(status.getUnrecognizedLines().isEmpty());
+ }
+
+ @Test()
+ public void testPublishedNoLine() throws DescriptorParseException {
+ BridgeNetworkStatus status =
+ StatusBuilder.createWithPublishedLine(null);
+ assertEquals(1448127576000L, status.getPublishedMillis());
+ }
+
+ @Test()
+ public void testFlagThresholdsNoLine() throws DescriptorParseException {
+ BridgeNetworkStatus status =
+ StatusBuilder.createWithFlagThresholdsLine(null);
+ assertEquals(-1L, status.getStableUptime());
+ assertEquals(-1L, status.getStableMtbf());
+ assertEquals(-1L, status.getFastBandwidth());
+ assertEquals(-1.0, status.getGuardWfu(), 0.001);
+ assertEquals(-1L, status.getGuardTk());
+ assertEquals(-1L, status.getGuardBandwidthIncludingExits());
+ assertEquals(-1L, status.getGuardBandwidthExcludingExits());
+ assertEquals(-1, status.getEnoughMtbfInfo());
+ assertEquals(-1, status.getIgnoringAdvertisedBws());
+ }
+}
+
More information about the tor-commits
mailing list