[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] [ernie/master] Add consensus health web page.
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date: Fri, 16 Apr 2010 01:08:25 +0200
Subject: Add consensus health web page.
Commit: 7037ef309351fceed9cf9de7e74fca2795f0320f
---
config | 4 +
src/Configuration.java | 11 +-
src/ConsensusHealthChecker.java | 441 +++++++++++++++++++++++++++++++++++++++
src/Main.java | 17 ++-
src/RelayDescriptorParser.java | 17 ++-
5 files changed, 481 insertions(+), 9 deletions(-)
create mode 100644 src/ConsensusHealthChecker.java
diff --git a/config b/config
index 1581a09..967403e 100644
--- a/config
+++ b/config
@@ -80,6 +80,10 @@
## JDBC string for relay descriptor database
#RelayDescriptorDatabaseJDBC jdbc:postgresql://localhost/tordir?user=ernie&password=password
#
+## Write statistics about the current consensus and votes to the
+## website
+#WriteConsensusHealth 0
+#
## Write sanitized bridges to disk
#WriteSanitizedBridges 0
#
diff --git a/src/Configuration.java b/src/Configuration.java
index 9bb8bb6..1db6f28 100644
--- a/src/Configuration.java
+++ b/src/Configuration.java
@@ -53,6 +53,7 @@ public class Configuration {
private String geoIPDatabasesDirectory = "geoipdb/";
private boolean downloadGeoIPDatabase = false;
private String maxmindLicenseKey = "";
+ private boolean writeConsensusHealth = false;
public Configuration() {
/* Initialize logger. */
@@ -191,6 +192,9 @@ public class Configuration {
line.split(" ")[1]) != 0;
} else if (line.startsWith("MaxmindLicenseKey")) {
this.maxmindLicenseKey = line.split(" ")[1];
+ } else if (line.startsWith("WriteConsensusHealth")) {
+ this.writeConsensusHealth = Integer.parseInt(
+ line.split(" ")[1]) != 0;
} else {
logger.severe("Configuration file contains unrecognized "
+ "configuration key in line '" + line + "'! Exiting!");
@@ -226,7 +230,7 @@ public class Configuration {
!this.writeRelayDescriptorDatabase &&
!this.writeSanitizedBridges && !this.writeConsensusStats &&
!this.writeDirreqStats && !this.writeBridgeStats &&
- !this.writeServerDescriptorStats) {
+ !this.writeServerDescriptorStats && !this.writeConsensusHealth) {
logger.warning("We have not been configured to read data from any "
+ "data source or write data to any data sink. You need to "
+ "edit your config file (" + configFile.getAbsolutePath()
@@ -238,7 +242,7 @@ public class Configuration {
!(this.writeDirectoryArchives ||
this.writeRelayDescriptorDatabase || this.writeConsensusStats ||
this.writeDirreqStats || this.writeBridgeStats ||
- this.writeServerDescriptorStats)) {
+ this.writeServerDescriptorStats || this.writeConsensusHealth)) {
logger.warning("We are configured to import/download relay "
+ "descriptors, but we don't have a single data sink to write "
+ "relay descriptors to.");
@@ -376,5 +380,8 @@ public class Configuration {
public String getMaxmindLicenseKey() {
return this.maxmindLicenseKey;
}
+ public boolean getWriteConsensusHealth() {
+ return this.writeConsensusHealth;
+ }
}
diff --git a/src/ConsensusHealthChecker.java b/src/ConsensusHealthChecker.java
new file mode 100644
index 0000000..f62e0b4
--- /dev/null
+++ b/src/ConsensusHealthChecker.java
@@ -0,0 +1,441 @@
+import java.io.*;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/*
+ * TODO Possible extensions:
+ * - Include consensus signatures and tell by which Tor versions the
+ * consensus will be accepted (and by which not)
+ */
+public class ConsensusHealthChecker {
+
+ private String mostRecentValidAfterTime = null;
+
+ private byte[] mostRecentConsensus = null;
+
+ private SortedMap<String, byte[]> mostRecentVotes =
+ new TreeMap<String, byte[]>();
+
+ public void processConsensus(String validAfterTime, byte[] data) {
+ if (this.mostRecentValidAfterTime == null ||
+ this.mostRecentValidAfterTime.compareTo(validAfterTime) < 0) {
+ this.mostRecentValidAfterTime = validAfterTime;
+ this.mostRecentVotes.clear();
+ this.mostRecentConsensus = data;
+ }
+ }
+
+ public void processVote(String validAfterTime, String dirSource,
+ byte[] data) {
+ if (this.mostRecentValidAfterTime == null ||
+ this.mostRecentValidAfterTime.compareTo(validAfterTime) < 0) {
+ this.mostRecentValidAfterTime = validAfterTime;
+ this.mostRecentVotes.clear();
+ this.mostRecentConsensus = null;
+ }
+ if (this.mostRecentValidAfterTime.equals(validAfterTime)) {
+ this.mostRecentVotes.put(dirSource, data);
+ }
+ }
+
+ public void writeStatusWebsite() {
+
+ /* If we don't have any consensus, we cannot write useful consensus
+ * health information to the website. Do not overwrite existing page
+ * with a warning, because we might just not have learned about a new
+ * consensus in this execution. */
+ if (this.mostRecentConsensus == null) {
+ return;
+ }
+
+ /* Prepare parsing dates. */
+ SimpleDateFormat dateTimeFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ StringBuilder knownFlagsResults = new StringBuilder();
+ StringBuilder consensusMethodsResults = new StringBuilder();
+ StringBuilder versionsResults = new StringBuilder();
+ StringBuilder paramsResults = new StringBuilder();
+ StringBuilder authorityKeysResults = new StringBuilder();
+ StringBuilder bandwidthScannersResults = new StringBuilder();
+
+ /* Read consensus and parse all information that we want to compare to
+ * votes. */
+ String consensusConsensusMethod = null, consensusKnownFlags = null,
+ consensusClientVersions = null, consensusServerVersions = null,
+ consensusParams = null;
+ Scanner s = new Scanner(new String(this.mostRecentConsensus));
+ while (s.hasNextLine()) {
+ String line = s.nextLine();
+ if (line.startsWith("consensus-method ")) {
+ consensusConsensusMethod = line;
+ } else if (line.startsWith("client-versions ")) {
+ consensusClientVersions = line;
+ } else if (line.startsWith("server-versions ")) {
+ consensusServerVersions = line;
+ } else if (line.startsWith("known-flags ")) {
+ consensusKnownFlags = line;
+ } else if (line.startsWith("params ")) {
+ consensusParams = line;
+ }
+ }
+ s.close();
+
+ /* Read votes and parse all information to compare with the
+ * consensus. */
+ for (byte[] voteBytes : this.mostRecentVotes.values()) {
+ String voteConsensusMethods = null, voteKnownFlags = null,
+ voteClientVersions = null, voteServerVersions = null,
+ voteParams = null, voteDirSourceLine = null,
+ voteDirKeyExpires = null;
+ int voteContainsBandwidthWeights = 0;
+ s = new Scanner(new String(voteBytes));
+ while (s.hasNextLine()) {
+ String line = s.nextLine();
+ if (line.startsWith("consensus-methods ")) {
+ voteConsensusMethods = line;
+ } else if (line.startsWith("client-versions ")) {
+ voteClientVersions = line;
+ } else if (line.startsWith("server-versions ")) {
+ voteServerVersions = line;
+ } else if (line.startsWith("known-flags ")) {
+ voteKnownFlags = line;
+ } else if (line.startsWith("params ")) {
+ voteParams = line;
+ } else if (line.startsWith("dir-source ")) {
+ voteDirSourceLine = line;
+ } else if (line.startsWith("dir-key-expires ")) {
+ voteDirKeyExpires = line;
+ } else if (line.startsWith("w ")) {
+ if (line.contains(" Measured")) {
+ voteContainsBandwidthWeights++;
+ }
+ }
+ }
+ s.close();
+
+ /* Remember authority nickname. */
+ String dirSource = voteDirSourceLine.split(" ")[1];
+
+ /* Write known flags. */
+ knownFlagsResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteKnownFlags + "</td>\n"
+ + " </tr>\n");
+
+ /* Write supported consensus methods. */
+ if (!voteConsensusMethods.contains(consensusConsensusMethod.
+ split(" ")[1])) {
+ consensusMethodsResults.append(" <tr>\n"
+ + " <td><font color=\"red\">" + dirSource
+ + "</font></td>\n"
+ + " <td><font color=\"red\">"
+ + voteConsensusMethods + "</font></td>\n"
+ + " </tr>\n");
+ } else {
+ consensusMethodsResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteConsensusMethods + "</td>\n"
+ + " </tr>\n");
+ }
+
+ /* Write recommended versions. */
+ if (voteClientVersions == null) {
+ /* Not a versioning authority. */
+ } else if (!voteClientVersions.equals(consensusClientVersions)) {
+ versionsResults.append(" <tr>\n"
+ + " <td><font color=\"red\">" + dirSource
+ + "</font></td>\n"
+ + " <td><font color=\"red\">"
+ + voteClientVersions + "</font></td>\n"
+ + " </tr>\n");
+ } else {
+ versionsResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteClientVersions + "</td>\n"
+ + " </tr>\n");
+ }
+ if (voteServerVersions == null) {
+ /* Not a versioning authority. */
+ } else if (!voteServerVersions.equals(consensusServerVersions)) {
+ versionsResults.append(" <tr>\n"
+ + " <td/>\n"
+ + " <td><font color=\"red\">"
+ + voteClientVersions + "</font></td>\n"
+ + " </tr>\n");
+ } else {
+ versionsResults.append(" <tr>\n"
+ + " <td/>\n"
+ + " <td>" + voteServerVersions + "</td>\n"
+ + " </tr>\n");
+ }
+
+ /* Write consensus parameters. */
+ if (voteParams == null) {
+ /* Authority doesn't set consensus parameters. */
+ } else if (!voteParams.equals(consensusParams)) {
+ paramsResults.append(" <tr>\n"
+ + " <td><font color=\"red\">" + dirSource
+ + "</font></td>\n"
+ + " <td><font color=\"red\">"
+ + voteParams + "</font></td>\n"
+ + " </tr>\n");
+ } else {
+ paramsResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteParams + "</td>\n"
+ + " </tr>\n");
+ }
+
+ /* Write authority key expiration date. */
+ if (voteDirKeyExpires != null) {
+ boolean expiresIn14Days = false;
+ try {
+ expiresIn14Days = (System.currentTimeMillis()
+ + 14L * 24L * 60L * 60L * 1000L >
+ dateTimeFormat.parse(voteDirKeyExpires.substring(
+ "dir-key-expires ".length())).getTime());
+ } catch (ParseException e) {
+ /* Can't parse the timestamp? Whatever. */
+ }
+ if (expiresIn14Days) {
+ authorityKeysResults.append(" <tr>\n"
+ + " <td><font color=\"red\">" + dirSource
+ + "</font></td>\n"
+ + " <td><font color=\"red\">"
+ + voteDirKeyExpires + "</font></td>\n"
+ + " </tr>\n");
+ } else {
+ authorityKeysResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteDirKeyExpires + "</td>\n"
+ + " </tr>\n");
+ }
+ }
+
+ /* Write results for bandwidth scanner status. */
+ if (voteContainsBandwidthWeights > 0) {
+ bandwidthScannersResults.append(" <tr>\n"
+ + " <td>" + dirSource + "</td>\n"
+ + " <td>" + voteContainsBandwidthWeights
+ + " Measured values in w lines<td/>\n"
+ + " </tr>\n");
+ }
+ }
+
+ try {
+
+ /* Start writing web page. */
+ BufferedWriter bw = new BufferedWriter(
+ new FileWriter("website/consensus-health.html"));
+ bw.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 "
+ + "Transitional//EN\">\n"
+ + "<html>\n"
+ + " <head>\n"
+ + " <title>Tor Metrics Portal: Consensus health</title>\n"
+ + " <meta http-equiv=Content-Type content=\"text/html; "
+ + "charset=iso-8859-1\">\n"
+ + " <link href=\"http://www.torproject.org/stylesheet-"
+ + "ltr.css\" type=text/css rel=stylesheet>\n"
+ + " <link href=\"http://www.torproject.org/favicon.ico\""
+ + " type=image/x-icon rel=\"shortcut icon\">\n"
+ + " </head>\n"
+ + " <body>\n"
+ + " <div class=\"center\">\n"
+ + " <table class=\"banner\" border=\"0\" "
+ + "cellpadding=\"0\" cellspacing=\"0\" summary=\"\">\n"
+ + " <tr>\n"
+ + " <td class=\"banner-left\"><a href=\"https://"
+ + "www.torproject.org/\"><img src=\"http://www.torproject"
+ + ".org/images/top-left.png\" alt=\"Click to go to home "
+ + "page\" width=\"193\" height=\"79\"></a></td>\n"
+ + " <td class=\"banner-middle\">\n"
+ + " <a href=\"/\">Home</a>\n"
+ + " <a href=\"graphs.html\">Graphs</a>\n"
+ + " <a href=\"reports.html\">Reports</a>\n"
+ + " <a href=\"papers.html\">Papers</a>\n"
+ + " <a href=\"data.html\">Data</a>\n"
+ + " <a href=\"tools.html\">Tools</a>\n"
+ + " </td>\n"
+ + " <td class=\"banner-right\"></td>\n"
+ + " </tr>\n"
+ + " </table>\n"
+ + " <div class=\"main-column\">\n"
+ + " <h2>Tor Metrics Portal: Consensus Health</h2>\n"
+ + " <br/>\n"
+ + " <p>This page shows statistics about the current "
+ + "consensus and votes to facilitate debugging of the "
+ + "directory consensus process.</p>\n");
+
+ /* Write valid-after time. */
+ bw.write(" <br/>\n"
+ + " <h3>Valid-after time</h3>\n"
+ + " <br/>\n"
+ + " <p>Consensus was published ");
+ boolean consensusIsStale = false;
+ try {
+ consensusIsStale = System.currentTimeMillis()
+ - 3L * 60L * 60L * 1000L >
+ dateTimeFormat.parse(this.mostRecentValidAfterTime).getTime();
+ } catch (ParseException e) {
+ /* Can't parse the timestamp? Whatever. */
+ }
+ if (consensusIsStale) {
+ bw.write("<font color=\"red\">" + this.mostRecentValidAfterTime
+ + "</font>");
+ } else {
+ bw.write(this.mostRecentValidAfterTime);
+ }
+ bw.write(". <i>Note that it takes "
+ + "15 to 30 minutes for the metrics portal to learn about "
+ + "new consensus and votes and process them.</i></p>\n");
+
+ /* Write known flags. */
+ bw.write(" <br/>\n"
+ + " <h3>Known flags</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (knownFlagsResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(knownFlagsResults.toString());
+ }
+ bw.write(" <td><font color=\"blue\">consensus</font>"
+ + "</td>\n"
+ + " <td><font color=\"blue\">"
+ + consensusKnownFlags + "</font></td>\n"
+ + " </tr>\n");
+ bw.write(" </table>\n");
+
+ /* Write consensus methods. */
+ bw.write(" <br/>\n"
+ + " <h3>Consensus methods</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (consensusMethodsResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(consensusMethodsResults.toString());
+ }
+ bw.write(" <td><font color=\"blue\">consensus</font>"
+ + "</td>\n"
+ + " <td><font color=\"blue\">"
+ + consensusConsensusMethod + "</font></td>\n"
+ + " </tr>\n");
+ bw.write(" </table>\n");
+
+ /* Write recommended versions. */
+ bw.write(" <br/>\n"
+ + " <h3>Recommended versions</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (versionsResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(versionsResults.toString());
+ }
+ bw.write(" <td><font color=\"blue\">consensus</font>"
+ + "</td>\n"
+ + " <td><font color=\"blue\">"
+ + consensusClientVersions + "</font></td>\n"
+ + " </tr>\n");
+ bw.write(" <td/>\n"
+ + " <td><font color=\"blue\">"
+ + consensusServerVersions + "</font></td>\n"
+ + " </tr>\n");
+ bw.write(" </table>\n");
+
+ /* Write consensus parameters. */
+ bw.write(" <br/>\n"
+ + " <h3>Consensus parameters</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (paramsResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(paramsResults.toString());
+ }
+ bw.write(" <td><font color=\"blue\">consensus</font>"
+ + "</td>\n"
+ + " <td><font color=\"blue\">"
+ + consensusParams + "</font></td>\n"
+ + " </tr>\n");
+ bw.write(" </table>\n");
+
+ /* Write authority keys. */
+ bw.write(" <br/>\n"
+ + " <h3>Authority keys</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (authorityKeysResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(authorityKeysResults.toString());
+ }
+ bw.write(" </table>\n"
+ + " <br/>\n"
+ + " <p><i>Note that expiration dates of legacy keys are "
+ + "not included in votes and therefore not listed here!</i>"
+ + "</p>\n");
+
+ /* Write bandwidth scanner status. */
+ bw.write(" <br/>\n"
+ + " <h3>Bandwidth scanner status</h3>\n"
+ + " <br/>\n"
+ + " <table border=\"0\" cellpadding=\"4\" "
+ + "cellspacing=\"0\" summary=\"\">\n"
+ + " <colgroup>\n"
+ + " <col width=\"160\">\n"
+ + " <col width=\"640\">\n"
+ + " </colgroup>\n");
+ if (bandwidthScannersResults.length() < 1) {
+ bw.write(" <tr><td>(No votes.)</td><td/></tr>\n");
+ } else {
+ bw.write(bandwidthScannersResults.toString());
+ }
+ bw.write(" </table>\n");
+
+ /* Finish writing. */
+ bw.write(" </div>\n"
+ + " </div>\n"
+ + " <div class=\"bottom\" id=\"bottom\">\n"
+ + " <p>\"Tor\" and the \"Onion Logo\" are <a "
+ + "href=\"https://www.torproject.org/trademark-faq.html"
+ + ".en\">"
+ + "registered trademarks</a> of The Tor Project, "
+ + "Inc.</p>\n"
+ + " </div>\n"
+ + " </body>\n"
+ + "</html>");
+ bw.close();
+
+ } catch (IOException e) {
+ }
+ }
+}
diff --git a/src/Main.java b/src/Main.java
index 7be5643..e7adcb5 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -41,6 +41,10 @@ public class Main {
new ServerDescriptorStatsFileHandler(config.getRelayVersions(),
config.getRelayPlatforms()) : null;
+ // Prepare consensus health checker
+ ConsensusHealthChecker chc = config.getWriteConsensusHealth() ?
+ new ConsensusHealthChecker() : null;
+
// Prepare writing relay descriptor archive to disk
ArchiveWriter aw = config.getWriteDirectoryArchives() ?
new ArchiveWriter(config.getDirectoryArchivesOutputDirectory())
@@ -58,8 +62,9 @@ public class Main {
config.getWriteBridgeStats() || config.getWriteDirreqStats() ||
config.getWriteServerDescriptorStats() ||
config.getWriteDirectoryArchives() ||
- config.getWriteRelayDescriptorDatabase() ?
- new RelayDescriptorParser(csfh, bsfh, dsfh, sdsfh, aw, rddi,
+ config.getWriteRelayDescriptorDatabase() ||
+ config.getWriteConsensusHealth() ?
+ new RelayDescriptorParser(csfh, bsfh, dsfh, sdsfh, aw, rddi, chc,
countries, directories) : null;
// Import/download relay descriptors from the various sources
@@ -69,8 +74,8 @@ public class Main {
List<String> dirSources =
config.getDownloadFromDirectoryAuthorities();
boolean downloadCurrentConsensus = aw != null || csfh != null ||
- bsfh != null || sdsfh != null || rddi != null;
- boolean downloadCurrentVotes = aw != null;
+ bsfh != null || sdsfh != null || rddi != null || chc != null;
+ boolean downloadCurrentVotes = aw != null || chc != null;
boolean downloadAllServerDescriptors = aw != null ||
sdsfh != null || rddi != null;
boolean downloadAllExtraInfos = aw != null;
@@ -109,6 +114,10 @@ public class Main {
}
// Write output to disk that only depends on relay descriptors
+ if (chc != null) {
+ chc.writeStatusWebsite();
+ chc = null;
+ }
if (aw != null) {
aw.dumpStats();
aw = null;
diff --git a/src/RelayDescriptorParser.java b/src/RelayDescriptorParser.java
index 26435ef..ff708d6 100644
--- a/src/RelayDescriptorParser.java
+++ b/src/RelayDescriptorParser.java
@@ -54,6 +54,8 @@ public class RelayDescriptorParser {
*/
private RelayDescriptorDatabaseImporter rddi;
+ private ConsensusHealthChecker chc;
+
/**
* Countries that we care about for directory request and bridge
* statistics.
@@ -76,14 +78,15 @@ public class RelayDescriptorParser {
public RelayDescriptorParser(ConsensusStatsFileHandler csfh,
BridgeStatsFileHandler bsfh, DirreqStatsFileHandler dsfh,
ServerDescriptorStatsFileHandler sdsfh, ArchiveWriter aw,
- RelayDescriptorDatabaseImporter rddi, SortedSet<String> countries,
- SortedSet<String> directories) {
+ RelayDescriptorDatabaseImporter rddi, ConsensusHealthChecker chc,
+ SortedSet<String> countries, SortedSet<String> directories) {
this.csfh = csfh;
this.bsfh = bsfh;
this.dsfh = dsfh;
this.sdsfh = sdsfh;
this.aw = aw;
this.rddi = rddi;
+ this.chc = chc;
this.countries = countries;
this.directories = directories;
@@ -192,6 +195,9 @@ public class RelayDescriptorParser {
if (this.aw != null) {
this.aw.storeConsensus(data, validAfter);
}
+ if (this.chc != null) {
+ this.chc.processConsensus(validAfterTime, data);
+ }
} else {
if (this.rdd != null) {
this.rdd.haveParsedVote(validAfterTime, fingerprint,
@@ -208,9 +214,14 @@ public class RelayDescriptorParser {
byte[] forDigest = new byte[sig - start];
System.arraycopy(data, start, forDigest, 0, sig - start);
String digest = DigestUtils.shaHex(forDigest).toUpperCase();
- this.aw.storeVote(data, validAfter, dirSource, digest);
+ if (this.aw != null) {
+ this.aw.storeVote(data, validAfter, dirSource, digest);
+ }
}
}
+ if (this.chc != null) {
+ this.chc.processVote(validAfterTime, dirSource, data);
+ }
}
} else if (line.startsWith("router ")) {
String platformLine = null, publishedLine = null,
--
1.6.5