commit 8a5a8e2c2fcd5317242feb0f485b0600102951f7 Author: Karsten Loesing karsten.loesing@gmx.net Date: Wed Feb 1 11:04:21 2012 +0100
Parse all statistics in extra-info descriptors. --- .../torproject/descriptor/ExtraInfoDescriptor.java | 25 +- .../torproject/descriptor/impl/DescriptorImpl.java | 12 + .../descriptor/impl/ExtraInfoDescriptorImpl.java | 406 ++++++++++++++------ .../torproject/descriptor/impl/ParseHelper.java | 103 +++++ .../descriptor/impl/ServerDescriptorImplTest.java | 5 + 5 files changed, 419 insertions(+), 132 deletions(-)
diff --git a/src/org/torproject/descriptor/ExtraInfoDescriptor.java b/src/org/torproject/descriptor/ExtraInfoDescriptor.java index bd4bcd8..bc9f49d 100644 --- a/src/org/torproject/descriptor/ExtraInfoDescriptor.java +++ b/src/org/torproject/descriptor/ExtraInfoDescriptor.java @@ -143,7 +143,7 @@ public interface ExtraInfoDescriptor extends Descriptor {
/* Return the mean number of cells contained in circuit queues by * circuit deciles. */ - public List<Integer> getCellQueueCells(); + public List<Double> getCellQueuedCells();
/* Return the mean times in milliseconds that cells spend in circuit * queues by circuit deciles. */ @@ -160,7 +160,7 @@ public interface ExtraInfoDescriptor extends Descriptor { /* Return the interval length of the included statistics on * bi-directional connection usage, or -1 if no such statistics are * included. */ - public long getConnBiDirectIntervalLength(); + public long getConnBiDirectStatsIntervalLength();
/* Return the number of connections on which this relay read and wrote * less than 2 KiB/s in a 10-second interval, or -1 if no statistics on @@ -194,18 +194,19 @@ public interface ExtraInfoDescriptor extends Descriptor { public long getExitStatsIntervalLength();
/* Return statistics on KiB written by port with map keys being ports - * and map values being KiB rounded up to the next full KiB, or null if - * no exit statistics are included. */ - public SortedMap<Integer, Integer> getExitKibibytesWritten(); + * (or "other") and map values being KiB rounded up to the next full + * KiB, or null if no exit statistics are included. */ + public SortedMap<String, Integer> getExitKibibytesWritten();
- /* Return statistics on KiB read by port with map keys being ports and - * map values being KiB rounded up to the next full KiB, or null if no - * exit statistics are included. */ - public SortedMap<Integer, Integer> getExitKibibytesRead(); + /* Return statistics on KiB read by port with map keys being ports (or + * "other") and map values being KiB rounded up to the next full KiB, or + * null if no exit statistics are included. */ + public SortedMap<String, Integer> getExitKibibytesRead();
/* Return statistics on opened exit streams with map keys being ports - * and map values being the number of opened streams, rounded up to the - * nearest multiple of 4, or null if no exit statistics are included. */ - public SortedMap<Integer, Integer> getExitStreamsOpened(); + * (or "other") and map values being the number of opened streams, + * rounded up to the nearest multiple of 4, or null if no exit + * statistics are included. */ + public SortedMap<String, Integer> getExitStreamsOpened(); }
diff --git a/src/org/torproject/descriptor/impl/DescriptorImpl.java b/src/org/torproject/descriptor/impl/DescriptorImpl.java index d8705e2..3192e21 100644 --- a/src/org/torproject/descriptor/impl/DescriptorImpl.java +++ b/src/org/torproject/descriptor/impl/DescriptorImpl.java @@ -218,6 +218,18 @@ public abstract class DescriptorImpl implements Descriptor { } }
+ protected void checkKeywordsDependOn(Set<String> dependentKeywords, + String dependingKeyword) throws DescriptorParseException { + for (String dependentKeyword : dependentKeywords) { + if (this.parsedKeywords.containsKey(dependentKeyword) && + !this.parsedKeywords.containsKey(dependingKeyword)) { + throw new DescriptorParseException("Keyword '" + dependentKeyword + + "' is contained, but keyword '" + dependingKeyword + "' is " + + "not."); + } + } + } + protected int getKeywordCount(String keyword) { if (!this.parsedKeywords.containsKey(keyword)) { return 0; diff --git a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java index 73ea040..5320563 100644 --- a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java +++ b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java @@ -11,12 +11,11 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedMap; +import java.util.TreeMap;
import org.torproject.descriptor.BandwidthHistory; import org.torproject.descriptor.ExtraInfoDescriptor;
-/* TODO Implement methods to parse the various statistics (other than - * bandwidth histories. */ /* TODO Write a test class. */ public class ExtraInfoDescriptorImpl extends DescriptorImpl implements ExtraInfoDescriptor { @@ -46,21 +45,39 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl Set<String> exactlyOnceKeywords = new HashSet<String>(Arrays.asList(( "extra-info,published").split(","))); this.checkExactlyOnceKeywords(exactlyOnceKeywords); + Set<String> dirreqStatsKeywords = new HashSet<String>(Arrays.asList(( + "dirreq-stats-end,dirreq-v2-ips,dirreq-v3-ips,dirreq-v2-reqs," + + "dirreq-v3-reqs,dirreq-v2-share,dirreq-v3-share,dirreq-v2-resp," + + "dirreq-v3-resp,dirreq-v2-direct-dl,dirreq-v3-direct-dl," + + "dirreq-v2-tunneled-dl,dirreq-v3-tunneled-dl,").split(","))); + Set<String> entryStatsKeywords = new HashSet<String>(Arrays.asList( + "entry-stats-end,entry-ips".split(","))); + Set<String> cellStatsKeywords = new HashSet<String>(Arrays.asList(( + "cell-stats-end,cell-processed-cells,cell-queued-cells," + + "cell-time-in-queue,cell-circuits-per-decile").split(","))); + Set<String> connBiDirectStatsKeywords = new HashSet<String>( + Arrays.asList("conn-bi-direct".split(","))); + Set<String> exitStatsKeywords = new HashSet<String>(Arrays.asList(( + "exit-stats-end,exit-kibibytes-written,exit-kibibytes-read," + + "exit-streams-opened").split(","))); + Set<String> bridgeStatsKeywords = new HashSet<String>(Arrays.asList( + "bridge-stats-end,bridge-stats-ips".split(","))); Set<String> atMostOnceKeywords = new HashSet<String>(Arrays.asList(( - "read-history,write-history,geoip-db-digest,dirreq-stats-end," - + "dirreq-v2-ips,dirreq-v3-ips,dirreq-v2-reqs,dirreq-v3-reqs," - + "dirreq-v2-share,dirreq-v3-share,dirreq-v2-resp,dirreq-v3-resp," - + "dirreq-v2-direct-dl,dirreq-v3-direct-dl,dirreq-v2-tunneled-dl," - + "dirreq-v3-tunneled-dl,dirreq-read-history," - + "dirreq-write-history,entry-stats-end,entry-ips,cell-stats-end," - + "cell-processed-cells,cell-queued-cells,cell-time-in-queue," - + "cell-circuits-per-decile,conn-bi-direct,exit-stats-end," - + "exit-kibibytes-written,exit-kibibytes-read," - + "exit-streams-opened,bridge-stats-end,bridge-stats-ips," - + "router-signature").split(","))); + "read-history,write-history,dirreq-read-history," + + "dirreq-write-history,geoip-db-digest,router-signature"). + split(","))); + atMostOnceKeywords.addAll(dirreqStatsKeywords); + atMostOnceKeywords.addAll(entryStatsKeywords); + atMostOnceKeywords.addAll(cellStatsKeywords); + atMostOnceKeywords.addAll(connBiDirectStatsKeywords); + atMostOnceKeywords.addAll(exitStatsKeywords); + atMostOnceKeywords.addAll(bridgeStatsKeywords); this.checkAtMostOnceKeywords(atMostOnceKeywords); - /* TODO Add more checks to see that only statistics details lines are - * included with corresponding statistics interval lines. */ + this.checkKeywordsDependOn(dirreqStatsKeywords, "dirreq-stats-end"); + this.checkKeywordsDependOn(entryStatsKeywords, "entry-stats-end"); + this.checkKeywordsDependOn(cellStatsKeywords, "cell-stats-end"); + this.checkKeywordsDependOn(exitStatsKeywords, "exit-stats-end"); + this.checkKeywordsDependOn(bridgeStatsKeywords, "bridge-stats-end"); this.checkFirstKeyword("extra-info"); return; } @@ -205,82 +222,139 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseGeoipDbDigestLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + if (partsNoOpt.length != 2) { + throw new DescriptorParseException("Illegal line '" + line + + "' in extra-info descriptor."); + } + this.geoipDbDigest = ParseHelper.parseTwentyByteHexString(line, + partsNoOpt[1]); }
private void parseGeoipStartTimeLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + if (partsNoOpt.length != 3) { + throw new DescriptorParseException("Illegal line '" + line + + "' in extra-info descriptor."); + } + this.geoipStartTimeMillis = ParseHelper.parseTimestampAtIndex(line, + partsNoOpt, 1, 2); }
private void parseGeoipClientOriginsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.geoipClientOrigins = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 2); }
private void parseDirreqStatsEndLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.dirreqStatsEndMillis = parsedStatsEndData[0]; + this.dirreqStatsIntervalLength = parsedStatsEndData[1]; + } + + private long[] parseStatsEndLine(String line, String partsNoOpt[], + int partsNoOptExpectedLength) throws DescriptorParseException { + if (partsNoOpt.length != partsNoOptExpectedLength || + partsNoOpt[3].length() < 2 || !partsNoOpt[3].startsWith("(") || + !partsNoOpt[4].equals("s)")) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + long[] result = new long[2]; + result[0] = ParseHelper.parseTimestampAtIndex(line, partsNoOpt, 1, 2); + result[1] = ParseHelper.parseSeconds(line, + partsNoOpt[3].substring(1)); + return result; }
private void parseDirreqV2IpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2Ips = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseDirreqV3IpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3Ips = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseDirreqV2ReqsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseDirreqV3ReqsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseDirreqV2ShareLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2Share = this.parseShareLine(line, partsNoOpt); }
private void parseDirreqV3ShareLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3Share = this.parseShareLine(line, partsNoOpt); + } + + private double parseShareLine(String line, String[] partsNoOpt) + throws DescriptorParseException { + double share = -1.0; + if (partsNoOpt.length == 2 && partsNoOpt[1].length() >= 2 && + partsNoOpt[1].endsWith("%")) { + String shareString = partsNoOpt[1]; + shareString = shareString.substring(0, shareString.length() - 1); + try { + share = Double.parseDouble(shareString); + } catch (NumberFormatException e) { + /* Handle below. */ + } + } + if (share < 0.0) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + return share; }
private void parseDirreqV2RespLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2Resp = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 0); }
private void parseDirreqV3RespLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3Resp = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 0); }
private void parseDirreqV2DirectDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2DirectDl = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseDirreqV3DirectDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3DirectDl = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseDirreqV2TunneledDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV2TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseDirreqV3TunneledDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.dirreqV3TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseDirreqReadHistoryLine(String line, String lineNoOpt, @@ -297,74 +371,118 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseEntryStatsEndLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.entryStatsEndMillis = parsedStatsEndData[0]; + this.entryStatsIntervalLength = parsedStatsEndData[1]; }
private void parseEntryIpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.entryIps = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseCellStatsEndLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.cellStatsEndMillis = parsedStatsEndData[0]; + this.cellStatsIntervalLength = parsedStatsEndData[1]; }
private void parseCellProcessedCellsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.cellProcessedCells = ParseHelper. + parseCommaSeparatedIntegerValueList(line, partsNoOpt, 1); }
private void parseCellQueuedCellsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.cellQueuedCells = ParseHelper.parseCommaSeparatedDoubleValueList( + line, partsNoOpt, 1); }
private void parseCellTimeInQueueLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.cellTimeInQueue = ParseHelper. + parseCommaSeparatedIntegerValueList(line, partsNoOpt, 1); }
private void parseCellCircuitsPerDecileLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + int circuits = -1; + if (partsNoOpt.length == 2) { + try { + circuits = Integer.parseInt(partsNoOpt[1]); + } catch (NumberFormatException e) { + /* Handle below. */ + } + } + if (circuits < 0) { + throw new DescriptorParseException("Illegal line '" + line + "'."); + } + this.cellCircuitsPerDecile = circuits; }
private void parseConnBiDirectLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 6); + this.connBiDirectStatsEndMillis = parsedStatsEndData[0]; + this.connBiDirectStatsIntervalLength = parsedStatsEndData[1]; + List<Integer> parsedConnBiDirectStats = ParseHelper. + parseCommaSeparatedIntegerValueList(line, partsNoOpt, 5); + if (parsedConnBiDirectStats.size() != 4) { + throw new DescriptorParseException("Illegal line '" + line + "' in " + + "extra-info descriptor."); + } + this.connBiDirectBelow = parsedConnBiDirectStats.get(0); + this.connBiDirectRead = parsedConnBiDirectStats.get(1); + this.connBiDirectWrite = parsedConnBiDirectStats.get(2); + this.connBiDirectBoth = parsedConnBiDirectStats.get(3); }
private void parseExitStatsEndLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.exitStatsEndMillis = parsedStatsEndData[0]; + this.exitStatsIntervalLength = parsedStatsEndData[1]; }
private void parseExitKibibytesWrittenLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.exitKibibytesWritten = ParseHelper. + parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0); }
private void parseExitKibibytesReadLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.exitKibibytesRead = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseExitStreamsOpenedLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.exitStreamsOpened = ParseHelper.parseCommaSeparatedKeyValueList( + line, partsNoOpt, 1, 0); }
private void parseBridgeStatsEndLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + long[] parsedStatsEndData = this.parseStatsEndLine(line, partsNoOpt, + 5); + this.bridgeStatsEndMillis = parsedStatsEndData[0]; + this.bridgeStatsIntervalLength = parsedStatsEndData[1]; }
private void parseBridgeStatsIpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - /* TODO Implement me. */ + this.bridgeIps = ParseHelper.parseCommaSeparatedKeyValueList(line, + partsNoOpt, 1, 2); }
private void parseRouterSignatureLine(String line, String lineNoOpt, @@ -400,79 +518,89 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl return this.writeHistory; }
+ private String geoipDbDigest; public String getGeoipDbDigest() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.geoipDbDigest; }
+ private long dirreqStatsEndMillis = -1L; public long getDirreqStatsEndMillis() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqStatsEndMillis; }
+ private long dirreqStatsIntervalLength = -1L; public long getDirreqStatsIntervalLength() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqStatsIntervalLength; }
+ private SortedMap<String, Integer> dirreqV2Ips; public SortedMap<String, Integer> getDirreqV2Ips() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2Ips == null ? null : + new TreeMap<String, Integer>(this.dirreqV2Ips); }
+ private SortedMap<String, Integer> dirreqV3Ips; public SortedMap<String, Integer> getDirreqV3Ips() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3Ips == null ? null : + new TreeMap<String, Integer>(this.dirreqV3Ips); }
+ private SortedMap<String, Integer> dirreqV2Reqs; public SortedMap<String, Integer> getDirreqV2Reqs() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2Reqs == null ? null : + new TreeMap<String, Integer>(this.dirreqV2Reqs); }
+ private SortedMap<String, Integer> dirreqV3Reqs; public SortedMap<String, Integer> getDirreqV3Reqs() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3Reqs == null ? null : + new TreeMap<String, Integer>(this.dirreqV3Reqs); }
+ private double dirreqV2Share = -1.0; public double getDirreqV2Share() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2Share; }
+ private double dirreqV3Share = -1.0; public double getDirreqV3Share() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3Share; }
+ private SortedMap<String, Integer> dirreqV2Resp; public SortedMap<String, Integer> getDirreqV2Resp() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2Resp == null ? null : + new TreeMap<String, Integer>(this.dirreqV2Resp); }
+ private SortedMap<String, Integer> dirreqV3Resp; public SortedMap<String, Integer> getDirreqV3Resp() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3Resp == null ? null : + new TreeMap<String, Integer>(this.dirreqV3Resp); }
+ private SortedMap<String, Integer> dirreqV2DirectDl; public SortedMap<String, Integer> getDirreqV2DirectDl() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2DirectDl == null ? null : + new TreeMap<String, Integer>(this.dirreqV2DirectDl); }
+ private SortedMap<String, Integer> dirreqV3DirectDl; public SortedMap<String, Integer> getDirreqV3DirectDl() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3DirectDl == null ? null : + new TreeMap<String, Integer>(this.dirreqV3DirectDl); }
+ private SortedMap<String, Integer> dirreqV2TunneledDl; public SortedMap<String, Integer> getDirreqV2TunneledDl() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV2TunneledDl == null ? null : + new TreeMap<String, Integer>(this.dirreqV2TunneledDl); }
+ private SortedMap<String, Integer> dirreqV3TunneledDl; public SortedMap<String, Integer> getDirreqV3TunneledDl() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.dirreqV3TunneledDl == null ? null : + new TreeMap<String, Integer>(this.dirreqV3TunneledDl); }
private BandwidthHistory dirreqReadHistory; @@ -485,104 +613,142 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl return this.dirreqWriteHistory; }
+ private long entryStatsEndMillis = -1L; public long getEntryStatsEndMillis() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.entryStatsEndMillis; }
+ private long entryStatsIntervalLength = -1L; public long getEntryStatsIntervalLength() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.entryStatsIntervalLength; }
+ private SortedMap<String, Integer> entryIps; public SortedMap<String, Integer> getEntryIps() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.entryIps == null ? null : + new TreeMap<String, Integer>(this.entryIps); }
+ private long cellStatsEndMillis = -1L; public long getCellStatsEndMillis() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.cellStatsEndMillis; }
+ private long cellStatsIntervalLength = -1L; public long getCellStatsIntervalLength() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.cellStatsIntervalLength; }
+ private List<Integer> cellProcessedCells; public List<Integer> getCellProcessedCells() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.cellProcessedCells == null ? null : + new ArrayList<Integer>(this.cellProcessedCells); }
- public List<Integer> getCellQueueCells() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + private List<Double> cellQueuedCells; + public List<Double> getCellQueuedCells() { + return this.cellQueuedCells == null ? null : + new ArrayList<Double>(this.cellQueuedCells); }
+ private List<Integer> cellTimeInQueue; public List<Integer> getCellTimeInQueue() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.cellTimeInQueue == null ? null : + new ArrayList<Integer>(this.cellTimeInQueue); }
+ private int cellCircuitsPerDecile = -1; public int getCellCircuitsPerDecile() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.cellCircuitsPerDecile; }
+ private long connBiDirectStatsEndMillis = -1L; public long getConnBiDirectStatsEndMillis() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.connBiDirectStatsEndMillis; }
- public long getConnBiDirectIntervalLength() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + private long connBiDirectStatsIntervalLength = -1L; + public long getConnBiDirectStatsIntervalLength() { + return this.connBiDirectStatsIntervalLength; }
+ private int connBiDirectBelow = -1; public int getConnBiDirectBelow() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.connBiDirectBelow; }
+ private int connBiDirectRead = -1; public int getConnBiDirectRead() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.connBiDirectRead; }
+ private int connBiDirectWrite = -1; public int getConnBiDirectWrite() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.connBiDirectWrite; }
+ private int connBiDirectBoth = -1; public int getConnBiDirectBoth() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.connBiDirectBoth; }
+ private long exitStatsEndMillis = -1L; public long getExitStatsEndMillis() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.exitStatsEndMillis; }
+ private long exitStatsIntervalLength = -1L; public long getExitStatsIntervalLength() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + return this.exitStatsIntervalLength; + } + + /* TODO Add custom comparators to the maps returned by all three + * exit-stats methods to sort keys alphanumerically, not + * alphabetically. */ + + private SortedMap<String, Integer> exitKibibytesWritten; + public SortedMap<String, Integer> getExitKibibytesWritten() { + return this.exitKibibytesWritten == null ? null : + new TreeMap<String, Integer>(this.exitKibibytesWritten); + } + + private SortedMap<String, Integer> exitKibibytesRead; + public SortedMap<String, Integer> getExitKibibytesRead() { + return this.exitKibibytesRead == null ? null : + new TreeMap<String, Integer>(this.exitKibibytesRead); + } + + private SortedMap<String, Integer> exitStreamsOpened; + public SortedMap<String, Integer> getExitStreamsOpened() { + return this.exitStreamsOpened == null ? null : + new TreeMap<String, Integer>(this.exitStreamsOpened); + } + + private long geoipStartTimeMillis = -1L; + public long getGeoipStartTimeMillis() { + return this.geoipStartTimeMillis; + } + + private SortedMap<String, Integer> geoipClientOrigins; + public SortedMap<String, Integer> getGeoipClientOrigins() { + return this.geoipClientOrigins == null ? null : + new TreeMap<String, Integer>(this.geoipClientOrigins); }
- public SortedMap<Integer, Integer> getExitKibibytesWritten() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + private long bridgeStatsEndMillis = -1L; + public long getBridgeStatsEndMillis() { + return this.bridgeStatsEndMillis; }
- public SortedMap<Integer, Integer> getExitKibibytesRead() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + private long bridgeStatsIntervalLength = -1L; + public long getBridgeStatsIntervalLength() { + return this.bridgeStatsIntervalLength; }
- public SortedMap<Integer, Integer> getExitStreamsOpened() { - /* TODO Implement me. */ - throw new UnsupportedOperationException(); + private SortedMap<String, Integer> bridgeIps; + public SortedMap<String, Integer> getBridgeIps() { + return this.bridgeIps == null ? null : + new TreeMap<String, Integer>(this.bridgeIps); } }
diff --git a/src/org/torproject/descriptor/impl/ParseHelper.java b/src/org/torproject/descriptor/impl/ParseHelper.java index facd4ea..2779d5a 100644 --- a/src/org/torproject/descriptor/impl/ParseHelper.java +++ b/src/org/torproject/descriptor/impl/ParseHelper.java @@ -4,6 +4,8 @@ package org.torproject.descriptor.impl;
import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; import java.util.SortedMap; import java.util.TimeZone; import java.util.TreeMap; @@ -61,6 +63,16 @@ public class ParseHelper { return port; }
+ public static long parseSeconds(String line, String secondsString) + throws DescriptorParseException { + try { + return Long.parseLong(secondsString); + } catch (NumberFormatException e) { + throw new DescriptorParseException("'" + secondsString + "' in " + + "line '" + line + "' is not a valid time in seconds."); + } + } + public static String parseExitPattern(String line, String exitPattern) throws DescriptorParseException { if (!exitPattern.contains(":")) { @@ -185,5 +197,96 @@ public class ParseHelper { return Hex.encodeHexString(Base64.decodeBase64(base64String + "=")). toUpperCase(); } + + public static SortedMap<String, Integer> + parseCommaSeparatedKeyValueList(String line, String[] partsNoOpt, + int index, int keyLength) throws DescriptorParseException { + SortedMap<String, Integer> result = new TreeMap<String, Integer>(); + if (partsNoOpt.length < index) { + throw new DescriptorParseException("Line '" + line + "' does not " + + "contain a key-value list at index " + index + "."); + } else if (partsNoOpt.length > index + 1 ) { + throw new DescriptorParseException("Line '" + line + "' contains " + + "unrecognized values beyond the expected key-value list at " + + "index " + index + "."); + } else if (partsNoOpt.length > index) { + String[] listElements = partsNoOpt[index].split(","); + for (String listElement : listElements) { + String[] keyAndValue = listElement.split("="); + String key = null; + int value = -1; + if (keyAndValue.length == 2 && (keyLength == 0 || + keyAndValue[0].length() == keyLength)) { + try { + value = Integer.parseInt(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; + } + + public static List<Integer> parseCommaSeparatedIntegerValueList( + String line, String[] partsNoOpt, int index) + throws DescriptorParseException { + List<Integer> result = new ArrayList<Integer>(); + if (partsNoOpt.length < index) { + throw new DescriptorParseException("Line '" + line + "' does not " + + "contain a comma-separated value list at index " + index + + "."); + } else if (partsNoOpt.length > index + 1 ) { + throw new DescriptorParseException("Line '" + line + "' contains " + + "unrecognized values beyond the expected comma-separated " + + "value list at index " + index + "."); + } else if (partsNoOpt.length > index) { + String[] listElements = partsNoOpt[index].split(","); + for (String listElement : listElements) { + try { + result.add(Integer.parseInt(listElement)); + } catch (NumberFormatException e) { + throw new DescriptorParseException("Line '" + line + "' " + + "contains an illegal value in list element '" + + listElement + "'."); + } + } + } + return result; + } + + public static List<Double> parseCommaSeparatedDoubleValueList( + String line, String[] partsNoOpt, int index) + throws DescriptorParseException { + List<Double> result = new ArrayList<Double>(); + if (partsNoOpt.length < index) { + throw new DescriptorParseException("Line '" + line + "' does not " + + "contain a comma-separated value list at index " + index + + "."); + } else if (partsNoOpt.length > index + 1 ) { + throw new DescriptorParseException("Line '" + line + "' contains " + + "unrecognized values beyond the expected comma-separated " + + "value list at index " + index + "."); + } else if (partsNoOpt.length > index) { + String[] listElements = partsNoOpt[index].split(","); + for (String listElement : listElements) { + try { + result.add(Double.parseDouble(listElement)); + } catch (NumberFormatException e) { + throw new DescriptorParseException("Line '" + line + "' " + + "contains an illegal value in list element '" + + listElement + "'."); + } + } + } + return result; + } }
diff --git a/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java b/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java index 439e5bb..889fce4 100644 --- a/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java +++ b/test/org/torproject/descriptor/impl/ServerDescriptorImplTest.java @@ -487,6 +487,11 @@ public class ServerDescriptorImplTest { + "04:03:19"); }
+ @Test(expected = DescriptorParseException.class) + public void testPublishedNoTime() throws DescriptorParseException { + DescriptorBuilder.createWithPublishedLine("published 2012-01-01"); + } + @Test() public void testFingerprintNoOpt() throws DescriptorParseException { ServerDescriptor descriptor = DescriptorBuilder.
tor-commits@lists.torproject.org