[tor-commits] [metrics-lib/release] Parse "padding-counts" lines in extra-info descriptors.

karsten at torproject.org karsten at torproject.org
Wed May 17 11:45:58 UTC 2017


commit 75844d046cf6df8162599ce4de4794cc2de09af0
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Thu May 11 16:21:17 2017 +0200

    Parse "padding-counts" lines in extra-info descriptors.
    
    Implements #22217.
---
 CHANGELOG.md                                       |  1 +
 .../torproject/descriptor/ExtraInfoDescriptor.java | 24 +++++++
 .../descriptor/impl/ExtraInfoDescriptorImpl.java   | 36 +++++++++++
 .../torproject/descriptor/impl/ParseHelper.java    | 33 ++++++++++
 .../impl/ExtraInfoDescriptorImplTest.java          | 75 ++++++++++++++++++++++
 5 files changed, 169 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9322ecd..36aa082 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
      DescriptorParser and DescriptorReader and refer to
      getUnrecognizedLines() in Descriptor if applications really need
      to fail descriptors containing unrecognized lines.
+   - Parse "padding-counts" lines in extra-info descriptors.
 
  * Minor changes
    - Accept extra arguments in statistics-related extra-info
diff --git a/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java b/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java
index bb1cbe6..04a46d4 100644
--- a/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java
+++ b/src/main/java/org/torproject/descriptor/ExtraInfoDescriptor.java
@@ -650,6 +650,30 @@ public interface ExtraInfoDescriptor extends Descriptor {
   public Map<String, Double> getHidservDirOnionsSeenParameters();
 
   /**
+   * Return the time in milliseconds since the epoch when the included
+   * padding-counts statistics ended, or -1 if no such statistics are included.
+   *
+   * @since 1.7.0
+   */
+  public long getPaddingCountsStatsEndMillis();
+
+  /**
+   * Return the interval length of the included padding-counts statistics in
+   * seconds, or -1 if no such statistics are included.
+   *
+   * @since 1.7.0
+   */
+  public long getPaddingCountsStatsIntervalLength();
+
+  /**
+   * Return padding-counts statistics, or <code>null</code> if no such
+   * statistics are included.
+   *
+   * @since 1.7.0
+   */
+  public Map<String, Long> getPaddingCounts();
+
+  /**
    * Return the RSA-1024 signature of the PKCS1-padded descriptor digest,
    * taken from the beginning of the router line through the newline after
    * the router-signature line, or null if the descriptor doesn't contain
diff --git a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
index e2b3827..dd1bc07 100644
--- a/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
+++ b/src/main/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
@@ -66,6 +66,7 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
     atMostOnceKeywords.addAll(connBiDirectStatsKeywords);
     atMostOnceKeywords.addAll(exitStatsKeywords);
     atMostOnceKeywords.addAll(bridgeStatsKeywords);
+    atMostOnceKeywords.add("padding-counts");
     this.checkAtMostOnceKeywords(atMostOnceKeywords);
     this.checkKeywordsDependOn(dirreqStatsKeywords, "dirreq-stats-end");
     this.checkKeywordsDependOn(entryStatsKeywords, "entry-stats-end");
@@ -220,6 +221,9 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
         case "hidserv-dir-onions-seen":
           this.parseHidservDirOnionsSeenLine(line, lineNoOpt, partsNoOpt);
           break;
+        case "padding-counts":
+          this.parsePaddingCountsLine(line, lineNoOpt, partsNoOpt);
+          break;
         case "identity-ed25519":
           this.parseIdentityEd25519Line(line, lineNoOpt, partsNoOpt);
           nextCrypto = "identity-ed25519";
@@ -756,6 +760,16 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
         partsNoOpt, 2);
   }
 
+  private void parsePaddingCountsLine(String line, String lineNoOpt,
+      String[] partsNoOpt) throws DescriptorParseException {
+    long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt,
+        6);
+    this.paddingCountsStatsEndMillis = parsedStatsEndData[0];
+    this.paddingCountsStatsIntervalLength = parsedStatsEndData[1];
+    this.paddingCounts = ParseHelper.parseSpaceSeparatedStringKeyLongValueMap(
+        line, partsNoOpt, 5);
+  }
+
   private void parseRouterSignatureLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
     if (!lineNoOpt.equals("router-signature")) {
@@ -1341,6 +1355,28 @@ public abstract class ExtraInfoDescriptorImpl extends DescriptorImpl
         : new HashMap<>(this.hidservDirOnionsSeenParameters);
   }
 
+  private long paddingCountsStatsEndMillis = -1L;
+
+  @Override
+  public long getPaddingCountsStatsEndMillis() {
+    return this.paddingCountsStatsEndMillis;
+  }
+
+  private long paddingCountsStatsIntervalLength = -1L;
+
+  @Override
+  public long getPaddingCountsStatsIntervalLength() {
+    return this.paddingCountsStatsIntervalLength;
+  }
+
+  private Map<String, Long> paddingCounts;
+
+  @Override
+  public Map<String, Long> getPaddingCounts() {
+    return this.paddingCounts == null ? null
+        : new HashMap<>(this.paddingCounts);
+  }
+
   private String routerSignature;
 
   @Override
diff --git a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
index fa6ca75..0d4a27a 100644
--- a/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
+++ b/src/main/java/org/torproject/descriptor/impl/ParseHelper.java
@@ -493,6 +493,39 @@ public class ParseHelper {
     return result;
   }
 
+  protected static Map<String, Long>
+      parseSpaceSeparatedStringKeyLongValueMap(String line,
+      String[] partsNoOpt, int startIndex)
+      throws DescriptorParseException {
+    Map<String, Long> result = new LinkedHashMap<>();
+    if (partsNoOpt.length < startIndex) {
+      throw new DescriptorParseException("Line '" + line + "' does not "
+          + "contain a key-value list starting at index " + startIndex
+          + ".");
+    }
+    for (int i = startIndex; i < partsNoOpt.length; i++) {
+      String listElement = partsNoOpt[i];
+      String[] keyAndValue = listElement.split("=");
+      String key = null;
+      Long value = null;
+      if (keyAndValue.length == 2) {
+        try {
+          value = Long.parseLong(keyAndValue[1]);
+          key = keyAndValue[0];
+        } catch (NumberFormatException e) {
+          /* Handle below. */
+        }
+      }
+      if (key == null) {
+        throw new DescriptorParseException("Line '" + line + "' contains "
+            + "an illegal key or value in list element '" + listElement
+            + "'.");
+      }
+      result.put(key, value);
+    }
+    return result;
+  }
+
   protected static String
       parseMasterKeyEd25519FromIdentityEd25519CryptoBlock(
       String identityEd25519CryptoBlock) throws DescriptorParseException {
diff --git a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
index 76a2148..0afc344 100644
--- a/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
+++ b/src/test/java/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
@@ -180,6 +180,15 @@ public class ExtraInfoDescriptorImplTest {
       return new RelayExtraInfoDescriptorImpl(db.buildDescriptor(), true);
     }
 
+    private String paddingCountsLine = null;
+
+    private static ExtraInfoDescriptor createWithPaddingCountsLine(
+        String line) throws DescriptorParseException {
+      DescriptorBuilder db = new DescriptorBuilder();
+      db.paddingCountsLine = line;
+      return new RelayExtraInfoDescriptorImpl(db.buildDescriptor(), true);
+    }
+
     private String unrecognizedLine = null;
 
     private static ExtraInfoDescriptor createWithUnrecognizedLine(
@@ -288,6 +297,9 @@ public class ExtraInfoDescriptorImplTest {
       if (this.hidservStatsLines != null) {
         sb.append(this.hidservStatsLines).append("\n");
       }
+      if (this.paddingCountsLine != null) {
+        sb.append(this.paddingCountsLine).append("\n");
+      }
       if (this.unrecognizedLine != null) {
         sb.append(this.unrecognizedLine).append("\n");
       }
@@ -1727,6 +1739,69 @@ public class ExtraInfoDescriptorImplTest {
   }
 
   @Test()
+  public void testPaddingCountsValid()
+      throws DescriptorParseException {
+    ExtraInfoDescriptor descriptor = DescriptorBuilder
+        .createWithPaddingCountsLine("padding-counts 2017-05-10 01:48:43 "
+        + "(86400 s) bin-size=10000 write-drop=10000 write-pad=10000 "
+        + "write-total=10000 read-drop=10000 read-pad=10000 read-total=70000 "
+        + "enabled-read-pad=0 enabled-read-total=0 enabled-write-pad=0 "
+        + "enabled-write-total=0 max-chanpad-timers=0");
+    assertEquals(1494380923000L,
+        descriptor.getPaddingCountsStatsEndMillis());
+    assertEquals(86400, descriptor.getPaddingCountsStatsIntervalLength());
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("bin-size"));
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("write-drop"));
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("write-pad"));
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("write-total"));
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("read-drop"));
+    assertEquals(10000L,
+        (long) descriptor.getPaddingCounts().get("read-pad"));
+    assertEquals(70000L,
+        (long) descriptor.getPaddingCounts().get("read-total"));
+    assertEquals(0L,
+        (long) descriptor.getPaddingCounts().get("enabled-read-pad"));
+    assertEquals(0L,
+        (long) descriptor.getPaddingCounts().get("enabled-read-total"));
+    assertEquals(0L,
+        (long) descriptor.getPaddingCounts().get("enabled-write-pad"));
+    assertEquals(0L,
+        (long) descriptor.getPaddingCounts().get("enabled-write-total"));
+    assertEquals(0L,
+        (long) descriptor.getPaddingCounts().get("max-chanpad-timers"));
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testPaddingCountsNoTime() throws DescriptorParseException {
+    DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+        + "(86400 s) bin-size=10000 write-drop=10000");
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testPaddingCountsNoInterval() throws DescriptorParseException {
+    DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+        + "01:48:43 bin-size=10000 write-drop=10000");
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testPaddingCountsCommaSeparatedList()
+      throws DescriptorParseException {
+    DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+        + "(86400 s) bin-size=10000,write-drop=10000");
+  }
+
+  @Test(expected = DescriptorParseException.class)
+  public void testPaddingCountsNoList() throws DescriptorParseException {
+    DescriptorBuilder.createWithPaddingCountsLine("padding-counts 2017-05-10 "
+        + "(86400 s)");
+  }
+
+  @Test()
   public void testHidservStatsValid() throws DescriptorParseException {
     ExtraInfoDescriptor descriptor = HidservStatsBuilder
         .createWithDefaultLines();





More information about the tor-commits mailing list