[tor-commits] [metrics-web/master] Remove consensus-health checker.
karsten at torproject.org
karsten at torproject.org
Tue Dec 6 06:28:22 UTC 2011
commit 8af25f86effec8bb9b7a577310cc569adb2879cc
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date: Mon Dec 5 20:23:44 2011 +0100
Remove consensus-health checker.
---
build.xml | 11 -
src/org/torproject/chc/Checker.java | 285 -------
src/org/torproject/chc/Downloader.java | 251 -------
src/org/torproject/chc/Main.java | 46 --
src/org/torproject/chc/MetricsWebsiteReport.java | 875 ----------------------
src/org/torproject/chc/Parser.java | 167 ----
src/org/torproject/chc/Report.java | 23 -
src/org/torproject/chc/Status.java | 176 -----
src/org/torproject/chc/StatusEntry.java | 48 --
src/org/torproject/chc/StatusFileReport.java | 197 -----
src/org/torproject/chc/Warning.java | 46 --
11 files changed, 0 insertions(+), 2125 deletions(-)
diff --git a/build.xml b/build.xml
index 570c973..e148a13 100644
--- a/build.xml
+++ b/build.xml
@@ -21,7 +21,6 @@
<copy file="${contextxmltemplate}" tofile="${contextxml}"/>
<copy file="config.template" tofile="config"/>
<mkdir dir="${classes}"/>
- <mkdir dir="website"/>
</target>
<!-- Compile all servlets and plain Java classes. -->
@@ -60,16 +59,6 @@
</java>
</target>
- <!-- Run consensus-health checker. -->
- <target name="chc" depends="compile">
- <java fork="true"
- maxmemory="512m"
- classname="org.torproject.chc.Main"
- error="chc-stderr.txt">
- <classpath refid="classpath"/>
- </java>
- </target>
-
<!-- Prepare data for being displayed on the website. -->
<target name="run" depends="compile">
<java fork="true"
diff --git a/src/org/torproject/chc/Checker.java b/src/org/torproject/chc/Checker.java
deleted file mode 100644
index 02c70b7..0000000
--- a/src/org/torproject/chc/Checker.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-
-/* Check a given consensus and votes for irregularities and write results
- * to a warnings map consisting of warning type and details. */
-public class Checker {
-
- /* Warning messages consisting of type and details. */
- private SortedMap<Warning, String> warnings =
- new TreeMap<Warning, String>();
-
- public SortedMap<Warning, String> getWarnings() {
- return this.warnings;
- }
-
- /* Date-time format to format timestamps. */
- private static SimpleDateFormat dateTimeFormat;
- static {
- dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /* Downloaded consensus and corresponding votes for processing. */
- private SortedMap<String, Status> downloadedConsensuses;
- private Status downloadedConsensus;
- private SortedSet<Status> downloadedVotes;
- public void processDownloadedConsensuses(
- SortedMap<String, Status> downloadedConsensuses) {
- this.downloadedConsensuses = downloadedConsensuses;
- this.findMostRecentConsensus();
- this.checkMissingConsensuses();
- this.checkAllConsensusesFresh();
- if (this.downloadedConsensus != null) {
- if (this.isConsensusFresh(this.downloadedConsensus)) {
- this.checkConsensusMethods();
- this.checkRecommendedVersions();
- this.checkConsensusParameters();
- this.checkAuthorityKeys();
- this.checkMissingVotes();
- this.checkBandwidthScanners();
- }
- } else {
- this.warnings.put(Warning.NoConsensusKnown, "");
- }
- }
-
- /* Find most recent consensus and corresponding votes. */
- private void findMostRecentConsensus() {
- long mostRecentValidAfterMillis = -1L;
- for (Status downloadedConsensus : downloadedConsensuses.values()) {
- if (downloadedConsensus.getValidAfterMillis() >
- mostRecentValidAfterMillis) {
- this.downloadedConsensus = downloadedConsensus;
- mostRecentValidAfterMillis =
- downloadedConsensus.getValidAfterMillis();
- }
- }
- if (this.downloadedConsensus != null) {
- this.downloadedVotes = this.downloadedConsensus.getVotes();
- }
- }
-
- /* Check if any directory authority didn't tell us a consensus. */
- private void checkMissingConsensuses() {
- SortedSet<String> missingConsensuses = new TreeSet<String>(
- Arrays.asList(("gabelmoo,tor26,ides,maatuska,dannenberg,urras,"
- + "moria1,dizum").split(",")));
- missingConsensuses.removeAll(this.downloadedConsensuses.keySet());
- if (!missingConsensuses.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String nickname : missingConsensuses) {
- sb.append(", " + nickname);
- }
- this.warnings.put(Warning.ConsensusDownloadTimeout,
- sb.toString().substring(2));
- }
- }
-
- /* Check if all consensuses are fresh. */
- private void checkAllConsensusesFresh() {
- long fresh = System.currentTimeMillis() - 60L * 60L * 1000L;
- SortedSet<String> nonFresh = new TreeSet<String>();
- for (Map.Entry<String, Status> e : downloadedConsensuses.entrySet()) {
- String nickname = e.getKey();
- Status downloadedConsensus = e.getValue();
- if (downloadedConsensus.getValidAfterMillis() < fresh) {
- nonFresh.add(nickname);
- }
- }
- if (!nonFresh.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String nickname : nonFresh) {
- sb.append(", " + nickname);
- }
- this.warnings.put(Warning.ConsensusNotFresh,
- sb.toString().substring(2));
- }
- }
-
- /* Check if the most recent consensus is older than 1 hour. */
- private boolean isConsensusFresh(Status consensus) {
- return (consensus.getValidAfterMillis() >=
- System.currentTimeMillis() - 60L * 60L * 1000L);
- }
-
- /* Check supported consensus methods of all votes. */
- private void checkConsensusMethods() {
- SortedSet<String> dirs = new TreeSet<String>();
- for (Status vote : this.downloadedVotes) {
- if (!vote.getConsensusMethods().contains(
- this.downloadedConsensus.getConsensusMethods().last())) {
- dirs.add(vote.getNickname());
- }
- }
- if (!dirs.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String dir : dirs) {
- sb.append(", " + dir);
- }
- this.warnings.put(Warning.ConsensusMethodNotSupported,
- sb.toString().substring(2));
- }
- }
-
- /* Check if the recommended versions in a vote are different from the
- * recommended versions in the consensus. */
- private void checkRecommendedVersions() {
- SortedSet<String> unrecommendedClientVersions = new TreeSet<String>(),
- unrecommendedServerVersions = new TreeSet<String>();
- for (Status vote : this.downloadedVotes) {
- if (vote.getRecommendedClientVersions() != null &&
- !downloadedConsensus.getRecommendedClientVersions().equals(
- vote.getRecommendedClientVersions())) {
- StringBuilder message = new StringBuilder();
- message.append(vote.getNickname());
- for (String version : vote.getRecommendedClientVersions()) {
- message.append(" " + version);
- }
- unrecommendedClientVersions.add(message.toString());
- }
- if (vote.getRecommendedServerVersions() != null &&
- !downloadedConsensus.getRecommendedServerVersions().equals(
- vote.getRecommendedServerVersions())) {
- StringBuilder message = new StringBuilder();
- message.append(vote.getNickname());
- for (String version : vote.getRecommendedServerVersions()) {
- message.append(" " + version);
- }
- unrecommendedServerVersions.add(message.toString());
- }
- }
- if (!unrecommendedServerVersions.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String dir : unrecommendedServerVersions) {
- sb.append(", " + dir);
- }
- this.warnings.put(Warning.DifferentRecommendedServerVersions,
- sb.toString().substring(2));
- }
- if (!unrecommendedClientVersions.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String dir : unrecommendedClientVersions) {
- sb.append(", " + dir);
- }
- this.warnings.put(Warning.DifferentRecommendedClientVersions,
- sb.toString().substring(2));
- }
- }
-
- /* Check if a vote contains conflicting or invalid consensus
- * parameters. */
- private void checkConsensusParameters() {
- Set<String> validParameters = new HashSet<String>(Arrays.asList(
- ("circwindow,CircuitPriorityHalflifeMsec,refuseunknownexits,"
- + "cbtdisabled,cbtnummodes,cbtrecentcount,cbtmaxtimeouts,"
- + "cbtmincircs,cbtquantile,cbtclosequantile,cbttestfreq,"
- + "cbtmintimeout,cbtinitialtimeout,perconnbwburst,perconnbwrate").
- split(",")));
- SortedSet<String> conflicts = new TreeSet<String>();
- for (Status vote : this.downloadedVotes) {
- Map<String, String> voteConsensusParams =
- vote.getConsensusParams();
- boolean conflictOrInvalid = false;
- if (voteConsensusParams != null) {
- for (Map.Entry<String, String> e :
- voteConsensusParams.entrySet()) {
- if (!downloadedConsensus.getConsensusParams().containsKey(
- e.getKey()) ||
- !downloadedConsensus.getConsensusParams().get(e.getKey()).
- equals(e.getValue()) ||
- (!validParameters.contains(e.getKey()) &&
- !e.getKey().startsWith("bwauth"))) {
- StringBuilder message = new StringBuilder();
- message.append(vote.getNickname());
- for (Map.Entry<String, String> p :
- voteConsensusParams.entrySet()) {
- message.append(" " + p.getKey() + "=" + p.getValue());
- }
- conflicts.add(message.toString());
- break;
- }
- }
- }
- }
- if (!conflicts.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String dir : conflicts) {
- sb.append(", " + dir);
- }
- this.warnings.put(Warning.ConflictingOrInvalidConsensusParams,
- sb.toString().substring(2));
- }
- }
-
- /* Check whether any of the authority keys expire in the next 14
- * days. */
- private void checkAuthorityKeys() {
- SortedMap<String, String> expiringCertificates =
- new TreeMap<String, String>();
- long now = System.currentTimeMillis();
- for (Status vote : this.downloadedVotes) {
- long voteDirKeyExpiresMillis = vote.getDirKeyExpiresMillis();
- if (voteDirKeyExpiresMillis - 14L * 24L * 60L * 60L * 1000L < now) {
- expiringCertificates.put(vote.getNickname(),
- dateTimeFormat.format(voteDirKeyExpiresMillis));
- }
- }
- if (!expiringCertificates.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (Map.Entry<String, String> e :
- expiringCertificates.entrySet()) {
- String dir = e.getKey();
- String timestamp = e.getValue();
- sb.append(", " + dir + " " + timestamp);
- }
- this.warnings.put(Warning.CertificateExpiresSoon,
- sb.toString().substring(2));
- }
- }
-
- /* Check if any votes are missing. */
- private void checkMissingVotes() {
- SortedSet<String> knownAuthorities = new TreeSet<String>(
- Arrays.asList(("dannenberg,dizum,gabelmoo,ides,maatuska,moria1,"
- + "tor26,urras").split(",")));
- SortedSet<String> missingVotes =
- new TreeSet<String>(knownAuthorities);
- for (Status vote : this.downloadedVotes) {
- missingVotes.remove(vote.getNickname());
- }
- if (!missingVotes.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String missingDir : missingVotes) {
- sb.append(", " + missingDir);
- }
- this.warnings.put(Warning.VotesMissing,
- sb.toString().substring(2));
- }
- }
-
- /* Check if any bandwidth scanner results are missing. */
- private void checkBandwidthScanners() {
- SortedSet<String> missingBandwidthScanners = new TreeSet<String>(
- Arrays.asList("ides,urras,moria1,gabelmoo,maatuska".split(",")));
- for (Status vote : this.downloadedVotes) {
- if (vote.getBandwidthWeights() > 0) {
- missingBandwidthScanners.remove(vote.getNickname());
- }
- }
- if (!missingBandwidthScanners.isEmpty()) {
- StringBuilder sb = new StringBuilder();
- for (String dir : missingBandwidthScanners) {
- sb.append(", " + dir);
- }
- this.warnings.put(Warning.BandwidthScannerResultsMissing,
- sb.toString().substring(2));
- }
- }
-}
-
diff --git a/src/org/torproject/chc/Downloader.java b/src/org/torproject/chc/Downloader.java
deleted file mode 100644
index e56d20d..0000000
--- a/src/org/torproject/chc/Downloader.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.io.*;
-import java.net.*;
-import java.text.*;
-import java.util.*;
-import java.util.zip.*;
-
-/* Download the latest network status consensus and corresponding
- * votes. */
-public class Downloader {
-
- /* List of directory authorities to download consensuses and votes
- * from. */
- private SortedMap<String, String> authorities =
- new TreeMap<String, String>();
- public Downloader() {
- this.authorities.put("gabelmoo", "212.112.245.170");
- this.authorities.put("tor26", "86.59.21.38");
- this.authorities.put("ides", "216.224.124.114:9030");
- this.authorities.put("maatuska", "213.115.239.118:443");
- this.authorities.put("dannenberg", "193.23.244.244");
- this.authorities.put("urras", "208.83.223.34:443");
- this.authorities.put("moria1", "128.31.0.34:9131");
- this.authorities.put("dizum", "194.109.206.212");
- }
-
- /* Download a new consensus and corresponding votes. */
- public void downloadFromAuthorities() {
- this.downloadConsensus();
- if (!this.downloadedConsensuses.isEmpty()) {
- this.parseConsensusToFindReferencedVotes();
- this.downloadReferencedVotes();
- }
- }
-
- /* Download the most recent consensus from all authorities. */
- private SortedMap<String, String> downloadedConsensuses =
- new TreeMap<String, String>();
- private void downloadConsensus() {
- Map<String, String> urls = new HashMap<String, String>();
- for (Map.Entry<String, String> e : this.authorities.entrySet()) {
- String nickname = e.getKey();
- String address = e.getValue();
- String resource = "/tor/status-vote/current/consensus.z";
- String fullUrl = "http://" + address + resource;
- urls.put(nickname, fullUrl);
- }
- Map<String, String> responses =
- this.downloadFromAuthority(new HashSet<String>(urls.values()));
- for (Map.Entry<String, String> e : urls.entrySet()) {
- String nickname = e.getKey();
- String url = e.getValue();
- if (responses.containsKey(url)) {
- String response = responses.get(url);
- this.downloadedConsensuses.put(nickname, response);
- } else {
- System.err.println("Could not download consensus from directory "
- + "authority " + nickname + ". Ignoring.");
- }
- }
- if (responses.isEmpty()) {
- System.err.println("Could not download consensus from any of the "
- + "directory authorities. Ignoring.");
- }
- }
-
- /* Downloads a consensus or vote in a separate thread that can be
- * interrupted after a timeout. */
- private static class DownloadRunnable implements Runnable {
- Thread mainThread;
- String url;
- String response;
- boolean finished = false;
- public DownloadRunnable(String url) {
- this.mainThread = Thread.currentThread();
- this.url = url;
- }
- public void run() {
- try {
- URL u = new URL(this.url);
- HttpURLConnection huc = (HttpURLConnection) u.openConnection();
- huc.setRequestMethod("GET");
- huc.connect();
- int responseCode = huc.getResponseCode();
- if (responseCode == 200) {
- BufferedInputStream in = new BufferedInputStream(
- new InflaterInputStream(huc.getInputStream()));
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int len;
- byte[] data = new byte[1024];
- while (!this.finished &&
- (len = in.read(data, 0, 1024)) >= 0) {
- baos.write(data, 0, len);
- }
- if (this.finished) {
- return;
- }
- in.close();
- byte[] allData = baos.toByteArray();
- this.response = new String(allData);
- this.finished = true;
- this.mainThread.interrupt();
- }
- } catch (IOException e) {
- /* Can't do much except leaving this.response at null. */
- }
- this.finished = true;
- }
- }
-
- /* Download one or more consensuses or votes from one or more directory
- * authorities using a timeout of 60 seconds. */
- private Map<String, String> downloadFromAuthority(Set<String> urls) {
- Set<DownloadRunnable> downloadRunnables =
- new HashSet<DownloadRunnable>();
- for (String url : urls) {
- DownloadRunnable downloadRunnable = new DownloadRunnable(url);
- downloadRunnables.add(downloadRunnable);
- new Thread(downloadRunnable).start();
- }
- long started = System.currentTimeMillis(), sleep;
- while ((sleep = started + 60L * 1000L - System.currentTimeMillis())
- > 0L) {
- try {
- Thread.sleep(sleep);
- } catch (InterruptedException e) {
- /* Do nothing. */
- }
- boolean unfinished = false;
- for (DownloadRunnable downloadRunnable : downloadRunnables) {
- if (!downloadRunnable.finished) {
- unfinished = true;
- break;
- }
- }
- if (!unfinished) {
- break;
- }
- }
- Map<String, String> responses = new HashMap<String, String>();
- for (DownloadRunnable downloadRunnable : downloadRunnables) {
- String url = downloadRunnable.url;
- String response = downloadRunnable.response;
- if (response != null) {
- responses.put(url, response);
- }
- downloadRunnable.finished = true;
- }
- return responses;
- }
-
- /* Date-time formats to parse and format timestamps. */
- private static SimpleDateFormat dateTimeFormat;
- static {
- dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /* Parse the downloaded consensus to find fingerprints of directory
- * authorities publishing the corresponding votes. */
- private SortedSet<String> fingerprints = new TreeSet<String>();
- private void parseConsensusToFindReferencedVotes() {
- for (String downloadedConsensus :
- this.downloadedConsensuses.values()) {
- try {
- BufferedReader br = new BufferedReader(new StringReader(
- downloadedConsensus));
- String line;
- while ((line = br.readLine()) != null) {
- if (line.startsWith("valid-after ")) {
- try {
- long validAfterMillis = dateTimeFormat.parse(line.substring(
- "valid-after ".length())).getTime();
- if (validAfterMillis + 60L * 60L * 1000L <
- System.currentTimeMillis()) {
- /* Consensus is more than 1 hour old. We won't be able to
- * download the corresponding votes anymore. */
- break;
- }
- } catch (ParseException e) {
- System.err.println("Could not parse valid-after timestamp "
- + "in line '" + line + "' of a downloaded consensus. "
- + "Not downloading votes.");
- break;
- }
- } else if (line.startsWith("dir-source ")) {
- String[] parts = line.split(" ");
- if (parts.length < 3) {
- System.err.println("Bad dir-source line '" + line
- + "' in downloaded consensus. Skipping.");
- continue;
- }
- String nickname = parts[1];
- if (nickname.endsWith("-legacy")) {
- continue;
- }
- String fingerprint = parts[2];
- this.fingerprints.add(fingerprint);
- }
- }
- br.close();
- } catch (IOException e) {
- System.err.println("Could not parse consensus to find referenced "
- + "votes in it. Skipping.");
- }
- }
- }
-
- /* Download the votes published by directory authorities listed in the
- * consensus. */
- private List<String> downloadedVotes = new ArrayList<String>();
- private void downloadReferencedVotes() {
- for (String fingerprint : this.fingerprints) {
- String downloadedVote = null;
- List<String> authorities = new ArrayList<String>(
- this.authorities.values());
- Collections.shuffle(authorities);
- for (String authority : authorities) {
- if (downloadedVote != null) {
- break;
- }
- String resource = "/tor/status-vote/current/" + fingerprint
- + ".z";
- String fullUrl = "http://" + authority + resource;
- Set<String> urls = new HashSet<String>();
- urls.add(fullUrl);
- Map<String, String> downloadedVotes =
- this.downloadFromAuthority(urls);
- if (downloadedVotes.containsKey(fullUrl)) {
- downloadedVote = downloadedVotes.get(fullUrl);
- this.downloadedVotes.add(downloadedVote);
- }
- }
- }
- }
-
- /* Return the previously downloaded (unparsed) consensus string by
- * authority nickname. */
- public SortedMap<String, String> getConsensusStrings() {
- return this.downloadedConsensuses;
- }
-
- /* Return the previously downloaded (unparsed) vote strings. */
- public List<String> getVoteStrings() {
- return this.downloadedVotes;
- }
-}
-
diff --git a/src/org/torproject/chc/Main.java b/src/org/torproject/chc/Main.java
deleted file mode 100644
index a0a3c19..0000000
--- a/src/org/torproject/chc/Main.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.util.*;
-
-/* Coordinate the process of downloading consensus and votes to check
- * Tor's consensus health. */
-public class Main {
- public static void main(String[] args) {
-
- /* Initialize reports. */
- List<Report> reports = new ArrayList<Report>();
- reports.add(new MetricsWebsiteReport(
- "website/consensus-health.html"));
- reports.add(new StatusFileReport());
-
- /* Download consensus and corresponding votes from the directory
- * authorities. */
- Downloader downloader = new Downloader();
- downloader.downloadFromAuthorities();
-
- /* Parse consensus and votes. */
- Parser parser = new Parser();
- SortedMap<String, Status> parsedDownloadedConsensuses = parser.parse(
- downloader.getConsensusStrings(), downloader.getVoteStrings());
-
- /* Check consensus and votes for possible problems. */
- Checker checker = new Checker();
- checker.processDownloadedConsensuses(parsedDownloadedConsensuses);
- SortedMap<Warning, String> warnings = checker.getWarnings();
-
- /* Pass warnings, consensuses, and votes to the reports, and finish
- * writing them. */
- for (Report report : reports) {
- report.processWarnings(warnings);
- report.processDownloadedConsensuses(parsedDownloadedConsensuses);
- report.writeReport();
- }
-
- /* Terminate the program including any download threads that may still
- * be running. */
- System.exit(0);
- }
-}
-
diff --git a/src/org/torproject/chc/MetricsWebsiteReport.java b/src/org/torproject/chc/MetricsWebsiteReport.java
deleted file mode 100644
index 8aa52b5..0000000
--- a/src/org/torproject/chc/MetricsWebsiteReport.java
+++ /dev/null
@@ -1,875 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-
-/* Transform the most recent consensus and corresponding votes into an
- * HTML page showing possible irregularities. */
-public class MetricsWebsiteReport implements Report {
-
- /* Date-time format to format timestamps. */
- private static SimpleDateFormat dateTimeFormat;
- static {
- dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /* Output file to write report to. */
- private File htmlOutputFile;
-
- /* Initialize this report. */
- public MetricsWebsiteReport(String htmlOutputFilename) {
- this.htmlOutputFile = new File(htmlOutputFilename);
- }
-
- /* Process warnings. */
- public void processWarnings(SortedMap<Warning, String> warnings) {
- /* We could use these warnings instead of running all checks
- * ourselves. But we're not doing that yet. */
- }
-
- /* Store the downloaded consensus and corresponding votes for later
- * processing. */
- private Status downloadedConsensus;
- private SortedSet<Status> downloadedVotes;
- public void processDownloadedConsensuses(
- SortedMap<String, Status> downloadedConsensuses) {
- long mostRecentValidAfterMillis = -1L;
- for (Status downloadedConsensus : downloadedConsensuses.values()) {
- if (downloadedConsensus.getValidAfterMillis() >
- mostRecentValidAfterMillis) {
- this.downloadedConsensus = downloadedConsensus;
- mostRecentValidAfterMillis =
- downloadedConsensus.getValidAfterMillis();
- }
- }
- if (this.downloadedConsensus != null) {
- this.downloadedVotes = this.downloadedConsensus.getVotes();
- }
- }
-
- /* Writer to write all HTML output to. */
- private BufferedWriter bw;
-
- /* Write HTML output file for the metrics website. */
- public void writeReport() {
-
- if (this.downloadedConsensus != null) {
- try {
- this.htmlOutputFile.getParentFile().mkdirs();
- this.bw = new BufferedWriter(new FileWriter(this.htmlOutputFile));
- writePageHeader();
- writeValidAfterTime();
- writeKnownFlags();
- writeNumberOfRelaysVotedAbout();
- writeConsensusMethods();
- writeRecommendedVersions();
- writeConsensusParameters();
- writeAuthorityKeys();
- writeBandwidthScannerStatus();
- writeAuthorityVersions();
- writeRelayFlagsTable();
- writeRelayFlagsSummary();
- writePageFooter();
- this.bw.close();
- } catch (IOException e) {
- System.err.println("Could not write HTML output file '"
- + this.htmlOutputFile.getAbsolutePath() + "'. Ignoring.");
- }
- }
- }
-
- /* Write the HTML page header including the metrics website
- * navigation. */
- private void writePageHeader() throws IOException {
- this.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=\"/css/stylesheet-ltr.css\" type=\"text/css\" "
- + "rel=\"stylesheet\">\n"
- + " <link href=\"/images/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=\"/index.html\"><img src=\"/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=\"research.html\">Research</a>\n"
- + " <a href=\"status.html\">Status</a>\n"
- + " <br>\n"
- + " <font size=\"2\">\n"
- + " <a href=\"networkstatus.html\">Network "
- + "Status</a>\n"
- + " <a href=\"exonerator.html\">ExoneraTor</a>\n"
- + " <a href=\"relay-search.html\">Relay Search</a>\n"
- + " <a class=\"current\">Consensus Health</a>\n"
- + " </font>\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 the valid-after time of the downloaded consensus. */
- private void writeValidAfterTime() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"validafter\">\n"
- + " <h3><a href=\"#validafter\" class=\"anchor\">"
- + "Valid-after time</a></h3>\n"
- + " <br>\n"
- + " <p>Consensus was published ");
- if (this.downloadedConsensus.getValidAfterMillis() <
- System.currentTimeMillis() - 3L * 60L * 60L * 1000L) {
- this.bw.write("<font color=\"red\">"
- + dateTimeFormat.format(
- this.downloadedConsensus.getValidAfterMillis()) + "</font>");
- } else {
- this.bw.write(dateTimeFormat.format(
- this.downloadedConsensus.getValidAfterMillis()));
- }
- this.bw.write(". <i>Note that it takes up to 15 to learn about new "
- + "consensus and votes and process them.</i></p>\n");
- }
-
- /* Write the lists of known flags. */
- private void writeKnownFlags() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"knownflags\">\n"
- + " <h3><a href=\"#knownflags\" class=\"anchor\">Known "
- + "flags</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>known-flags");
- for (String knownFlag : vote.getKnownFlags()) {
- this.bw.write(" " + knownFlag);
- }
- this.bw.write("</td>\n"
- + " </tr>\n");
- }
- }
- this.bw.write(" <tr>\n"
- + " <td><font color=\"blue\">consensus</font>"
- + "</td>\n"
- + " <td><font color=\"blue\">known-flags");
- for (String knownFlag : this.downloadedConsensus.getKnownFlags()) {
- this.bw.write(" " + knownFlag);
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n"
- + " </table>\n");
- }
-
- /* Write the number of relays voted about. */
- private void writeNumberOfRelaysVotedAbout() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"numberofrelays\">\n"
- + " <h3><a href=\"#numberofrelays\" class=\"anchor\">"
- + "Number of relays voted about</a></h3>\n"
- + " <br>\n"
- + " <table border=\"0\" cellpadding=\"4\" "
- + "cellspacing=\"0\" summary=\"\">\n"
- + " <colgroup>\n"
- + " <col width=\"160\">\n"
- + " <col width=\"320\">\n"
- + " <col width=\"320\">\n"
- + " </colgroup>\n");
- if (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td><td></td>"
- + "</tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>" + vote.getStatusEntries().size()
- + " total</td>\n"
- + " <td>" + vote.getRunningRelays()
- + " Running</td>\n"
- + " </tr>\n");
- }
- }
- this.bw.write(" <tr>\n"
- + " <td><font color=\"blue\">consensus</font>"
- + "</td>\n"
- + " <td><font color=\"blue\">"
- + this.downloadedConsensus.getStatusEntries().size()
- + " total</font></td>\n"
- + " <td><font color=\"blue\">"
- + this.downloadedConsensus.getRunningRelays()
- + " Running</font></td>\n"
- + " </tr>\n"
- + " </table>\n");
- }
-
- /* Write the supported consensus methods of directory authorities and
- * the resulting consensus method. */
- private void writeConsensusMethods() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"consensusmethods\">\n"
- + " <h3><a href=\"#consensusmethods\" class=\"anchor\">"
- + "Consensus methods</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- SortedSet<Integer> consensusMethods =
- vote.getConsensusMethods();
- if (consensusMethods.contains(
- this.downloadedConsensus.getConsensusMethods().last())) {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>consensus-methods");
- for (int consensusMethod : consensusMethods) {
- this.bw.write(" " + String.valueOf(consensusMethod));
- }
- this.bw.write("</td>\n"
- + " </tr>\n");
- } else {
- this.bw.write(" <tr>\n"
- + " <td><font color=\"red\">"
- + vote.getNickname() + "</font></td>\n"
- + " <td><font color=\"red\">"
- + "consensus-methods");
- for (int consensusMethod : consensusMethods) {
- this.bw.write(" " + String.valueOf(consensusMethod));
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n");
- }
- }
- }
- this.bw.write(" <tr>\n"
- + " <td><font color=\"blue\">consensus</font>"
- + "</td>\n"
- + " <td><font color=\"blue\">consensus-method "
- + this.downloadedConsensus.getConsensusMethods().last()
- + "</font></td>\n"
- + " </tr>\n"
- + " </table>\n");
- }
-
- /* Write recommended versions. */
- private void writeRecommendedVersions() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"recommendedversions\">\n"
- + " <h3><a href=\"#recommendedversions\" class=\"anchor\">"
- + "Recommended versions</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- SortedSet<String> voteRecommendedClientVersions =
- vote.getRecommendedClientVersions();
- if (voteRecommendedClientVersions != null) {
- if (downloadedConsensus.getRecommendedClientVersions().equals(
- voteRecommendedClientVersions)) {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>client-versions ");
- int i = 0;
- for (String version : voteRecommendedClientVersions) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</td>\n"
- + " </tr>\n");
- } else {
- this.bw.write(" <tr>\n"
- + " <td><font color=\"red\">"
- + vote.getNickname()
- + "</font></td>\n"
- + " <td><font color=\"red\">client-versions ");
- int i = 0;
- for (String version : voteRecommendedClientVersions) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n");
- }
- }
- SortedSet<String> voteRecommendedServerVersions =
- vote.getRecommendedServerVersions();
- if (voteRecommendedServerVersions != null) {
- if (downloadedConsensus.getRecommendedServerVersions().equals(
- voteRecommendedServerVersions)) {
- this.bw.write(" <tr>\n"
- + " <td></td>\n"
- + " <td>server-versions ");
- int i = 0;
- for (String version : voteRecommendedServerVersions) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</td>\n"
- + " </tr>\n");
- } else {
- this.bw.write(" <tr>\n"
- + " <td></td>\n"
- + " <td><font color=\"red\">server-versions ");
- int i = 0;
- for (String version : voteRecommendedServerVersions) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n");
- }
- }
- }
- }
- this.bw.write(" <tr>\n"
- + " <td><font color=\"blue\">consensus</font>"
- + "</td>\n"
- + " <td><font color=\"blue\">client-versions ");
- int i = 0;
- for (String version :
- downloadedConsensus.getRecommendedClientVersions()) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n"
- + " <tr>\n"
- + " <td></td>\n"
- + " <td><font color=\"blue\">server-versions ");
- i = 0;
- for (String version :
- downloadedConsensus.getRecommendedServerVersions()) {
- this.bw.write((i++ > 0 ? "," : "") + version);
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n"
- + " </table>\n");
- }
-
- /* Write consensus parameters. */
- private void writeConsensusParameters() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"consensusparams\">\n"
- + " <h3><a href=\"#consensusparams\" class=\"anchor\">"
- + "Consensus parameters</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- Set<String> validParameters = new HashSet<String>(Arrays.asList(
- ("circwindow,CircuitPriorityHalflifeMsec,refuseunknownexits,"
- + "cbtdisabled,cbtnummodes,cbtrecentcount,cbtmaxtimeouts,"
- + "cbtmincircs,cbtquantile,cbtclosequantile,cbttestfreq,"
- + "cbtmintimeout,cbtinitialtimeout,bwauthpid").split(",")));
- Map<String, String> consensusConsensusParams =
- downloadedConsensus.getConsensusParams();
- for (Status vote : this.downloadedVotes) {
- Map<String, String> voteConsensusParams =
- vote.getConsensusParams();
- boolean conflictOrInvalid = false;
- if (voteConsensusParams != null) {
- for (Map.Entry<String, String> e :
- voteConsensusParams.entrySet()) {
- if (!consensusConsensusParams.containsKey(e.getKey()) ||
- !consensusConsensusParams.get(e.getKey()).equals(
- e.getValue()) ||
- !validParameters.contains(e.getKey())) {
- conflictOrInvalid = true;
- break;
- }
- }
- }
- if (conflictOrInvalid) {
- this.bw.write(" <tr>\n"
- + " <td><font color=\"red\">"
- + vote.getNickname() + "</font></td>\n"
- + " <td><font color=\"red\">params");
- for (Map.Entry<String, String> e :
- voteConsensusParams.entrySet()) {
- this.bw.write(" " + e.getKey() + "=" + e.getValue());
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n");
- } else {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>params");
- for (Map.Entry<String, String> e :
- voteConsensusParams.entrySet()) {
- this.bw.write(" " + e.getKey() + "=" + e.getValue());
- }
- this.bw.write("</td>\n"
- + " </tr>\n");
- }
- }
- }
- this.bw.write(" <tr>\n"
- + " <td><font color=\"blue\">consensus</font>"
- + "</td>\n"
- + " <td><font color=\"blue\">params");
- for (Map.Entry<String, String> e :
- this.downloadedConsensus.getConsensusParams().entrySet()) {
- this.bw.write(" " + e.getKey() + "=" + e.getValue());
- }
- this.bw.write("</font></td>\n"
- + " </tr>\n"
- + " </table>\n");
- }
-
- /* Write authority keys and their expiration dates. */
- private void writeAuthorityKeys() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"authoritykeys\">\n"
- + " <h3><a href=\"#authoritykeys\" class=\"anchor\">"
- + "Authority keys</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- long voteDirKeyExpiresMillis = vote.getDirKeyExpiresMillis();
- if (voteDirKeyExpiresMillis - 14L * 24L * 60L * 60L * 1000L <
- System.currentTimeMillis()) {
- this.bw.write(" <tr>\n"
- + " <td><font color=\"red\">"
- + vote.getNickname() + "</font></td>\n"
- + " <td><font color=\"red\">dir-key-expires "
- + dateTimeFormat.format(voteDirKeyExpiresMillis)
- + "</font></td>\n"
- + " </tr>\n");
- } else {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>dir-key-expires "
- + dateTimeFormat.format(voteDirKeyExpiresMillis)
- + "</td>\n"
- + " </tr>\n");
- }
- }
- }
- this.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 the status of bandwidth scanners and results being contained
- * in votes. */
- private void writeBandwidthScannerStatus() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"bwauthstatus\">\n"
- + " <h3><a href=\"#bwauthstatus\" class=\"anchor\">"
- + "Bandwidth scanner status</a></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 (this.downloadedVotes.size() < 1) {
- this.bw.write(" <tr><td>(No votes.)</td><td></td></tr>\n");
- } else {
- for (Status vote : this.downloadedVotes) {
- if (vote.getBandwidthWeights() > 0) {
- this.bw.write(" <tr>\n"
- + " <td>" + vote.getNickname() + "</td>\n"
- + " <td>" + vote.getBandwidthWeights()
- + " Measured values in w lines</td>\n"
- + " </tr>\n");
- }
- }
- }
- this.bw.write(" </table>\n");
- }
-
- /* Write directory authority versions. */
- private void writeAuthorityVersions() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"authorityversions\">\n"
- + " <h3><a href=\"#authorityversions\" class=\"anchor\">"
- + "Authority versions</a></h3>\n"
- + " <br>\n");
- Map<String, String> authorityVersions =
- this.downloadedConsensus.getAuthorityVersions();
- if (authorityVersions.size() < 1) {
- this.bw.write(" <p>(No relays with Authority flag found.)"
- + "</p>\n");
- } else {
- this.bw.write(" <table border=\"0\" cellpadding=\"4\" "
- + "cellspacing=\"0\" summary=\"\">\n"
- + " <colgroup>\n"
- + " <col width=\"160\">\n"
- + " <col width=\"640\">\n"
- + " </colgroup>\n");
- for (Map.Entry<String, String> e : authorityVersions.entrySet()) {
- String nickname = e.getKey();
- String versionString = e.getValue();
- this.bw.write(" <tr>\n"
- + " <td>" + nickname + "</td>\n"
- + " <td>" + versionString + "</td>\n"
- + " </tr>\n");
- }
- this.bw.write(" </table>\n"
- + " <br>\n"
- + " <p><i>Note that this list of relays with the "
- + "Authority flag may be different from the list of v3 "
- + "directory authorities!</i></p>\n");
- }
- }
-
- /* Write the (huge) table containing relay flags contained in votes and
- * the consensus for each relay. */
- private void writeRelayFlagsTable() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"relayflags\">\n"
- + " <h3><a href=\"#relayflags\" class=\"anchor\">Relay "
- + "flags</a></h3>\n"
- + " <br>\n"
- + " <p>The semantics of flags written in the table is "
- + "as follows:</p>\n"
- + " <ul>\n"
- + " <li><b>In vote and consensus:</b> Flag in vote "
- + "matches flag in consensus, or relay is not listed in "
- + "consensus (because it doesn't have the Running "
- + "flag)</li>\n"
- + " <li><b><font color=\"red\">Only in "
- + "vote:</font></b> Flag in vote, but missing in the "
- + "consensus, because there was no majority for the flag or "
- + "the flag was invalidated (e.g., Named gets invalidated by "
- + "Unnamed)</li>\n"
- + " <li><b><font color=\"gray\"><s>Only in "
- + "consensus:</s></font></b> Flag in consensus, but missing "
- + "in a vote of a directory authority voting on this "
- + "flag</li>\n"
- + " <li><b><font color=\"blue\">In "
- + "consensus:</font></b> Flag in consensus</li>\n"
- + " </ul>\n"
- + " <br>\n"
- + " <p>See also the summary below the table.</p>\n"
- + " <table border=\"0\" cellpadding=\"4\" "
- + "cellspacing=\"0\" summary=\"\">\n"
- + " <colgroup>\n"
- + " <col width=\"120\">\n"
- + " <col width=\"80\">\n");
- for (int i = 0; i < this.downloadedVotes.size(); i++) {
- this.bw.write(" <col width=\""
- + (640 / this.downloadedVotes.size()) + "\">\n");
- }
- this.bw.write(" </colgroup>\n");
- SortedMap<String, String> allRelays = new TreeMap<String, String>();
- for (Status vote : this.downloadedVotes) {
- for (StatusEntry statusEntry : vote.getStatusEntries().values()) {
- allRelays.put(statusEntry.getFingerprint(),
- statusEntry.getNickname());
- }
- }
- for (StatusEntry statusEntry :
- this.downloadedConsensus.getStatusEntries().values()) {
- allRelays.put(statusEntry.getFingerprint(),
- statusEntry.getNickname());
- }
- int linesWritten = 0;
- for (Map.Entry<String, String> e : allRelays.entrySet()) {
- if (linesWritten++ % 10 == 0) {
- this.writeRelayFlagsTableHeader();
- }
- String fingerprint = e.getKey();
- String nickname = e.getValue();
- this.writeRelayFlagsTableRow(fingerprint, nickname);
- }
- this.bw.write(" </table>\n");
- }
-
- /* Write the table header that is repeated every ten relays and that
- * contains the directory authority names. */
- private void writeRelayFlagsTableHeader() throws IOException {
- this.bw.write(" <tr><td><br><b>Fingerprint</b></td>"
- + "<td><br><b>Nickname</b></td>\n");
- for (Status vote : this.downloadedVotes) {
- String shortDirName = vote.getNickname().length() > 6 ?
- vote.getNickname().substring(0, 5) + "." :
- vote.getNickname();
- this.bw.write("<td><br><b>" + shortDirName + "</b></td>");
- }
- this.bw.write("<td><br><b>consensus</b></td></tr>\n");
- }
-
- /* Write a single row in the table of relay flags. */
- private void writeRelayFlagsTableRow(String fingerprint,
- String nickname) throws IOException {
- this.bw.write(" <tr>\n");
- if (this.downloadedConsensus.containsStatusEntry(fingerprint) &&
- this.downloadedConsensus.getStatusEntry(fingerprint).getFlags().
- contains("Named") &&
- !Character.isDigit(nickname.charAt(0))) {
- this.bw.write(" <td id=\"" + nickname
- + "\"><a href=\"relay.html?fingerprint="
- + fingerprint + "\" target=\"_blank\">"
- + fingerprint.substring(0, 8) + "</a></td>\n");
- } else {
- this.bw.write(" <td><a href=\"relay.html?fingerprint="
- + fingerprint + "\" target=\"_blank\">"
- + fingerprint.substring(0, 8) + "</a></td>\n");
- }
- this.bw.write(" <td>" + nickname + "</td>\n");
- SortedSet<String> relevantFlags = new TreeSet<String>();
- for (Status vote : this.downloadedVotes) {
- if (vote.containsStatusEntry(fingerprint)) {
- relevantFlags.addAll(vote.getStatusEntry(fingerprint).getFlags());
- }
- }
- SortedSet<String> consensusFlags = null;
- if (this.downloadedConsensus.containsStatusEntry(fingerprint)) {
- consensusFlags = this.downloadedConsensus.
- getStatusEntry(fingerprint).getFlags();
- relevantFlags.addAll(consensusFlags);
- }
- for (Status vote : this.downloadedVotes) {
- if (vote.containsStatusEntry(fingerprint)) {
- SortedSet<String> flags = vote.getStatusEntry(fingerprint).
- getFlags();
- this.bw.write(" <td>");
- int flagsWritten = 0;
- for (String flag : relevantFlags) {
- this.bw.write(flagsWritten++ > 0 ? "<br>" : "");
- if (flags.contains(flag)) {
- if (consensusFlags == null ||
- consensusFlags.contains(flag)) {
- this.bw.write(flag);
- } else {
- this.bw.write("<font color=\"red\">" + flag + "</font>");
- }
- } else if (consensusFlags != null &&
- vote.getKnownFlags().contains(flag) &&
- consensusFlags.contains(flag)) {
- this.bw.write("<font color=\"gray\"><s>" + flag
- + "</s></font>");
- }
- }
- this.bw.write("</td>\n");
- } else {
- this.bw.write(" <td></td>\n");
- }
- }
- if (consensusFlags != null) {
- this.bw.write(" <td>");
- int flagsWritten = 0;
- for (String flag : relevantFlags) {
- this.bw.write(flagsWritten++ > 0 ? "<br>" : "");
- if (consensusFlags.contains(flag)) {
- this.bw.write("<font color=\"blue\">" + flag + "</font>");
- }
- }
- this.bw.write("</td>\n");
- } else {
- this.bw.write(" <td></td>\n");
- }
- this.bw.write(" </tr>\n");
- }
-
- /* Write the relay flag summary. */
- private void writeRelayFlagsSummary() throws IOException {
- this.bw.write(" <br>\n"
- + " <a name=\"overlap\">\n"
- + " <h3><a href=\"#overlap\" class=\"anchor\">Overlap "
- + "between votes and consensus</a></h3>\n"
- + " <br>\n"
- + " <p>The semantics of columns is similar to the "
- + "table above:</p>\n"
- + " <ul>\n"
- + " <li><b>In vote and consensus:</b> Flag in vote "
- + "matches flag in consensus, or relay is not listed in "
- + "consensus (because it doesn't have the Running "
- + "flag)</li>\n"
- + " <li><b><font color=\"red\">Only in "
- + "vote:</font></b> Flag in vote, but missing in the "
- + "consensus, because there was no majority for the flag or "
- + "the flag was invalidated (e.g., Named gets invalidated by "
- + "Unnamed)</li>\n"
- + " <li><b><font color=\"gray\"><s>Only in "
- + "consensus:</s></font></b> Flag in consensus, but missing "
- + "in a vote of a directory authority voting on this "
- + "flag</li>\n"
- + " </ul>\n"
- + " <br>\n"
- + " <table border=\"0\" cellpadding=\"4\" "
- + "cellspacing=\"0\" summary=\"\">\n"
- + " <colgroup>\n"
- + " <col width=\"160\">\n"
- + " <col width=\"210\">\n"
- + " <col width=\"210\">\n"
- + " <col width=\"210\">\n"
- + " </colgroup>\n"
- + " <tr><td></td><td><b>Only in vote</b></td>"
- + "<td><b>In vote and consensus</b></td>"
- + "<td><b>Only in consensus</b></td>\n");
- Set<String> allFingerprints = new HashSet<String>();
- for (Status vote : this.downloadedVotes) {
- allFingerprints.addAll(vote.getStatusEntries().keySet());
- }
- allFingerprints.addAll(this.downloadedConsensus.getStatusEntries().
- keySet());
- SortedMap<String, SortedMap<String, Integer>> flagsAgree =
- new TreeMap<String, SortedMap<String, Integer>>();
- SortedMap<String, SortedMap<String, Integer>> flagsLost =
- new TreeMap<String, SortedMap<String, Integer>>();
- SortedMap<String, SortedMap<String, Integer>> flagsMissing =
- new TreeMap<String, SortedMap<String, Integer>>();
- for (String fingerprint : allFingerprints) {
- SortedSet<String> consensusFlags =
- this.downloadedConsensus.containsStatusEntry(fingerprint) ?
- this.downloadedConsensus.getStatusEntry(fingerprint).getFlags() :
- null;
- for (Status vote : this.downloadedVotes) {
- String dir = vote.getNickname();
- if (vote.containsStatusEntry(fingerprint)) {
- SortedSet<String> flags = vote.getStatusEntry(fingerprint).
- getFlags();
- for (String flag : this.downloadedConsensus.getKnownFlags()) {
- SortedMap<String, SortedMap<String, Integer>> sums = null;
- if (flags.contains(flag)) {
- if (consensusFlags == null ||
- consensusFlags.contains(flag)) {
- sums = flagsAgree;
- } else {
- sums = flagsLost;
- }
- } else if (consensusFlags != null &&
- vote.getKnownFlags().contains(flag) &&
- consensusFlags.contains(flag)) {
- sums = flagsMissing;
- }
- if (sums != null) {
- SortedMap<String, Integer> sum = null;
- if (sums.containsKey(dir)) {
- sum = sums.get(dir);
- } else {
- sum = new TreeMap<String, Integer>();
- sums.put(dir, sum);
- }
- sum.put(flag, sum.containsKey(flag) ?
- sum.get(flag) + 1 : 1);
- }
- }
- }
- }
- }
- for (Status vote : this.downloadedVotes) {
- String dir = vote.getNickname();
- int i = 0;
- for (String flag : vote.getKnownFlags()) {
- this.bw.write(" <tr>\n"
- + " <td>" + (i++ == 0 ? dir : "")
- + "</td>\n");
- if (flagsLost.containsKey(dir) &&
- flagsLost.get(dir).containsKey(flag)) {
- this.bw.write(" <td><font color=\"red\"> "
- + flagsLost.get(dir).get(flag) + " " + flag
- + "</font></td>\n");
- } else {
- this.bw.write(" <td></td>\n");
- }
- if (flagsAgree.containsKey(dir) &&
- flagsAgree.get(dir).containsKey(flag)) {
- this.bw.write(" <td>" + flagsAgree.get(dir).get(flag)
- + " " + flag + "</td>\n");
- } else {
- this.bw.write(" <td></td>\n");
- }
- if (flagsMissing.containsKey(dir) &&
- flagsMissing.get(dir).containsKey(flag)) {
- this.bw.write(" <td><font color=\"gray\"><s>"
- + flagsMissing.get(dir).get(flag) + " " + flag
- + "</s></font></td>\n");
- } else {
- this.bw.write(" <td></td>\n");
- }
- this.bw.write(" </tr>\n");
- }
- }
- this.bw.write(" </table>\n");
- }
-
- /* Write the footer of the HTML page containing the blurb that is on
- * every page of the metrics website. */
- private void writePageFooter() throws IOException {
- this.bw.write(" </div>\n"
- + " </div>\n"
- + " <div class=\"bottom\" id=\"bottom\">\n"
- + " <p>This material is supported in part by the "
- + "National Science Foundation under Grant No. "
- + "CNS-0959138. Any opinions, finding, and conclusions "
- + "or recommendations expressed in this material are "
- + "those of the author(s) and do not necessarily reflect "
- + "the views of the National Science Foundation.</p>\n"
- + " <p>\"Tor\" and the \"Onion Logo\" are <a "
- + "href=\"https://www.torproject.org/docs/trademark-faq.html"
- + ".en\">"
- + "registered trademarks</a> of The Tor Project, "
- + "Inc.</p>\n"
- + " <p>Data on this site is freely available under a "
- + "<a href=\"http://creativecommons.org/publicdomain/"
- + "zero/1.0/\">CC0 no copyright declaration</a>: To the "
- + "extent possible under law, the Tor Project has waived "
- + "all copyright and related or neighboring rights in "
- + "the data. Graphs are licensed under a <a "
- + "href=\"http://creativecommons.org/licenses/by/3.0/"
- + "us/\">Creative Commons Attribution 3.0 United States "
- + "License</a>.</p>\n"
- + " </div>\n"
- + " </body>\n"
- + "</html>");
- }
-}
-
diff --git a/src/org/torproject/chc/Parser.java b/src/org/torproject/chc/Parser.java
deleted file mode 100644
index 053c7b4..0000000
--- a/src/org/torproject/chc/Parser.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-import org.apache.commons.codec.binary.*;
-
-/* Parse a network status consensus or vote. */
-public class Parser {
-
- /* Parse and return a consensus and corresponding votes, or null if
- * something goes wrong. */
- public SortedMap<String, Status> parse(
- SortedMap<String, String> consensusStrings,
- List<String> voteStrings) {
- SortedSet<Status> parsedVotes = new TreeSet<Status>();
- for (String voteString : voteStrings) {
- Status parsedVote = this.parseConsensusOrVote(voteString, false);
- if (parsedVote != null) {
- parsedVotes.add(parsedVote);
- }
- }
- SortedMap<String, Status> parsedConsensuses =
- new TreeMap<String, Status>();
- for (Map.Entry<String, String> e : consensusStrings.entrySet()) {
- String nickname = e.getKey();
- String consensusString = e.getValue();
- Status parsedConsensus = this.parseConsensusOrVote(consensusString,
- true);
- if (parsedConsensus != null) {
- for (Status parsedVote : parsedVotes) {
- if (parsedConsensus.getValidAfterMillis() ==
- parsedVote.getValidAfterMillis()) {
- parsedConsensus.addVote(parsedVote);
- }
- }
- parsedConsensuses.put(nickname, parsedConsensus);
- }
- }
- return parsedConsensuses;
- }
-
- /* Date-time formats to parse and format timestamps. */
- private static SimpleDateFormat dateTimeFormat;
- static {
- dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /* Parse a consensus or vote string into a Status instance. */
- private Status parseConsensusOrVote(String statusString,
- boolean isConsensus) {
- if (statusString == null) {
- return null;
- }
- Status status = new Status();
- status.setUnparsedString(statusString);
- try {
- BufferedReader br = new BufferedReader(new StringReader(
- statusString));
- String line, rLine = null, sLine = null;
- int totalRelays = 0, runningRelays = 0, bandwidthWeights = 0;
- while ((line = br.readLine()) != null) {
- if (line.startsWith("consensus-method ") ||
- line.startsWith("consensus-methods ")) {
- SortedSet<Integer> consensusMethods = new TreeSet<Integer>();
- String[] parts = line.split(" ");
- for (int i = 1; i < parts.length; i++) {
- consensusMethods.add(Integer.parseInt(parts[i]));
- }
- status.setConsensusMethods(consensusMethods);
- } else if (line.startsWith("valid-after ")) {
- try {
- status.setValidAfterMillis(dateTimeFormat.parse(
- line.substring("valid-after ".length())).getTime());
- } catch (ParseException e) {
- System.err.println("Could not parse valid-after timestamp in "
- + "line '" + line + "' of a "
- + (isConsensus ? "consensus" : "vote") + ". Skipping.");
- return null;
- }
- } else if (line.startsWith("client-versions ")) {
- status.setRecommendedClientVersions(
- new TreeSet<String>(Arrays.asList(
- line.split(" ")[1].split(","))));
- } else if (line.startsWith("server-versions ")) {
- status.setRecommendedServerVersions(
- new TreeSet<String>(Arrays.asList(
- line.split(" ")[1].split(","))));
- } else if (line.startsWith("known-flags ")) {
- for (String flag : line.substring("known-flags ".length()).
- split(" ")) {
- status.addKnownFlag(flag);
- }
- } else if (line.startsWith("params ")) {
- if (line.length() > "params ".length()) {
- for (String param :
- line.substring("params ".length()).split(" ")) {
- String paramName = param.split("=")[0];
- String paramValue = param.split("=")[1];
- status.addConsensusParam(paramName, paramValue);
- }
- }
- } else if (line.startsWith("dir-source ") && !isConsensus) {
- status.setNickname(line.split(" ")[1]);
- status.setFingerprint(line.split(" ")[2]);
- } else if (line.startsWith("dir-key-expires ")) {
- try {
- status.setDirKeyExpiresMillis(dateTimeFormat.parse(
- line.substring("dir-key-expires ".length())).getTime());
- } catch (ParseException e) {
- System.err.println("Could not parse dir-key-expires "
- + "timestamp in line '" + line + "' of a "
- + (isConsensus ? "consensus" : "vote") + ". Skipping.");
- return null;
- }
- } else if (line.startsWith("r ") ||
- line.equals("directory-footer")) {
- if (rLine != null) {
- StatusEntry statusEntry = new StatusEntry();
- statusEntry.setNickname(rLine.split(" ")[1]);
- statusEntry.setFingerprint(Hex.encodeHexString(
- Base64.decodeBase64(rLine.split(" ")[2] + "=")).
- toUpperCase());
- SortedSet<String> flags = new TreeSet<String>();
- if (sLine.length() > 2) {
- for (String flag : sLine.substring(2).split(" ")) {
- flags.add(flag);
- }
- }
- statusEntry.setFlags(flags);
- status.addStatusEntry(statusEntry);
- }
- if (line.startsWith("r ")) {
- rLine = line;
- } else {
- break;
- }
- } else if (line.startsWith("s ") || line.equals("s")) {
- sLine = line;
- if (line.contains(" Running")) {
- runningRelays++;
- }
- } else if (line.startsWith("v ") &&
- sLine.contains(" Authority")) {
- String nickname = rLine.split(" ")[1];
- String versionString = line.substring(2);
- status.addAuthorityVersion(nickname, versionString);
- } else if (line.startsWith("w ") && !isConsensus &&
- line.contains(" Measured")) {
- bandwidthWeights++;
- }
- }
- br.close();
- status.setRunningRelays(runningRelays);
- status.setBandwidthWeights(bandwidthWeights);
- } catch (IOException e) {
- System.err.println("Caught an IOException while parsing a "
- + (isConsensus ? "consensus" : "vote") + " string. Skipping.");
- return null;
- }
- return status;
- }
-}
-
diff --git a/src/org/torproject/chc/Report.java b/src/org/torproject/chc/Report.java
deleted file mode 100644
index 48015eb..0000000
--- a/src/org/torproject/chc/Report.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.util.*;
-
-/* Transform findings from parsing consensuses and votes into a report of
- * some form. */
-public interface Report {
-
- /* Process the downloaded current consensus and corresponding votes to
- * find irregularities between them. */
- public abstract void processDownloadedConsensuses(
- SortedMap<String, Status> downloadedConsensuses);
-
- /* Process warnings consisting of warning type and details. */
- public abstract void processWarnings(
- SortedMap<Warning, String> warnings);
-
- /* Finish writing report. */
- public abstract void writeReport();
-}
-
diff --git a/src/org/torproject/chc/Status.java b/src/org/torproject/chc/Status.java
deleted file mode 100644
index cbf7395..0000000
--- a/src/org/torproject/chc/Status.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.util.*;
-
-/* Contains the unparsed string and parsed fields from a network status
- * consensus or vote. */
-public class Status implements Comparable<Status> {
-
- /* Helper methods to implement the Comparable interface; Status
- * instances are compared by nickname of the publishing directory
- * authorities. */
- public int compareTo(Status o) {
- return this.nickname.compareTo(o.nickname);
- }
- public boolean equals(Object o) {
- return (o instanceof Status &&
- this.nickname.equals(((Status) o).nickname));
- }
-
- /* Unparsed string that was downloaded or read from disk and that can
- * be written to disk. */
- private String unparsedString;
- public void setUnparsedString(String unparsedString) {
- this.unparsedString = unparsedString;
- }
- public String getUnparsedString() {
- return this.unparsedString;
- }
-
- /* Votes published at the same time as this consensus; votes don't
- * reference any statuses. */
- private SortedSet<Status> votes = new TreeSet<Status>();
- public void addVote(Status vote) {
- this.votes.add(vote);
- }
- public SortedSet<Status> getVotes() {
- return this.votes;
- }
-
- /* Fingerprint of the directory authority publishing this vote; left
- * empty for consensuses. */
- private String fingerprint;
- public void setFingerprint(String fingerprint) {
- this.fingerprint = fingerprint;
- }
- public String getFingerprint() {
- return this.fingerprint;
- }
-
- /* Nickname of the directory authority publishing this vote; left empty
- * for consensuses. */
- private String nickname;
- public void setNickname(String nickname) {
- this.nickname= nickname;
- }
- public String getNickname() {
- return this.nickname;
- }
-
- /* Valid-after time in milliseconds. */
- private long validAfterMillis;
- public void setValidAfterMillis(long validAfterMillis) {
- this.validAfterMillis = validAfterMillis;
- }
- public long getValidAfterMillis() {
- return this.validAfterMillis;
- }
-
- /* Consensus parameters. */
- private SortedMap<String, String> consensusParams =
- new TreeMap<String, String>();
- public void addConsensusParam(String paramName, String paramValue) {
- this.consensusParams.put(paramName, paramValue);
- }
- public SortedMap<String, String> getConsensusParams() {
- return this.consensusParams;
- }
-
- /* Consensus methods supported by the directory authority sending a vote
- * or of the produced consensus. */
- private SortedSet<Integer> consensusMethods;
- public void setConsensusMethods(SortedSet<Integer> consensusMethods) {
- this.consensusMethods = consensusMethods;
- }
- public SortedSet<Integer> getConsensusMethods() {
- return this.consensusMethods;
- }
-
- /* Recommended server versions. */
- private SortedSet<String> recommendedServerVersions;
- public void setRecommendedServerVersions(
- SortedSet<String> recommendedServerVersions) {
- this.recommendedServerVersions = recommendedServerVersions;
- }
- public SortedSet<String> getRecommendedServerVersions() {
- return this.recommendedServerVersions;
- }
-
- /* Recommended client versions. */
- private SortedSet<String> recommendedClientVersions;
- public void setRecommendedClientVersions(
- SortedSet<String> recommendedClientVersions) {
- this.recommendedClientVersions = recommendedClientVersions;
- }
- public SortedSet<String> getRecommendedClientVersions() {
- return this.recommendedClientVersions;
- }
-
- /* Expiration times of directory signing keys. */
- private long dirKeyExpiresMillis;
- public void setDirKeyExpiresMillis(long dirKeyExpiresMillis) {
- this.dirKeyExpiresMillis = dirKeyExpiresMillis;
- }
- public long getDirKeyExpiresMillis() {
- return this.dirKeyExpiresMillis;
- }
-
- /* Known flags by the directory authority sending a vote or of the
- * produced consensus. */
- private SortedSet<String> knownFlags = new TreeSet<String>();
- public void addKnownFlag(String knownFlag) {
- this.knownFlags.add(knownFlag);
- }
- public SortedSet<String> getKnownFlags() {
- return this.knownFlags;
- }
-
- /* Number of status entries with the Running flag. */
- private int runningRelays;
- public void setRunningRelays(int runningRelays) {
- this.runningRelays = runningRelays;
- }
- public int getRunningRelays() {
- return this.runningRelays;
- }
-
- /* Number of status entries containing bandwidth weights (only relevant
- * in votes). */
- private int bandwidthWeights;
- public void setBandwidthWeights(int bandwidthWeights) {
- this.bandwidthWeights = bandwidthWeights;
- }
- public int getBandwidthWeights() {
- return this.bandwidthWeights;
- }
-
- /* Status entries contained in this status. */
- private SortedMap<String, StatusEntry> statusEntries =
- new TreeMap<String, StatusEntry>();
- public void addStatusEntry(StatusEntry statusEntry) {
- this.statusEntries.put(statusEntry.getFingerprint(), statusEntry);
- }
- public SortedMap<String, StatusEntry> getStatusEntries() {
- return this.statusEntries;
- }
- public boolean containsStatusEntry(String fingerprint) {
- return this.statusEntries.containsKey(fingerprint);
- }
- public StatusEntry getStatusEntry(String fingerprint) {
- return this.statusEntries.get(fingerprint);
- }
-
- /* Versions of directory authorities (only set in a consensus). */
- private SortedMap<String, String> authorityVersions =
- new TreeMap<String, String>();
- public void addAuthorityVersion(String fingerprint,
- String versionString) {
- this.authorityVersions.put(fingerprint, versionString);
- }
- public SortedMap<String, String> getAuthorityVersions() {
- return this.authorityVersions;
- }
-}
-
diff --git a/src/org/torproject/chc/StatusEntry.java b/src/org/torproject/chc/StatusEntry.java
deleted file mode 100644
index 0377937..0000000
--- a/src/org/torproject/chc/StatusEntry.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.util.*;
-
-/* Contains the parsed data from a network status entry contained in a
- * network status consensus or vote. */
-public class StatusEntry implements Comparable<StatusEntry> {
-
- /* Helper methods to implement the Comparable interface; StatusEntry
- * instances are compared by fingerprint. */
- public int compareTo(StatusEntry o) {
- return this.fingerprint.compareTo(o.fingerprint);
- }
- public boolean equals(Object o) {
- return (o instanceof StatusEntry &&
- this.fingerprint.equals(((StatusEntry) o).fingerprint));
- }
-
- /* Relay fingerprint. */
- private String fingerprint;
- public void setFingerprint(String fingerprint) {
- this.fingerprint = fingerprint;
- }
- public String getFingerprint() {
- return this.fingerprint;
- }
-
- /* Relay nickname. */
- private String nickname;
- public void setNickname(String nickname) {
- this.nickname = nickname;
- }
- public String getNickname() {
- return this.nickname;
- }
-
- /* Relay flags. */
- private SortedSet<String> flags;
- public void setFlags(SortedSet<String> flags) {
- this.flags = flags;
- }
- public SortedSet<String> getFlags() {
- return this.flags;
- }
-}
-
diff --git a/src/org/torproject/chc/StatusFileReport.java b/src/org/torproject/chc/StatusFileReport.java
deleted file mode 100644
index 4aef195..0000000
--- a/src/org/torproject/chc/StatusFileReport.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-import java.io.*;
-import java.text.*;
-import java.util.*;
-
-/* Check a given consensus and votes for irregularities and write results
- * to stdout while rate-limiting warnings based on severity. */
-public class StatusFileReport implements Report {
-
- /* Date-time format to format timestamps. */
- private static SimpleDateFormat dateTimeFormat;
- static {
- dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
-
- /* Downloaded consensus and corresponding votes for later
- * processing. */
- private SortedMap<String, Status> downloadedConsensuses;
- private Status downloadedConsensus;
- private SortedSet<Status> downloadedVotes;
- public void processDownloadedConsensuses(
- SortedMap<String, Status> downloadedConsensuses) {
- this.downloadedConsensuses = downloadedConsensuses;
- }
-
- /* Warnings obtained from checking the current consensus and votes. */
- private SortedMap<Warning, String> warnings;
- public void processWarnings(SortedMap<Warning, String> warnings) {
- this.warnings = warnings;
- }
-
- /* Check consensuses and votes for irregularities and write output to
- * stdout. */
- public void writeReport() {
- this.readLastWarned();
- this.prepareReports();
- this.writeStatusFiles();
- this.writeLastWarned();
- }
-
- /* Warning messages of the last 24 hours that is used to implement
- * rate limiting. */
- private Map<String, Long> lastWarned = new HashMap<String, Long>();
-
- /* Read when we last emitted a warning to rate-limit some of them. */
- private void readLastWarned() {
- long now = System.currentTimeMillis();
- File lastWarnedFile = new File("stats/chc-last-warned");
- try {
- if (lastWarnedFile.exists()) {
- BufferedReader br = new BufferedReader(new FileReader(
- lastWarnedFile));
- String line;
- while ((line = br.readLine()) != null) {
- if (!line.contains(": ")) {
- System.err.println("Bad line in stats/chc-last-warned: '" + line
- + "'. Ignoring this line.");
- continue;
- }
- long warnedMillis = Long.parseLong(line.substring(0,
- line.indexOf(": ")));
- if (warnedMillis < now - 24L * 60L * 60L * 1000L) {
- /* Remove warnings that are older than 24 hours. */
- continue;
- }
- String message = line.substring(line.indexOf(": ") + 2);
- lastWarned.put(message, warnedMillis);
- }
- }
- } catch (IOException e) {
- System.err.println("Could not read file '"
- + lastWarnedFile.getAbsolutePath() + "' to learn which "
- + "warnings have been sent out before. Ignoring.");
- }
- }
-
- /* Prepare a report to be written to stdout. */
- private String allWarnings = null, newWarnings = null;
- private void prepareReports() {
- SortedMap<String, Long> warningStrings = new TreeMap<String, Long>();
- for (Map.Entry<Warning, String> e : this.warnings.entrySet()) {
- Warning type = e.getKey();
- String details = e.getValue();
- switch (type) {
- case NoConsensusKnown:
- break;
- case ConsensusDownloadTimeout:
- warningStrings.put("The following directory authorities did "
- + "not return a consensus within a timeout of 60 seconds: "
- + details, 150L * 60L * 1000L);
- break;
- case ConsensusNotFresh:
- warningStrings.put("The consensuses published by the following "
- + "directory authorities are more than 1 hour old and "
- + "therefore not fresh anymore: " + details,
- 150L * 60L * 1000L);
- break;
- case ConsensusMethodNotSupported:
- warningStrings.put("The following directory authorities do not "
- + "support the consensus method that the consensus uses: "
- + details, 24L * 60L * 60L * 1000L);
- break;
- case DifferentRecommendedClientVersions:
- warningStrings.put("The following directory authorities "
- + "recommend other client versions than the consensus: "
- + details, 150L * 60L * 1000L);
- break;
- case DifferentRecommendedServerVersions:
- warningStrings.put("The following directory authorities "
- + "recommend other server versions than the consensus: "
- + details, 150L * 60L * 1000L);
- break;
- case ConflictingOrInvalidConsensusParams:
- warningStrings.put("The following directory authorities set "
- + "conflicting or invalid consensus parameters: " + details,
- 150L * 60L * 1000L);
- break;
- case CertificateExpiresSoon:
- warningStrings.put("The certificates of the following "
- + "directory authorities expire within the next 14 days: "
- + details, 24L * 60L * 60L * 1000L);
- break;
- case VotesMissing:
- warningStrings.put("We're missing votes from the following "
- + "directory authorities: " + details, 150L * 60L * 1000L);
- break;
- case BandwidthScannerResultsMissing:
- warningStrings.put("The following directory authorities are "
- + "not reporting bandwidth scanner results: " + details,
- 150L * 60L * 1000L);
- break;
- }
- }
- long now = System.currentTimeMillis();
- StringBuilder allSb = new StringBuilder(),
- newSb = new StringBuilder();
- for (Map.Entry<String, Long> e : warningStrings.entrySet()) {
- String message = e.getKey();
- allSb.append(message + "\n");
- long warnInterval = e.getValue();
- if (!lastWarned.containsKey(message) ||
- lastWarned.get(message) + warnInterval < now) {
- newSb.append(message + "\n");
- }
- }
- if (newSb.length() > 0) {
- this.allWarnings = allSb.toString();
- this.newWarnings = newSb.toString();
- for (String message : warningStrings.keySet()) {
- this.lastWarned.put(message, now);
- }
- }
- }
-
- /* Write report to stdout. */
- private void writeStatusFiles() {
- try {
- BufferedWriter allBw = new BufferedWriter(new FileWriter(
- "all-warnings")), newBw = new BufferedWriter(new FileWriter(
- "new-warnings"));
- if (this.allWarnings != null) {
- allBw.write(this.allWarnings);
- }
- if (this.newWarnings != null) {
- newBw.write(this.newWarnings);
- }
- allBw.close();
- newBw.close();
- } catch (IOException e) {
- System.err.println("Could not write status files 'all-warnings' "
- + "and/or 'new-warnings'. Ignoring.");
- }
- }
-
- /* Write timestamps when warnings were last sent to disk. */
- private void writeLastWarned() {
- File lastWarnedFile = new File("stats/chc-last-warned");
- try {
- lastWarnedFile.getParentFile().mkdirs();
- BufferedWriter bw = new BufferedWriter(new FileWriter(
- lastWarnedFile));
- for (Map.Entry<String, Long> e : lastWarned.entrySet()) {
- bw.write(String.valueOf(e.getValue()) + ": " + e.getKey() + "\n");
- }
- bw.close();
- } catch (IOException e) {
- System.err.println("Could not write file '"
- + lastWarnedFile.getAbsolutePath() + "' to remember which "
- + "warnings have been sent out before. Ignoring.");
- }
- }
-}
-
diff --git a/src/org/torproject/chc/Warning.java b/src/org/torproject/chc/Warning.java
deleted file mode 100644
index 3425c6c..0000000
--- a/src/org/torproject/chc/Warning.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2011 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.chc;
-
-/* Warning about irregularities in parsed consensuses and votes. */
-public enum Warning {
-
- /* No consensus is known that can be checked. */
- NoConsensusKnown,
-
- /* One or more directory authorities did not return a consensus within a
- * timeout of 60 seconds. */
- ConsensusDownloadTimeout,
-
- /* One or more directory authorities published a consensus that is more
- * than 1 hour old and therefore not fresh anymore. */
- ConsensusNotFresh,
-
- /* One or more directory authorities does not support the consensus
- * method that the consensus uses. */
- ConsensusMethodNotSupported,
-
- /* One or more directory authorities recommends different client
- * versions than the ones in the consensus. */
- DifferentRecommendedClientVersions,
-
- /* One or more directory authorities recommends different server
- * versions than the ones in the consensus. */
- DifferentRecommendedServerVersions,
-
- /* One or more directory authorities set conflicting or invalid
- * consensus parameters. */
- ConflictingOrInvalidConsensusParams,
-
- /* The certificate(s) of one or more directory authorities expire within
- * the next 14 days. */
- CertificateExpiresSoon,
-
- /* The vote(s) of one or more directory authorities are missing. */
- VotesMissing,
-
- /* One or more directory authorities are not reporting bandwidth scanner
- * results. */
- BandwidthScannerResultsMissing
-}
-
More information about the tor-commits
mailing list