commit 60a066a0b08bbe621ed5ce9d0184ac168435bfa4 Author: Karsten Loesing karsten.loesing@gmx.net Date: Mon Jul 8 12:53:53 2013 +0200
Fast exits read/write more than MAX_INT KiB per day.
For example, see "other" entry in:
exit-kibibytes-read 80=505190490,182=25102395,443=61873906, 6881=47999666,8989=8657674,17173=7910494,21762=9138992, 45682=5154543,50500=6086469,51413=62394452,other=2282907805 --- .../torproject/descriptor/ExtraInfoDescriptor.java | 6 +- .../descriptor/impl/ExtraInfoDescriptorImpl.java | 101 +++++++++++--------- .../torproject/descriptor/impl/ParseHelper.java | 43 ++++++++- .../impl/ExtraInfoDescriptorImplTest.java | 15 ++- 4 files changed, 111 insertions(+), 54 deletions(-)
diff --git a/src/org/torproject/descriptor/ExtraInfoDescriptor.java b/src/org/torproject/descriptor/ExtraInfoDescriptor.java index 1478a4a..d19c590 100644 --- a/src/org/torproject/descriptor/ExtraInfoDescriptor.java +++ b/src/org/torproject/descriptor/ExtraInfoDescriptor.java @@ -205,18 +205,18 @@ public interface ExtraInfoDescriptor extends Descriptor { /* Return statistics on KiB written 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> getExitKibibytesWritten(); + public SortedMap<String, Long> getExitKibibytesWritten();
/* 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(); + public SortedMap<String, Long> getExitKibibytesRead();
/* Return statistics on opened exit streams with map keys being ports * (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(); + public SortedMap<String, Long> getExitStreamsOpened();
/* Return the start of the included geoip statistics, or -1 if no geoip * statistics are included. */ diff --git a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java index f5bf8ed..c67a040 100644 --- a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java +++ b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java @@ -258,8 +258,9 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseGeoipClientOriginsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.geoipClientOrigins = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 2); + this.geoipClientOrigins = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 2); }
private void parseDirreqStatsEndLine(String line, String lineNoOpt, @@ -290,25 +291,27 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseDirreqV2IpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV2Ips = ParseHelper.parseCommaSeparatedKeyValueList(line, - partsNoOpt, 1, 2); + this.dirreqV2Ips = ParseHelper.parseCommaSeparatedKeyIntegerValueList( + line, partsNoOpt, 1, 2); }
private void parseDirreqV3IpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV3Ips = ParseHelper.parseCommaSeparatedKeyValueList(line, - partsNoOpt, 1, 2); + this.dirreqV3Ips = ParseHelper.parseCommaSeparatedKeyIntegerValueList( + line, partsNoOpt, 1, 2); }
private void parseDirreqV2ReqsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV2Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line, + this.dirreqV2Reqs = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, partsNoOpt, 1, 2); }
private void parseDirreqV3ReqsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV3Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line, + this.dirreqV3Reqs = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, partsNoOpt, 1, 2); }
@@ -343,38 +346,44 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseDirreqV2RespLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV2Resp = ParseHelper.parseCommaSeparatedKeyValueList(line, + this.dirreqV2Resp = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, partsNoOpt, 1, 0); }
private void parseDirreqV3RespLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV3Resp = ParseHelper.parseCommaSeparatedKeyValueList(line, + this.dirreqV3Resp = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, partsNoOpt, 1, 0); }
private void parseDirreqV2DirectDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV2DirectDl = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 0); + this.dirreqV2DirectDl = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 0); }
private void parseDirreqV3DirectDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV3DirectDl = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 0); + this.dirreqV3DirectDl = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 0); }
private void parseDirreqV2TunneledDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV2TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 0); + this.dirreqV2TunneledDl = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 0); }
private void parseDirreqV3TunneledDlLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.dirreqV3TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 0); + this.dirreqV3TunneledDl = + ParseHelper.parseCommaSeparatedKeyIntegerValueList( + line,partsNoOpt, 1, 0); }
private void parseDirreqReadHistoryLine(String line, String lineNoOpt, @@ -399,8 +408,8 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseEntryIpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.entryIps = ParseHelper.parseCommaSeparatedKeyValueList(line, - partsNoOpt, 1, 2); + this.entryIps = ParseHelper.parseCommaSeparatedKeyIntegerValueList( + line, partsNoOpt, 1, 2); }
private void parseCellStatsEndLine(String line, String lineNoOpt, @@ -488,7 +497,7 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { this.exitKibibytesWritten = this.sortByPorts(ParseHelper. - parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0)); + parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0)); this.verifyPorts(line, this.exitKibibytesWritten.keySet()); this.verifyBytesOrStreams(line, this.exitKibibytesWritten.values()); } @@ -496,7 +505,7 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl private void parseExitKibibytesReadLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { this.exitKibibytesRead = this.sortByPorts(ParseHelper. - parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0)); + parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0)); this.verifyPorts(line, this.exitKibibytesRead.keySet()); this.verifyBytesOrStreams(line, this.exitKibibytesRead.values()); } @@ -504,15 +513,15 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl private void parseExitStreamsOpenedLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { this.exitStreamsOpened = this.sortByPorts(ParseHelper. - parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0)); + parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0)); this.verifyPorts(line, this.exitStreamsOpened.keySet()); this.verifyBytesOrStreams(line, this.exitStreamsOpened.values()); }
- private SortedMap<String, Integer> sortByPorts( - SortedMap<String, Integer> naturalOrder) { - SortedMap<String, Integer> byPortNumber = - new TreeMap<String, Integer>(new Comparator<String>() { + private SortedMap<String, Long> sortByPorts( + SortedMap<String, Long> naturalOrder) { + SortedMap<String, Long> byPortNumber = + new TreeMap<String, Long>(new Comparator<String>() { public int compare(String arg0, String arg1) { int port0 = 0, port1 = 0; try { @@ -557,11 +566,10 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl }
private void verifyBytesOrStreams(String line, - Collection<Integer> bytesOrStreams) - throws DescriptorParseException { + Collection<Long> bytesOrStreams) throws DescriptorParseException { boolean valid = true; - for (int s : bytesOrStreams) { - if (s < 0) { + for (long s : bytesOrStreams) { + if (s < 0L) { valid = false; break; } @@ -582,20 +590,23 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
private void parseBridgeStatsIpsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.bridgeIps = ParseHelper.parseCommaSeparatedKeyValueList(line, + this.bridgeIps = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, partsNoOpt, 1, 2); }
private void parseBridgeIpVersionsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.bridgeIpVersions = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 2); + this.bridgeIpVersions = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 2); }
private void parseBridgeIpTransportsLine(String line, String lineNoOpt, String[] partsNoOpt) throws DescriptorParseException { - this.bridgeIpTransports = ParseHelper.parseCommaSeparatedKeyValueList( - line, partsNoOpt, 1, 0); + this.bridgeIpTransports = + ParseHelper.parseCommaSeparatedKeyIntegerValueList(line, + partsNoOpt, 1, 0); }
private void parseTransportLine(String line, String lineNoOpt, @@ -869,22 +880,22 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl return this.exitStatsIntervalLength; }
- private SortedMap<String, Integer> exitKibibytesWritten; - public SortedMap<String, Integer> getExitKibibytesWritten() { + private SortedMap<String, Long> exitKibibytesWritten; + public SortedMap<String, Long> getExitKibibytesWritten() { return this.exitKibibytesWritten == null ? null : - new TreeMap<String, Integer>(this.exitKibibytesWritten); + new TreeMap<String, Long>(this.exitKibibytesWritten); }
- private SortedMap<String, Integer> exitKibibytesRead; - public SortedMap<String, Integer> getExitKibibytesRead() { + private SortedMap<String, Long> exitKibibytesRead; + public SortedMap<String, Long> getExitKibibytesRead() { return this.exitKibibytesRead == null ? null : - new TreeMap<String, Integer>(this.exitKibibytesRead); + new TreeMap<String, Long>(this.exitKibibytesRead); }
- private SortedMap<String, Integer> exitStreamsOpened; - public SortedMap<String, Integer> getExitStreamsOpened() { + private SortedMap<String, Long> exitStreamsOpened; + public SortedMap<String, Long> getExitStreamsOpened() { return this.exitStreamsOpened == null ? null : - new TreeMap<String, Integer>(this.exitStreamsOpened); + new TreeMap<String, Long>(this.exitStreamsOpened); }
private long geoipStartTimeMillis = -1L; diff --git a/src/org/torproject/descriptor/impl/ParseHelper.java b/src/org/torproject/descriptor/impl/ParseHelper.java index 4fd776e..ebb8bc6 100644 --- a/src/org/torproject/descriptor/impl/ParseHelper.java +++ b/src/org/torproject/descriptor/impl/ParseHelper.java @@ -253,8 +253,9 @@ public class ParseHelper { }
public static SortedMap<String, Integer> - parseCommaSeparatedKeyValueList(String line, String[] partsNoOpt, - int index, int keyLength) throws DescriptorParseException { + parseCommaSeparatedKeyIntegerValueList(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 " @@ -289,6 +290,44 @@ public class ParseHelper { return result; }
+ public static SortedMap<String, Long> + parseCommaSeparatedKeyLongValueList(String line, + String[] partsNoOpt, int index, int keyLength) + throws DescriptorParseException { + SortedMap<String, Long> result = new TreeMap<String, Long>(); + 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(",", -1); + for (String listElement : listElements) { + String[] keyAndValue = listElement.split("="); + String key = null; + long value = -1; + if (keyAndValue.length == 2 && (keyLength == 0 || + keyAndValue[0].length() == keyLength)) { + 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; + } + public static List<Integer> parseCommaSeparatedIntegerValueList( String line, String[] partsNoOpt, int index) throws DescriptorParseException { diff --git a/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java b/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java index 11b07b2..4aa8a44 100644 --- a/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java +++ b/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java @@ -1234,7 +1234,7 @@ public class ExtraInfoDescriptorImplTest { int[] writtenValues = new int[] { 74647, 31370, 20577, 23, 12, 1111, 4, 11, 6, 3365, 2592 }; int i = 0; - for (Map.Entry<String, Integer> e : + for (Map.Entry<String, Long> e : descriptor.getExitKibibytesWritten().entrySet()) { assertEquals(ports[i], e.getKey()); assertEquals(writtenValues[i++], e.getValue().intValue()); @@ -1242,7 +1242,7 @@ public class ExtraInfoDescriptorImplTest { int[] readValues = new int[] { 35562, 1254256, 110279, 9396, 1911, 648, 1188, 1427, 1824, 14, 3054 }; i = 0; - for (Map.Entry<String, Integer> e : + for (Map.Entry<String, Long> e : descriptor.getExitKibibytesRead().entrySet()) { assertEquals(ports[i], e.getKey()); assertEquals(readValues[i++], e.getValue().intValue()); @@ -1250,7 +1250,7 @@ public class ExtraInfoDescriptorImplTest { int[] streamsValues = new int[] { 369748, 64212, 151660, 4, 4, 4, 4, 4, 4, 4, 1212 }; i = 0; - for (Map.Entry<String, Integer> e : + for (Map.Entry<String, Long> e : descriptor.getExitStreamsOpened().entrySet()) { assertEquals(ports[i], e.getKey()); assertEquals(streamsValues[i++], e.getValue().intValue()); @@ -1285,7 +1285,14 @@ public class ExtraInfoDescriptorImplTest { "exit-kibibytes-read 25=-35562"); }
- @Test(expected = DescriptorParseException.class) + @Test() + public void testExitStatsReadTooLarge() + throws DescriptorParseException { + ExitStatsBuilder.createWithExitKibibytesReadLine( + "exit-kibibytes-read other=2282907805"); + } + + @Test() public void testExitStatsStreamsTooLarge() throws DescriptorParseException { ExitStatsBuilder.createWithExitStreamsOpenedLine(