commit 0f0b0091a629945d07e365b194f58b6fd3c9fb84 Author: Karsten Loesing karsten.loesing@gmx.net Date: Sun Jan 15 11:17:51 2012 +0100
Start parsing bridge pool assignments. --- .../descriptor/BridgePoolAssignment.java | 17 +++ .../descriptor/BridgePoolAssignmentReader.java | 7 ++ .../descriptor/DescriptorSourceFactory.java | 6 + .../descriptor/impl/BridgePoolAssignmentImpl.java | 107 ++++++++++++++++++++ .../torproject/descriptor/impl/DescriptorImpl.java | 9 +- .../impl/RelayOrBridgeDescriptorReaderImpl.java | 4 +- 6 files changed, 146 insertions(+), 4 deletions(-)
diff --git a/src/org/torproject/descriptor/BridgePoolAssignment.java b/src/org/torproject/descriptor/BridgePoolAssignment.java new file mode 100644 index 0000000..43857ac --- /dev/null +++ b/src/org/torproject/descriptor/BridgePoolAssignment.java @@ -0,0 +1,17 @@ +/* Copyright 2012 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.descriptor; + +import java.util.SortedMap; + +public interface BridgePoolAssignment extends Descriptor { + + /* Return the publication time of this bridge pool assignment list. */ + public long getPublishedMillis(); + + /* Return the entries contained in this bridge pool assignment list with + * map keys being bridge fingerprints and map values being assignment + * strings, e.g. "https ring=3 flag=stable". */ + public SortedMap<String, String> getEntries(); +} + diff --git a/src/org/torproject/descriptor/BridgePoolAssignmentReader.java b/src/org/torproject/descriptor/BridgePoolAssignmentReader.java index 9553fe4..e84f2b4 100644 --- a/src/org/torproject/descriptor/BridgePoolAssignmentReader.java +++ b/src/org/torproject/descriptor/BridgePoolAssignmentReader.java @@ -11,6 +11,13 @@ public interface BridgePoolAssignmentReader { /* Add a local directory to read bridge pool assignments from. */ public void addDirectory(File directory);
+ /* Exclude files that are contained in the given history file and that + * haven't changed since they were last read. Add reads from the + * current run to the history file. Remove files that don't exist + * anymore from the history file. Lines in the history file contain the + * last modified timestamp and the absolute path of a file. */ + public void setExcludeFiles(File historyFile); + /* Read the previously configured bridge pool assignments and make them * available via the returned blocking iterator. Whenever the reader * runs out of descriptors and expects to provide more shortly after, it diff --git a/src/org/torproject/descriptor/DescriptorSourceFactory.java b/src/org/torproject/descriptor/DescriptorSourceFactory.java index 9dcba61..031eeab 100644 --- a/src/org/torproject/descriptor/DescriptorSourceFactory.java +++ b/src/org/torproject/descriptor/DescriptorSourceFactory.java @@ -23,5 +23,11 @@ public class DescriptorSourceFactory { public static BridgeDescriptorReader createBridgeDescriptorReader() { return new RelayOrBridgeDescriptorReaderImpl(); } + + /* Create a bridge pool assignment reader. */ + public static BridgePoolAssignmentReader + createBridgePoolAssignmentReader() { + return new RelayOrBridgeDescriptorReaderImpl(); + } }
diff --git a/src/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java b/src/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java new file mode 100644 index 0000000..b539dde --- /dev/null +++ b/src/org/torproject/descriptor/impl/BridgePoolAssignmentImpl.java @@ -0,0 +1,107 @@ +/* Copyright 2012 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.descriptor.impl; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import org.torproject.descriptor.BridgePoolAssignment; + +/* TODO Write a test class. */ +public class BridgePoolAssignmentImpl extends DescriptorImpl + implements BridgePoolAssignment { + + protected static List<BridgePoolAssignment> parseDescriptors( + byte[] descriptorsBytes) { + List<BridgePoolAssignment> parsedDescriptors = + new ArrayList<BridgePoolAssignment>(); + List<byte[]> splitDescriptorsBytes = + DescriptorImpl.splitRawDescriptorBytes(descriptorsBytes, + "bridge-pool-assignment "); + try { + for (byte[] descriptorBytes : splitDescriptorsBytes) { + BridgePoolAssignment parsedDescriptor = + new BridgePoolAssignmentImpl(descriptorBytes); + parsedDescriptors.add(parsedDescriptor); + } + } catch (DescriptorParseException e) { + /* TODO Handle this error somehow. */ + System.err.println("Failed to parse descriptor. Skipping."); + e.printStackTrace(); + } + return parsedDescriptors; + } + + protected BridgePoolAssignmentImpl(byte[] descriptorBytes) + throws DescriptorParseException { + super(descriptorBytes); + this.parseDescriptorBytes(); + Set<String> exactlyOnceKeywords = new HashSet<String>(Arrays.asList( + new String[] { "bridge-pool-assignment" })); + this.checkExactlyOnceKeywords(exactlyOnceKeywords); + this.checkFirstKeyword("bridge-pool-assignment"); + return; + } + + private void parseDescriptorBytes() throws DescriptorParseException { + try { + BufferedReader br = new BufferedReader(new StringReader( + new String(this.rawDescriptorBytes))); + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("bridge-pool-assignment ")) { + this.parseBridgePoolAssignmentLine(line); + } else { + this.parseBridgeLine(line); + } + } + } catch (IOException e) { + throw new RuntimeException("Internal error: Ran into an " + + "IOException while parsing a String in memory. Something's " + + "really wrong.", e); + } + } + + private void parseBridgePoolAssignmentLine(String line) + throws DescriptorParseException { + String[] parts = line.split(" "); + if (parts.length != 3) { + throw new DescriptorParseException("Illegal line '" + line + + "' in bridge pool assignment."); + } + this.publishedMillis = ParseHelper.parseTimestampAtIndex(line, + parts, 1, 2); + } + + private void parseBridgeLine(String line) + throws DescriptorParseException { + String[] parts = line.split(" "); + if (parts.length < 2) { + throw new DescriptorParseException("Illegal line '" + line + + "' in bridge pool assignment."); + } + String fingerprint = ParseHelper.parseTwentyByteHexString(line, + parts[0]); + String poolAndDetails = line.substring(line.indexOf(" ") + 1); + this.entries.put(fingerprint, poolAndDetails); + } + + private long publishedMillis; + public long getPublishedMillis() { + return this.publishedMillis; + } + + private SortedMap<String, String> entries = + new TreeMap<String, String>(); + public SortedMap<String, String> getEntries() { + return new TreeMap<String, String>(this.entries); + } +} + diff --git a/src/org/torproject/descriptor/impl/DescriptorImpl.java b/src/org/torproject/descriptor/impl/DescriptorImpl.java index 68b70e1..cc0cd6e 100644 --- a/src/org/torproject/descriptor/impl/DescriptorImpl.java +++ b/src/org/torproject/descriptor/impl/DescriptorImpl.java @@ -47,10 +47,13 @@ public abstract class DescriptorImpl implements Descriptor { firstLines.contains("\nextra-info ")) { parsedDescriptors.addAll(ExtraInfoDescriptorImpl. parseDescriptors(rawDescriptorBytes)); + } else if (firstLines.startsWith("bridge-pool-assignment ") || + firstLines.contains("\nbridge-pool-assignment ")) { + parsedDescriptors.addAll(BridgePoolAssignmentImpl. + parseDescriptors(rawDescriptorBytes)); } else { - throw new DescriptorParseException("Could not detect relay or " - + "bridge descriptor type in descriptor starting with '" - + firstLines + "'."); + throw new DescriptorParseException("Could not detect descriptor " + + "type in descriptor starting with '" + firstLines + "'."); } return parsedDescriptors; } diff --git a/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java b/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java index 1e341f5..27a5a40 100644 --- a/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java +++ b/src/org/torproject/descriptor/impl/RelayOrBridgeDescriptorReaderImpl.java @@ -24,9 +24,11 @@ import org.torproject.descriptor.Descriptor; import org.torproject.descriptor.DescriptorFile; import org.torproject.descriptor.RelayDescriptorReader; import org.torproject.descriptor.BridgeDescriptorReader; +import org.torproject.descriptor.BridgePoolAssignmentReader;
public class RelayOrBridgeDescriptorReaderImpl - implements RelayDescriptorReader, BridgeDescriptorReader { + implements RelayDescriptorReader, BridgeDescriptorReader, + BridgePoolAssignmentReader {
private List<File> directories = new ArrayList<File>(); public void addDirectory(File directory) {