summaryrefslogtreecommitdiff
path: root/other
diff options
context:
space:
mode:
authorPeter Palfrader <peter@palfrader.org>2005-04-11 21:16:38 +0000
committerPeter Palfrader <peter@palfrader.org>2005-04-11 21:16:38 +0000
commitc4cbd290c89d38687dc4f523fb8b44851066975d (patch)
tree9f3056e9dc01109100b36914557b0af4137d5c51 /other
parent31c579ec715796afbdd176227ec4bc2fb6cc96fa (diff)
Add tor and mixminion
Diffstat (limited to 'other')
-rw-r--r--other/mixminion/Makefile21
-rwxr-xr-xother/mixminion/bin/rrd-graph103
-rwxr-xr-xother/mixminion/bin/rrd-update147
-rw-r--r--other/tor/Makefile25
-rwxr-xr-xother/tor/bin/rrd-graph413
-rwxr-xr-xother/tor/bin/rrd-update448
6 files changed, 1157 insertions, 0 deletions
diff --git a/other/mixminion/Makefile b/other/mixminion/Makefile
new file mode 100644
index 0000000..78706a5
--- /dev/null
+++ b/other/mixminion/Makefile
@@ -0,0 +1,21 @@
+TODAY=`TZ=UTC date +'%Y-%m-%d_%H:%M:%S'`
+WGET=wget --cache=off
+OUTDIR=mixminion-directory
+SOURCE=http://mixminion.net/directory/Directory.gz
+TMPFILE=download.tmp
+LAST_NAME=dir.last
+
+all:
+ rm -f $(TMPFILE)
+ $(WGET) -q -O $(TMPFILE) $(SOURCE)
+ NAME=directory-$(TODAY).gz; \
+ if [ -e $(LAST_NAME) ] && diff -q $(TMPFILE) $(OUTDIR)/`cat $(LAST_NAME)` >/dev/null ; then \
+ ln $(OUTDIR)/`cat $(LAST_NAME)` $(OUTDIR)/$$NAME; \
+ else \
+ mv $(TMPFILE) $(OUTDIR)/$$NAME; \
+ echo "$$NAME" > $(LAST_NAME); \
+ fi; \
+ bin/rrd-update $$NAME
+ rm -rf result
+ mkdir result
+ bin/rrd-graph
diff --git a/other/mixminion/bin/rrd-graph b/other/mixminion/bin/rrd-graph
new file mode 100755
index 0000000..269a2ad
--- /dev/null
+++ b/other/mixminion/bin/rrd-graph
@@ -0,0 +1,103 @@
+#!/usr/bin/perl -w
+
+use strict;
+use RRDs;
+use BER;
+
+my $HOSTNAME = `hostname`;
+
+#my $IMG_URL = 'http://images.noreply.org/mixminion-nodes/';
+my $IMG_URL = '';
+my $NOW = time;
+my $GMTIME = gmtime($NOW);
+my $START_AT = $NOW-9*30*24*3600;
+my $RRD = '/home/weasel/www/www.noreply.org/Build/other/mixminion/rrd/nodes.rrd';
+my $RRD_DIR = '/home/weasel/www/www.noreply.org/Build/other/mixminion/rrd/nodes';
+
+opendir(D,$RRD_DIR) or die ("Cannot opendir .: $!\n");
+my @SOURCES = sort { lc($a) cmp lc($b)} grep { /\.rrd$/ } readdir(D);
+@SOURCES = grep {
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = stat($RRD_DIR.'/'.$_);
+ $mtime >= $START_AT;
+ } @SOURCES;
+closedir(D);
+
+my @params = qw{result/total.png};
+push @params, sprintf('-s %s', $START_AT);
+#push @params, sprintf('-e %s', $NOW- 2*24*3600);
+push @params, sprintf('-t %s', "Mixminion nodes");
+push @params, sprintf('-v %s', "# nodes");
+#push @params, sprintf('-w %d', 600);
+#push @params, sprintf('-h %d', 400);
+
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_inDirectory' , $RRD, 'inDirectory', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_inDirectory' , 'd_inDirectory');
+push @params, sprintf('%s:%s#%s:%s' , 'LINE2' , 'c_inDirectory' , 'FF77FF', '# in directory');
+
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_recommended' , $RRD, 'recommended', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_recommended' , 'd_recommended');
+push @params, sprintf('%s:%s#%s:%s' , 'LINE3' , 'c_recommended' , '7777FF', '# recommended' );
+
+push @params, sprintf('CDEF:%s=d_inDirectory,0,*,%s,+' , 'zeroline' , '0');
+push @params, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+
+my $body;
+my $index;
+
+for my $source (@SOURCES) {
+ my $def = $source;
+ $def =~ s/\.rrd$//;
+ my $cdef = 'c_'.$def;
+ my $label = $def;
+
+ $source = $RRD_DIR .'/'. $source;
+
+ my @this;
+ push @this, sprintf('result/node-%s.png', $def);
+ push @this, sprintf('-s %s', $START_AT);
+ push @this, sprintf('-t %s', "$def");
+ push @this, sprintf('-v %s', "#");
+ #push @this, sprintf('-w %d', 150);
+ #push @this, sprintf('-h %d', 50);
+
+ push @this, sprintf('DEF:%s=%s:%s:%s', 'd_inDirectory' , $source, 'inDirectory', 'AVERAGE');
+ push @this, sprintf('CDEF:%s=%s' , 'c_inDirectory' , 'd_inDirectory');
+ push @this, sprintf('%s:%s#%s:%s' , 'AREA' , 'c_inDirectory' , 'FF77FF', '# in directory');
+
+ push @this, sprintf('DEF:%s=%s:%s:%s', 'd_recommended' , $source, 'recommended', 'AVERAGE');
+ push @this, sprintf('CDEF:%s=%s' , 'c_recommended' , 'd_recommended');
+ push @this, sprintf('%s:%s#%s:%s' , 'AREA' , 'c_recommended' , '7777FF', '# recommended' );
+
+ push @this, sprintf('CDEF:%s=d_inDirectory,0,*,%s,+' , 'zeroline' , '0');
+ push @this, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+
+ my ($averages,$xsize,$ysize) = RRDs::graph @this;
+ warn RRDs::error if RRDs::error;
+
+ $body .= "<h2><a name=\"$def\">$def</a></h2><p><a href=\"#_top\">top</a><p><img width=\"$xsize\" height=\"$ysize\" alt=\"$def running\" src=\"$IMG_URL"."node-$def.png\"></p>\n";
+ $index .= "<li><a href=\"#$def\">$def</a></li>\n";
+}
+
+my ($averages,$xsize,$ysize) = RRDs::graph @params;
+die RRDs::error if RRDs::error;
+
+my $html = "<html><head><title>Number of Mixminion Nodes</title></head><body>";
+$html .= "<h1><a name=\"_top\">Number of Mixminion Nodes</a></h1>";
+$html .= "<a href=\"../\">..</a><br>\n";
+$html .= "<p><img width=\"$xsize\" height=\"$ysize\" src=\"$IMG_URL"."total.png\"></p>";
+$html .= "<h1>Nodes</h1>";
+$html .= "<ul>".$index."</ul>";
+$html .= $body;
+$html .= "<br><br><br>\n";
+$html .= 'Images created with Tobi Oetiker\'s <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">rrdtool</a>'."\n";
+$html .= "<hr>\nBuilt at $GMTIME on $HOSTNAME<br>\n";
+$html .= "<a href=\"mailto:web\@palfrader.org\">Peter Palfrader &lt;web\@palfrader.org&gt;</a>\n";
+$html .= "</body></html>\n";
+
+open (F, ">result/index.html") or die ("Cannot open index.html: $!\n");
+print F $html;
+close F;
+
diff --git a/other/mixminion/bin/rrd-update b/other/mixminion/bin/rrd-update
new file mode 100755
index 0000000..29d0c17
--- /dev/null
+++ b/other/mixminion/bin/rrd-update
@@ -0,0 +1,147 @@
+#!/usr/bin/perl -w
+
+use strict;
+use RRDs;
+use BER;
+use Time::ParseDate;
+use Compress::Zlib;
+
+my $NOW = time;
+my $VERBOSE = 0;
+my $RRD = '/home/weasel/www/www.noreply.org/Build/other/mixminion/rrd/nodes.rrd';
+my $RRD_DIR = '/home/weasel/www/www.noreply.org/Build/other/mixminion/rrd/nodes';
+my $DIR_DIR = '/home/weasel/www/www.noreply.org/Build/other/mixminion/mixminion-directory';
+
+sub check_exists($) {
+ my ($rrd) = @_;
+ return if (-e $rrd);
+ my @params = ($rrd);
+ push @params, '-b', 'now - 1 year',
+ qw{ --step 14400
+ DS:inDirectory:GAUGE:172800:U:U
+ DS:recommended:GAUGE:172800:U:U
+ RRA:AVERAGE:0.5:1:21900
+ };
+ print "Creating rrd: $rrd...\n" if $VERBOSE;
+ RRDs::create @params;
+ my $err=RRDs::error;
+ warn "ERROR while creating $rrd: $err\n" if $err;
+}
+sub get_last($) {
+ my ($rrd) = @_;
+ my $last = 0;
+ if ( -e $rrd) {
+ $last = RRDs::last($rrd);
+ my $err = RRDs::error;
+ warn "ERROR while getting last for $rrd: $err\n" if $err;
+ };
+ return $last;
+};
+
+check_exists($RRD);
+my $last = get_last($RRD);
+
+opendir(DIR, $RRD_DIR) || die ("Cannot opendir $RRD_DIR: $!\n");
+my @rrdfiles = grep { /\.rrd$/ } readdir (DIR);
+closedir(DIR);
+my %last_node;
+for my $rrdfile (@rrdfiles) {
+ my $nodename = $rrdfile;
+ $nodename =~ s/\.rrd$//;
+ $last_node{$nodename} = get_last($RRD_DIR.'/'.$rrdfile);
+}
+
+my @dirfiles;
+if (scalar @ARGV) {
+ @dirfiles = @ARGV;
+} else {
+ opendir(DIR, $DIR_DIR) || die ("Cannot opendir $DIR_DIR: $!\n");
+ @dirfiles = sort { ($a cmp $b) } grep { /^directory-/ } readdir (DIR);
+ closedir(DIR);
+};
+
+my @updateGlobal;
+my %updates;
+for my $dir (@dirfiles) {
+ print "Doing $dir\n" if $VERBOSE;
+ open (DIRECTORY, $DIR_DIR.'/'.$dir) || die ("Cannot open $DIR_DIR/$dir: $!\n");
+ my $compressed_dir = join '', <DIRECTORY>;
+ close (DIRECTORY);
+
+ my $directory = Compress::Zlib::memGunzip($compressed_dir);
+
+ my $published = undef;
+ my $recommended_servers = undef;
+ my %in_directory;
+ my %is_recommended;
+ my $section = '' ;
+ for my $line (split /\r?\n/, $directory) {
+ chomp $line;
+ if ($line =~ /^\[(.*)\]\s*$/) {
+ $section = $1;
+ };
+ if ($section eq 'Directory' && $line =~ /^Published: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})$/) {
+ my $date = $1;
+ print "Found published: $date\n" if ($VERBOSE >= 3);
+ $date =~ s#/#-#g;
+ $published = parsedate($date);
+ print "Parsed as $published (".(gmtime $published).")\n" if ($VERBOSE >= 4);
+ };
+ if ($section eq 'Directory' && $line =~ m#^Published: (\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2})$#) {
+ my $date = $1;
+ print "Found published: $date\n" if ($VERBOSE >= 3);
+ $date =~ s#/#-#g;
+ $published = parsedate($date);
+ print "Parsed as $published (".(gmtime $published).")\n" if ($VERBOSE >= 4);
+ };
+ if ($section eq 'Directory' && $line =~ /^Recommended-Servers: \s*(.*?)\s*$/) {
+ $recommended_servers = $1
+ };
+ if ($section eq 'Server' && $line =~ /Nickname: ([a-zA-Z0-9_-]+)\s*$/) {
+ $in_directory{$1} = 1;
+ };
+ }
+ close (DIRECTORY);
+ my @recommended_servers = split /,?\s*\s+/, $recommended_servers;
+ for my $node (@recommended_servers) {
+ $is_recommended{$node} = 1;
+ }
+
+ if ($published > $last) {
+ push @updateGlobal, $published.':'.(scalar keys %in_directory).':'.(scalar @recommended_servers);
+ $last = $published;
+ print "at ".(gmtime $published)." there are ".(scalar keys %in_directory).' in the directory and '.(scalar @recommended_servers)." recommended servers\n" if ($VERBOSE >= 3);
+ } else {
+ print "ignoring data at ".(gmtime $published)." because it's older than ".(gmtime $last)."\n" if ($VERBOSE >= 3);
+ };
+ for my $node (keys %in_directory) {
+ if (!defined $last_node{$node} || $published > $last_node{$node}) {
+ push @{$updates{$node}}, $published.':1:'.( defined $is_recommended{$node} ? '1' : '0' );
+ $last_node{$node} = $published;
+ }
+ delete $is_recommended{$node};
+ }
+ if (scalar keys %is_recommended) {
+ my $nodes = join ', ', keys %is_recommended;
+ warn ("$nodes recommended but not in directory.\n");
+ }
+};
+
+if (scalar @updateGlobal != 0) {
+ check_exists($RRD);
+ RRDs::update( $RRD, @updateGlobal );
+ my $err=RRDs::error;
+ warn "ERROR while updating $RRD: $err\n" if $err;
+};
+
+for my $node (keys %updates) {
+ if ($node =~ /[^a-zA-Z0-9_-]/) {
+ warn ("Illegal characters in node name '$node'\n");
+ next;
+ };
+ my $rrd = $RRD_DIR.'/'.$node.'.rrd';
+ check_exists($rrd);
+ RRDs::update( $rrd, @{$updates{$node}} );
+ my $err=RRDs::error;
+ warn "ERROR while updating $rrd: $err\n" if $err;
+};
diff --git a/other/tor/Makefile b/other/tor/Makefile
new file mode 100644
index 0000000..e08ee8e
--- /dev/null
+++ b/other/tor/Makefile
@@ -0,0 +1,25 @@
+TODAY=`TZ=UTC date +'%Y-%m-%d_%H:%M:%S'`
+WGET=wget --cache=off
+OUTDIR=tor-directory
+#SOURCE=http://moria.mit.edu:9031/
+SOURCE=http://tor.noreply.org:9030/
+TMPFILE=download.tmp
+LAST_NAME=dir.last
+
+all:
+ rm -f $(TMPFILE)
+ $(WGET) -q -O $(TMPFILE) $(SOURCE)
+ NAME=directory-$(TODAY); \
+ if [ -e $(LAST_NAME) ] && diff -q $(TMPFILE) $(OUTDIR)/`cat $(LAST_NAME)` >/dev/null ; then \
+ ln $(OUTDIR)/`cat $(LAST_NAME)` $(OUTDIR)/$$NAME; \
+ else \
+ mv $(TMPFILE) $(OUTDIR)/$$NAME; \
+ echo "$$NAME" > $(LAST_NAME); \
+ fi; \
+ bin/rrd-update $$NAME
+ rm -rf result.new
+ mkdir result.new
+ bin/rrd-graph
+ mv result result.old
+ mv result.new result
+ rm -rf result.old
diff --git a/other/tor/bin/rrd-graph b/other/tor/bin/rrd-graph
new file mode 100755
index 0000000..63c5c43
--- /dev/null
+++ b/other/tor/bin/rrd-graph
@@ -0,0 +1,413 @@
+#!/usr/bin/perl -w
+
+use strict;
+use RRDs;
+use BER;
+
+my $HOSTNAME = `hostname`;
+
+#my $IMG_URL = 'http://images.noreply.org/tor-running-routers/';
+#my $IMG_URL = 'http://new.noreply.org/tor-running-routers/';
+my $IMG_URL = '';
+my $NOW = time;
+my $GMTIME = gmtime($NOW);
+my $START_AT = $NOW-4*30*24*3600;
+my $END_AT = $NOW-4*3600;
+my $OLD_AT = $NOW-7*24*3600;
+my $RRD = '/home/weasel/www/www.noreply.org/Build/other/tor/rrd/running_Routers.rrd';
+my $RRD_DIR = '/home/weasel/www/www.noreply.org/Build/other/tor/rrd/nodes';
+my $INDEX_DIR = '/home/weasel/www/www.noreply.org/Build/other/tor/index';
+my $RESULT_DIR = 'result.new';
+
+# Get list of RRD files
+opendir(D,$RRD_DIR) or die ("Cannot opendir $RRD_DIR: $!\n");
+my @SOURCES = grep { /\.rrd$/ } readdir(D);
+@SOURCES = grep {
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = stat($RRD_DIR.'/'.$_);
+ $mtime >= $START_AT;
+ } @SOURCES;
+closedir(D);
+
+# Read hash <-> name mapping
+my %hashes_router;
+opendir(D,$INDEX_DIR) or die ("Cannot opendir $INDEX_DIR: $!\n");
+my @NAME = grep { /\.name$/ } readdir(D);
+closedir(D);
+for my $hash (@NAME) {
+ my $f = $INDEX_DIR.'/'.$hash;
+ open (F, $f) or warn("Cannot open $f: $!\n"), next;
+ my $name = <F>;
+ my $platform = <F>;
+ my $published = <F>;
+ chomp $name;
+ chomp $platform;
+ chomp $published;
+ close F;
+ $hash =~ s/\.name$//;
+ $hashes_router{$hash} = {name => $name, platform => $platform, published => $published };
+};
+
+@SOURCES = grep { !/^TRAF-/ } @SOURCES;
+@SOURCES = sort {
+ my $aa = $a;
+ my $bb = $b;
+ $aa =~ s/\.rrd//;
+ $bb =~ s/\.rrd//;
+ lc($hashes_router{$aa}->{'name'}) cmp lc($hashes_router{$bb}->{'name'}) ||
+ $a cmp $b
+ } @SOURCES;
+
+my @params = 'MAGIX1';
+push @params, sprintf('MAGIX2');
+push @params, sprintf('-e %s', $END_AT);
+#push @params, sprintf('-e %s', $NOW- 2*24*3600);
+push @params, sprintf('-t %s', "Running routers");
+push @params, sprintf('-aPNG');
+push @params, sprintf('-v %s', "# Routers");
+#push @params, sprintf('-w %d', 600);
+#push @params, sprintf('-h %d', 400);
+push @params, sprintf('-w %d', 497);
+push @params, sprintf('-h %d', 301);
+#push @params, sprintf('-h %d', 271);
+
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_runningVerified' , $RRD, 'runningVerified', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_runningVerified' , 'd_runningVerified');
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_runningUnverified' , $RRD, 'runningUnverified', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_runningUnverified' , 'd_runningUnverified');
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_exit80Verified' , $RRD, 'exit80Verified', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_exit80Verified' , 'd_exit80Verified');
+
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_f_runningVerified' , $RRD, 'fastRunningVerified', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_f_runningVerified' , 'd_f_runningVerified');
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_f_runningUnverified' , $RRD, 'fastRunningUnverifi', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_f_runningUnverified' , 'd_f_runningUnverified');
+push @params, sprintf('DEF:%s=%s:%s:%s', 'd_f_exit80Verified' , $RRD, 'fastExit80Verified', 'AVERAGE');
+push @params, sprintf('CDEF:%s=%s' , 'c_f_exit80Verified' , 'd_f_exit80Verified');
+
+#push @params, sprintf('%s:%s#%s:%s' , 'AREA' , 'c_runningVerified' , '7777FF', 'verified Nodes' );
+#push @params, sprintf('%s:%s#%s:%s' , 'STACK' , 'c_runningUnverified' , 'FF7700', 'unverified Nodes' );
+#push @params, sprintf('%s:%s#%s:%s' , 'LINE3' , 'c_exit80Verified' , '00FF00', 'verified Nodes exiting to port 80' );
+push @params, sprintf('%s:%s#%s:%s' , 'AREA' , 'c_runningVerified' , 'AAAAFF', 'verified Nodes' );
+push @params, sprintf('%s:%s#%s:%s' , 'STACK' , 'c_runningUnverified' , 'FF7700', '+unverified Nodes' );
+push @params, sprintf('%s:%s#%s:%s' , 'LINE2' , 'c_exit80Verified' , 'BBFFBB', 'verified Nodes exiting to port 80' );
+
+push @params, sprintf('%s:%s#%s:%s' , 'LINE3' , 'c_f_runningVerified' , '0000FF', 'fast verified Nodes' );
+push @params, sprintf('%s:%s#%s:%s' , 'STACK' , 'c_f_runningUnverified' , 'FF0000', '+fast unverified Nodes' );
+push @params, sprintf('%s:%s#%s:%s' , 'LINE3' , 'c_f_exit80Verified' , '00FF00', 'fast verified Nodes exiting to port 80' );
+
+push @params, sprintf('CDEF:%s=d_runningVerified,0,*,%s,+' , 'zeroline' , '0');
+push @params, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+
+
+my @totalTraffic = 'MAGIX1';
+push @totalTraffic, sprintf('MAGIX2');
+#push @totalTraffic, sprintf('-s %s', $START_AT);
+push @totalTraffic, sprintf('-e %s', $END_AT);
+#push @totalTraffic, sprintf('-e %s', $NOW- 2*24*3600);
+push @totalTraffic, sprintf('-t %s', "Total Traffic");
+push @totalTraffic, sprintf('-aPNG');
+push @totalTraffic, sprintf('-v %s', "Bandwidth Used");
+#push @totalTraffic, sprintf('-w %d', 600);
+#push @totalTraffic, sprintf('-h %d', 400);
+push @totalTraffic, sprintf('-w %d', 497);
+push @totalTraffic, sprintf('-h %d', 201);
+#push @totalTraffic, sprintf('-h %d', 301);
+#push @totalTraffic, sprintf('-h %d', 271);
+
+
+my %body;
+my %index;
+my $traf_item_counter = 0;
+
+for my $source (@SOURCES) {
+ my $hash = $source;
+ $hash =~ s/\.rrd$//;
+ my $name = $hashes_router{$hash}->{'name'};
+ my $platform = $hashes_router{$hash}->{'platform'};
+ my $published = $hashes_router{$hash}->{'published'};
+ my $def = $name;
+ my $cdef = 'c_'.$def;
+ my $label = $def;
+
+ my $source_traffic = $RRD_DIR .'/TRAF-'. $source;
+ $source = $RRD_DIR .'/'. $source;
+
+ my (undef,undef,undef,undef,undef,undef,undef,undef, undef,$mtime,undef,undef,undef) = stat($source);
+ my $section = $mtime < $OLD_AT ? 'old' : 'current';
+
+
+ my @this;
+ push @this, sprintf($RESULT_DIR.'/node-%s.png', $hash);
+ push @this, sprintf('-s %s', $START_AT);
+ push @this, sprintf('-e %s', $END_AT);
+ push @this, sprintf('-t %s', "$name");
+ push @this, sprintf('-aPNG');
+ push @this, sprintf('-v %s', "running");
+ push @this, sprintf('-w %d', 150);
+ push @this, sprintf('-h %d', 50);
+
+ push @this, sprintf('DEF:%s=%s:%s:%s', 'd_runningVerified' , $source, 'runningVerified', 'AVERAGE');
+ push @this, sprintf('CDEF:%s=%s' , 'c_runningVerified' , 'd_runningVerified');
+
+ push @this, sprintf('DEF:%s=%s:%s:%s', 'd_runningUnverified' , $source, 'runningUnverified', 'AVERAGE');
+ push @this, sprintf('CDEF:%s=%s' , 'c_runningUnverified' , 'd_runningUnverified');
+
+ push @this, sprintf('DEF:%s=%s:%s:%s', 'd_exit80Verified' , $source, 'exit80Verified', 'AVERAGE');
+ push @this, sprintf('CDEF:c_exit80Verified=d_exit80Verified,0.5,*,c_runningVerified,*');
+
+ push @this, sprintf('%s:%s#%s' , 'AREA' , 'c_runningVerified' , '7777FF' );
+ push @this, sprintf('%s:%s#%s' , 'STACK' , 'c_runningUnverified' , 'FF7700' );
+ push @this, sprintf('%s:%s#%s' , 'AREA' , 'c_exit80Verified' , '00FF00' );
+
+ push @this, sprintf('CDEF:%s=d_runningVerified,0,*,%s,+' , 'zeroline' , '0');
+ push @this, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+ my ($averages,$xsize,$ysize) = RRDs::graph @this;
+ warn RRDs::error if RRDs::error;
+
+ $body{$section} .= "<h2><a name=\"$hash\">$name</a></h2>".
+ "<p>".
+ "Last descriptor data:".
+ "<blockquote>".
+ "platform $platform<br>".
+ "published $published".
+ "</blockquote>".
+ "<p><img width=\"$xsize\" height=\"$ysize\" alt=\"$name running\" src=\"$IMG_URL"."node-$hash.png\">\n";
+ $index{$section} .= "<li><a href=\"$section.html#$hash\">$name</a></li>\n";
+
+ if (-e $source_traffic) {
+ $traf_item_counter++;
+ push @totalTraffic, sprintf('DEF:read%d=%s:read:AVERAGE', $traf_item_counter, $source_traffic);
+ push @totalTraffic, sprintf('DEF:write%d=%s:write:AVERAGE', $traf_item_counter, $source_traffic);
+ push @totalTraffic, sprintf('DEF:max_read%d=%s:read:MAX', $traf_item_counter, $source_traffic);
+ push @totalTraffic, sprintf('DEF:max_write%d=%s:write:MAX', $traf_item_counter, $source_traffic);
+ #push @totalTraffic, sprintf('DEF:min_read%d=%s:read:MIN', $traf_item_counter, $source_traffic);
+ #push @totalTraffic, sprintf('DEF:min_write%d=%s:write:MIN', $traf_item_counter, $source_traffic);
+ push @totalTraffic, sprintf('DEF:max_capacity%d=%s:capacity:MAX', $traf_item_counter, $source);
+
+ push @totalTraffic, sprintf('CDEF:cleanread%d=read%d,UN,0,read%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:cleanwrite%d=write%d,UN,0,write%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_cleanread%d=max_read%d,UN,0,max_read%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_cleanwrite%d=max_write%d,UN,0,max_write%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ #push @totalTraffic, sprintf('CDEF:min_cleanread%d=min_read%d,UN,0,min_read%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ #push @totalTraffic, sprintf('CDEF:min_cleanwrite%d=min_write%d,UN,0,min_write%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_cleancapacity%d=max_capacity%d,UN,0,max_capacity%d,IF', $traf_item_counter, $traf_item_counter, $traf_item_counter);
+
+ if ($traf_item_counter == 1) {
+ push @totalTraffic, sprintf('CDEF:aggread%d=cleanread%d', $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:aggwrite%d=cleanwrite%d', $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_aggread%d=max_cleanread%d', $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_aggwrite%d=max_cleanwrite%d', $traf_item_counter, $traf_item_counter);
+ #push @totalTraffic, sprintf('CDEF:min_aggread%d=min_cleanread%d', $traf_item_counter, $traf_item_counter);
+ #push @totalTraffic, sprintf('CDEF:min_aggwrite%d=min_cleanwrite%d', $traf_item_counter, $traf_item_counter);
+ push @totalTraffic, sprintf('CDEF:max_aggcapacity%d=max_cleancapacity%d', $traf_item_counter, $traf_item_counter);
+ } else {
+ push @totalTraffic, sprintf('CDEF:aggread%d=cleanread%d,aggread%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ push @totalTraffic, sprintf('CDEF:aggwrite%d=cleanwrite%d,aggwrite%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ push @totalTraffic, sprintf('CDEF:max_aggread%d=max_cleanread%d,max_aggread%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ push @totalTraffic, sprintf('CDEF:max_aggwrite%d=max_cleanwrite%d,max_aggwrite%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ #push @totalTraffic, sprintf('CDEF:min_aggread%d=min_cleanread%d,min_aggread%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ #push @totalTraffic, sprintf('CDEF:min_aggwrite%d=min_cleanwrite%d,min_aggwrite%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ push @totalTraffic, sprintf('CDEF:max_aggcapacity%d=max_cleancapacity%d,max_aggcapacity%d,+', $traf_item_counter, $traf_item_counter, $traf_item_counter-1);
+ };
+
+ for my $thumb (0, 1) {
+ @this = ();
+ push @this, sprintf($RESULT_DIR.'/node-'.($thumb ? 'small-' : '').'traf-%s.png', $hash);
+ #push @this, sprintf('-s %s', '-604800');
+ push @this, sprintf('-s %s', $START_AT);
+ push @this, sprintf('-e %s', $END_AT);
+ push @this, sprintf('-t %s', "$name traffic");
+ push @this, sprintf('-v %s', "bytes/sec");
+ if ($thumb) {
+ push @this, sprintf('-w %d', 150);
+ push @this, sprintf('-h %d', 50);
+ };
+ push @this, sprintf('-aPNG');
+ push @this, sprintf('DEF:read=%s:read:AVERAGE', $source_traffic);
+ push @this, sprintf('DEF:maxread=%s:read:MAX', $source_traffic);
+ #push @this, sprintf('DEF:minread=%s:read:MIN', $source_traffic);
+ push @this, sprintf('DEF:write=%s:write:AVERAGE', $source_traffic);
+ push @this, sprintf('DEF:maxwrite=%s:write:MAX', $source_traffic);
+ #push @this, sprintf('DEF:minwrite=%s:write:MIN', $source_traffic);
+ push @this, sprintf('DEF:maxcapacity=%s:capacity:MAX', $source);
+ push @this, sprintf('AREA:read#00FF00:Read');
+ push @this, sprintf('LINE2:write#0000FF:Write');
+ unless ($thumb) {
+ push @this, sprintf('LINE1:maxread#009A2C:Read [max 15min]');
+ push @this, sprintf('LINE1:maxwrite#5555FF:Write [max 15min]');
+ #push @this, sprintf('LINE1:minread#FF76D4:Read [min]');
+ #push @this, sprintf('LINE1:minwrite#222255:Write [min]');
+ push @this, sprintf('LINE1:maxcapacity#FF5555:Capacity');
+ }
+ #push @this, sprintf('COMMENT:\\n');
+ #push @this, sprintf('COMMENT:%s\\r', $GMTIME);
+ #push @this, sprintf('COMMENT:\\n');
+ #push @this, sprintf('COMMENT: Min Max Average Last\\n');
+ #push @this, sprintf('COMMENT:Read: ');
+ #push @this, sprintf('GPRINT:minread:MIN:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:maxread:MAX:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:read:AVERAGE:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:read:LAST:%6.2lf %sb/s\\n');
+ #push @this, sprintf('COMMENT:Write: ');
+ #push @this, sprintf('GPRINT:minwrite:MIN:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:maxwrite:MAX:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:write:AVERAGE:%6.2lf %sb/s ');
+ #push @this, sprintf('GPRINT:write:LAST:%6.2lf %sb/s\\n');
+
+ #push @this, sprintf('CDEF:%s=read,0,*,%s,+' , 'zeroline' , '0');
+ #push @this, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+ ($averages,$xsize,$ysize) = RRDs::graph @this;
+ warn RRDs::error if RRDs::error;
+
+ };
+ $body{$section} .= " <a href=\"$IMG_URL"."node-traf-$hash.png\">";
+ $body{$section} .= "<img width=\"$xsize\" height=\"$ysize\" alt=\"$name traffic\" src=\"$IMG_URL"."node-small-traf-$hash.png\">";
+ $body{$section} .= "</a>";
+ };
+ #$body{$section} .= "<br><a href=\"#_top\">top</a>";
+ $body{$section} .= "<br><a href=\"./\">back</a>";
+ $body{$section} .= '</p>';
+};
+push @totalTraffic, sprintf('AREA:aggread%d#00FF00:Read bytes/s', $traf_item_counter);
+push @totalTraffic, sprintf('LINE2:aggwrite%d#0000FF:Write bytes/s', $traf_item_counter);
+push @totalTraffic, sprintf('LINE1:max_aggread%d#009A2C:Read [max 15min]', $traf_item_counter);
+push @totalTraffic, sprintf('LINE1:max_aggwrite%d#5555FF:Write [max 15min]', $traf_item_counter);
+#push @totalTraffic, sprintf('LINE1:min_aggread%d#FF76D4:Read [min]', $traf_item_counter);
+#push @totalTraffic, sprintf('LINE1:min_aggwrite%d#222255:Write [min]', $traf_item_counter);
+push @totalTraffic, sprintf('LINE1:max_aggcapacity%d#FF5555:Capacity', $traf_item_counter);
+
+push @totalTraffic, sprintf('CDEF:zeroline=aggread%d,0,*', $traf_item_counter);
+push @totalTraffic, sprintf('%s:%s' , 'LINE1' , 'zeroline' );
+
+
+my $html = "<html><head><title>Number of Running Tor routers</title></head><body>";
+$html .= "<h1><a name=\"_top\">Number of Running Tor routers</a></h1>";
+$html .= "<a href=\"../\">..</a><br>\n";
+
+
+if ($params[0] ne 'MAGIX1' || $params[1] ne 'MAGIX2') {
+ warn "params[0,1] aren't MAGIX1,2. not nice";
+} else {
+ $params[0] = $RESULT_DIR.'/totalWeekly.png';
+ $params[1] = sprintf('-s %s', $NOW-7*24*3600);
+ my ($averages,$xsize,$ysize) = RRDs::graph @params;
+ warn RRDs::error if RRDs::error;
+
+ $params[0] = $RESULT_DIR.'/totalBiWeekly.png';
+ $params[1] = sprintf('-s %s', $NOW-14*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @params;
+ warn RRDs::error if RRDs::error;
+
+ $params[0] = $RESULT_DIR.'/totalMonthly.png';
+ $params[1] = sprintf('-s %s', $NOW-35*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @params;
+ warn RRDs::error if RRDs::error;
+
+ $params[0] = $RESULT_DIR.'/total.png';
+ $params[1] = sprintf('-s %s', $START_AT);
+ ($averages,$xsize,$ysize) = RRDs::graph @params;
+ warn RRDs::error if RRDs::error;
+
+ $params[0] = $RESULT_DIR.'/total9Months.png';
+ $params[1] = sprintf('-s %s', $NOW-9*30*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @params;
+ warn RRDs::error if RRDs::error;
+
+ $html .= "<p><img width=\"$xsize\" height=\"$ysize\" src=\"$IMG_URL"."total.png\"></p>";
+ $html .= "<p>\"Fast\" means a capacity of over 20,000 bytes/second</p>\n";
+ $html .= "<p>Number of routers over the <a href=\"$IMG_URL"."total9Months.png\">last 9 months</a> | ";
+ $html .= " <a href=\"$IMG_URL"."totalMonthly.png\">last month</a> |";
+ $html .= " <a href=\"$IMG_URL"."totalBiWeekly.png\">last 2 weeks</a></p>";
+};
+
+
+if ($totalTraffic[0] ne 'MAGIX1' || $totalTraffic[1] ne 'MAGIX2') {
+ warn "totalTraffic[0,1] aren't MAGIX1,2. not nice";
+} else {
+ $totalTraffic[0] = $RESULT_DIR.'/totalTrafficWeekly.png';
+ $totalTraffic[1] = sprintf('-s %s', $NOW-7*24*3600);
+ my ($averages,$xsize,$ysize) = RRDs::graph @totalTraffic;
+ warn RRDs::error if RRDs::error;
+
+ $totalTraffic[0] = $RESULT_DIR.'/totalTrafficBiWeekly.png';
+ $totalTraffic[1] = sprintf('-s %s', $NOW-14*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @totalTraffic;
+ warn RRDs::error if RRDs::error;
+
+ $totalTraffic[0] = $RESULT_DIR.'/totalTrafficMonthly.png';
+ $totalTraffic[1] = sprintf('-s %s', $NOW-35*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @totalTraffic;
+ warn RRDs::error if RRDs::error;
+
+ $totalTraffic[0] = $RESULT_DIR.'/totalTraffic.png';
+ $totalTraffic[1] = sprintf('-s %s', $START_AT);
+ ($averages,$xsize,$ysize) = RRDs::graph @totalTraffic;
+ warn RRDs::error if RRDs::error;
+
+ $totalTraffic[0] = $RESULT_DIR.'/totalTraffic9Months.png';
+ $totalTraffic[1] = sprintf('-s %s', $NOW-9*30*24*3600);
+ ($averages,$xsize,$ysize) = RRDs::graph @totalTraffic;
+ warn RRDs::error if RRDs::error;
+
+ $html .= "<p><img width=\"$xsize\" height=\"$ysize\" src=\"$IMG_URL"."totalTraffic.png\"></p>";
+ $html .= "<p>Bandwidth usage for <a href=\"$IMG_URL"."totalTraffic9Months.png\">last 9 months</a> | ";
+ $html .= " <a href=\"$IMG_URL"."totalTrafficMonthly.png\">last month</a> |";
+ $html .= " <a href=\"$IMG_URL"."totalTrafficBiWeekly.png\">last 2 weeks</a></p>";
+}
+
+
+
+$html .= "<p>The directory is downloaded from ";
+ $html .= "<a href=\"http://tor.noreply.org:9030/\">http://tor.noreply.org:9030/</a>";
+
+$html .= " at regular intervals.<br>\n";
+$html .= "Other directory sources are ";
+ $html .= "<a href=\"http://moria.mit.edu:9031/\">http://moria.mit.edu:9031/</a>";
+
+$html .= " and\n";
+ $html .= "<a href=\"http://moria.mit.edu:9032/\">http://moria.mit.edu:9032/</a>";
+
+$html .= ".";
+$html .= "<h1>Recent Nodes</h1>";
+$html .= "<ul>".$index{'current'}."</ul>";
+#$html .= $body{'current'};
+$html .= "<h1>Older Nodes</h1>";
+$html .= "<ul>".$index{'old'}."</ul>";
+#$html .= $body{'current'};
+$html .= "<br><br><br>\n";
+$html .= 'Images created with Tobi Oetiker\'s <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">rrdtool</a>'."\n";
+$html .= "<hr>\nBuilt at $GMTIME on $HOSTNAME<br>\n";
+$html .= "<a href=\"mailto:web\@palfrader.org\">Peter Palfrader &lt;web\@palfrader.org&gt;</a>\n";
+$html .= "</body></html>\n";
+
+open (F, ">$RESULT_DIR/index.html") or die ("Cannot open index.html: $!\n");
+print F $html;
+close F;
+
+open (F, ">$RESULT_DIR/current.html") or die ("Cannot open current.html: $!\n");
+print F "<html><head><title>Current Tor Routers</title></head><body>",
+ "<h1><a name=\"_top\">Current Tor routers</a></h1>",
+ "<a href=\"./\">./</a><br>\n",
+ $body{'current'},
+ "<br><br><br>\n",
+ 'Images created with Tobi Oetiker\'s <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">rrdtool</a>'."\n",
+ "<hr>\nBuilt at $GMTIME on $HOSTNAME<br>\n",
+ "<a href=\"mailto:web\@palfrader.org\">Peter Palfrader &lt;web\@palfrader.org&gt;</a>\n",
+ "</body></html>\n";
+close F;
+
+open (F, ">$RESULT_DIR/old.html") or die ("Cannot open old.html: $!\n");
+print F "<html><head><title>Older Tor Routers</title></head><body>",
+ "<h1><a name=\"_top\">Older Tor routers</a></h1>",
+ "<a href=\"./\">./</a><br>\n",
+ $body{'old'},
+ "<br><br><br>\n",
+ 'Images created with Tobi Oetiker\'s <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">rrdtool</a>'."\n",
+ "<hr>\nBuilt at $GMTIME on $HOSTNAME<br>\n",
+ "<a href=\"mailto:web\@palfrader.org\">Peter Palfrader &lt;web\@palfrader.org&gt;</a>\n",
+ "</body></html>\n";
+close F;
diff --git a/other/tor/bin/rrd-update b/other/tor/bin/rrd-update
new file mode 100755
index 0000000..885eef3
--- /dev/null
+++ b/other/tor/bin/rrd-update
@@ -0,0 +1,448 @@
+#!/usr/bin/perl -w
+
+use strict;
+use RRDs;
+use BER;
+use MIME::Base64;
+use Digest::SHA1 qw(sha1_hex);
+use Time::ParseDate;
+
+my $NOW = time;
+my $VERBOSE = 1;
+my $RRD = '/home/weasel/www/www.noreply.org/Build/other/tor/rrd/running_Routers.rrd';
+my $RRD_DIR = '/home/weasel/www/www.noreply.org/Build/other/tor/rrd/nodes';
+my $INDEX_DIR = '/home/weasel/www/www.noreply.org/Build/other/tor/index';
+my $DIR_DIR = '/home/weasel/www/www.noreply.org/Build/other/tor/tor-directory';
+my $MIN_BANDWIDTH_FOR_FAST = 20000;
+
+sub check_exists_running($$) {
+ my ($rrd, $global) = @_;
+ return if (-e $rrd);
+ my @params = ($rrd);
+ push @params, '-b', 'now - 12 months',
+ qw{ --step 3600
+ DS:runningVerified:GAUGE:172800:U:U
+ DS:runningUnverified:GAUGE:172800:U:U
+ DS:exit80Verified:GAUGE:172800:U:U };
+ if ($global) {
+ push @params, qw{
+ DS:fastRunningVerified:GAUGE:172800:U:U
+ DS:fastRunningUnverifi:GAUGE:172800:U:U
+ DS:fastExit80Verified:GAUGE:172800:U:U };
+ } else {
+ push @params, 'DS:capacity:GAUGE:172800:U:U';
+ };
+ push @params, qw{
+ RRA:MIN:0.5:1:336
+ RRA:MAX:0.5:1:336
+ RRA:AVERAGE:0.5:1:336
+ RRA:LAST:0.5:1:336
+ RRA:MIN:0.5:24:730
+ RRA:MAX:0.5:24:730
+ RRA:AVERAGE:0.5:24:730
+ };
+ print "Creating rrd: $rrd...\n" if $VERBOSE;
+ RRDs::create @params;
+ my $err=RRDs::error;
+ warn "ERROR while creating $rrd: $err\n" if $err;
+}
+sub check_exists_traffic($) {
+ my ($rrd) = @_;
+ return if (-e $rrd);
+ my @params = ($rrd);
+ push @params, '-b', 'now - 8 months',
+ qw{ --step 900
+ DS:write:ABSOLUTE:900:U:U
+ DS:read:ABSOLUTE:900:U:U
+ RRA:AVERAGE:0.5:1:600
+ RRA:AVERAGE:0.5:8:675
+ RRA:AVERAGE:0.5:96:789
+ RRA:MIN:0.5:1:600
+ RRA:MIN:0.5:8:675
+ RRA:MIN:0.5:96:789
+ RRA:MAX:0.5:1:600
+ RRA:MAX:0.5:8:675
+ RRA:MAX:0.5:96:789
+ RRA:LAST:0.5:1:600
+ RRA:LAST:0.5:8:675
+ RRA:LAST:0.5:96:789
+ };
+ print "Creating rrd: $rrd...\n" if $VERBOSE;
+ RRDs::create @params;
+ my $err=RRDs::error;
+ warn "ERROR while creating $rrd: $err\n" if $err;
+}
+sub get_last($) {
+ my ($rrd) = @_;
+ my $last = 0;
+ if ( -e $rrd) {
+ $last = RRDs::last($rrd);
+ my $err = RRDs::error;
+ warn "ERROR while getting last for $rrd: $err\n" if $err;
+ };
+ return $last;
+};
+
+check_exists_running($RRD, 1);
+my $last = get_last($RRD);
+
+opendir(DIR, $RRD_DIR) || die ("Cannot opendir $RRD_DIR: $!\n");
+my @rrdfiles = grep { /\.rrd$/ } readdir (DIR);
+closedir(DIR);
+my %last_node;
+for my $rrdfile (@rrdfiles) {
+ my $nodename = $rrdfile;
+ $nodename =~ s/\.rrd$//;
+ $last_node{$nodename} = get_last($RRD_DIR.'/'.$rrdfile);
+}
+
+my @dirfiles;
+if (scalar @ARGV) {
+ @dirfiles = @ARGV;
+} else {
+ opendir(DIR, $DIR_DIR) || die ("Cannot opendir $DIR_DIR: $!\n");
+ @dirfiles = sort { ($a cmp $b) } grep { /^directory-/ } readdir (DIR);
+ closedir(DIR);
+}
+
+my %KEY_TO_FPR_HASH = ();
+
+my %router_hashes;
+my %hashes_router;
+my @updateGlobal;
+my %updates;
+my %updates_traffic;
+for my $dir (@dirfiles) {
+ print "Doing $dir...\n" if $VERBOSE;
+ open (DIRECTORY, $DIR_DIR.'/'.$dir) || die ("Cannot open $DIR_DIR/$dir: $!\n");
+ # published 2004-06-11 02:07:01
+ # recommended-software 0.0.6.2,0.0.7pre1-cvs-2,0.0.7pre1,0.0.7rc1,0.0.7rc1-cvs,0.0.7rc2,0.0.7
+ # running-routers moria1 moria2 peacetime metacolo ovmja....
+ my $dir_published = undef;
+ my $running_routers = undef;
+ my $linenr = 0;
+ while (<DIRECTORY>) {
+ $linenr++;
+ chomp;
+ if (/^published (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})$/) {
+ if (!defined $dir_published) {
+ $dir_published = parsedate($1);
+ } else {
+ warn ("dir_published already set to '$dir_published' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^running-routers\s*(.*?)\s*$/) {
+ if (!defined $running_routers) {
+ $running_routers = $1
+ } else {
+ warn ("running_routers already set to '$running_routers' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ last if (/^\s*$/);
+ };
+
+ my $current_router = undef;
+ my $current_platform = undef;
+ my $current_published = undef;
+ my $current_capacity = undef;
+ my $current_hash = undef;
+ my %history;
+ my %router_desc;
+ my $current_write_history = undef;
+ my $current_read_history = undef;
+ my $current_port80 = undef;
+ while (<DIRECTORY>) {
+ $linenr++;
+ chomp;
+ if (/^router\s+(\S+)\s/) {
+ if (!defined $current_router) {
+ $current_router = $1;
+ } else {
+ warn ("current_router already set to '$current_router' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^platform\s+(.*)/) {
+ if (!defined $current_platform) {
+ $current_platform = $1;
+ } else {
+ warn ("current_platform already set to '$current_platform' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^published (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})$/) {
+ if (!defined $current_published) {
+ $current_published = $1;
+ } else {
+ warn ("current_published already set to '$current_published' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^bandwidth (\d+)\s+\d+\s+(\d+)$/) {
+ if (!defined $current_capacity) {
+ my $rate_limit = $1;
+ $current_capacity = $2;
+ $current_capacity = $rate_limit if ($rate_limit < $current_capacity);
+ } else {
+ warn ("current_capacity already set to '$current_capacity' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^opt write-history\s+(.*)/) {
+ if (!defined $current_write_history) {
+ $current_write_history = $1;
+ } else {
+ warn ("current_write_history already set to '$current_write_history' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^opt read-history\s+(.*)/) {
+ if (!defined $current_read_history) {
+ $current_read_history = $1;
+ } else {
+ warn ("current_read_history already set to '$current_read_history' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^(accept|reject) \*:(.*)/ && !defined $current_port80) {
+ my $policy = $1;
+ my $port = $2;
+ if ($port eq '*') {
+ $current_port80 = $policy eq 'accept';
+ } elsif ($port =~ /^(\d+)$/) {
+ $current_port80 = $policy eq 'accept' if $port == 80;
+ } elsif ($port =~ /^(\d+)-(\d+)$/) {
+ my $min = $1;
+ my $max = $2;
+ $current_port80 = $policy eq 'accept' if $min <= 80 && 80 <= $max;
+ } else {
+ warn ("Cannot parse port spec '$port' in directory $dir, line $linenr\n");
+ next;
+ }
+ };
+ if (/^signing-key/) {
+ if (!defined $current_hash) {
+ if ($linenr++ && <DIRECTORY> !~ /^-----BEGIN RSA PUBLIC KEY-----/) {
+ warn ("line after signing key not in expected form\n");
+ $current_router = undef;
+ $current_platform = undef;
+ $current_published = undef;
+ $current_capacity = undef;
+ $current_port80 = undef;
+ next;
+ };
+ my $key = '';
+ my $line;
+ while ($linenr++ && ($line = <DIRECTORY>)) {
+ last if ($line =~ /^-----END RSA PUBLIC KEY-----/);
+ $key .= $line;
+ }
+ if (!defined $line) {
+ warn ("No END RSA PUBLIC KEY in signing key of $current_router ($dir)\n");
+ last;
+ };
+ if (defined $KEY_TO_FPR_HASH{$key}) {
+ $current_hash = $KEY_TO_FPR_HASH{$key};
+ } else {
+ $current_hash = uc(sha1_hex(decode_base64($key)));
+ $KEY_TO_FPR_HASH{$key} = $current_hash;
+ };
+ } else {
+ warn ("current_hash already set to '$current_hash' in directory $dir, line $linenr\n");
+ next;
+ };
+ };
+ if (/^\s*$/) {
+ if (!defined $current_router) {
+ warn("end of block without current_router\n");
+ next;
+ };
+ if (!defined $current_platform) {
+ warn("end of block without current_platform\n");
+ next;
+ };
+ if (!defined $current_published) {
+ warn("end of block without current_published\n");
+ next;
+ };
+ if (!defined $current_capacity) {
+ if ($current_platform =~ /^Tor 0\.0\.(6|7|8pre1-cvs)/) {
+ $current_capacity = 'U';
+ } else {
+ warn("end of block without current_capacity in directory $dir, line $linenr\n");
+ exit;
+ };
+ };
+ if (!defined $current_port80) {
+ warn("end of block without current_port80\n");
+ next;
+ };
+ if (!defined $current_hash) {
+ warn("end of block without current_hash\n");
+ next;
+ };
+ $router_hashes{$current_router} = $current_hash;
+ $hashes_router{$current_hash} = { name => $current_router,
+ platform => $current_platform,
+ published => $current_published };
+ $router_desc{$current_hash} = { capacity => $current_capacity,
+ port80 => $current_port80 };
+ $history{$current_hash} = { write_history => $current_write_history,
+ read_history => $current_read_history};
+ $current_router = undef;
+ $current_platform = undef;
+ $current_published = undef;
+ $current_capacity = undef;
+ $current_port80 = undef;
+ $current_hash = undef;
+ $current_write_history = undef;
+ $current_read_history = undef;
+ }
+ }
+ close (DIRECTORY);
+
+ # find out which nodes are running
+ my @running_routers = split /\s+/, $running_routers;
+ @running_routers = grep {! /^!/ } @running_routers;
+ my @verified_routers;
+ my @verified_routers_port80;
+ my @unverified_routers;
+ my @fast_verified_routers;
+ my @fast_verified_routers_port80;
+ my @fast_unverified_routers;
+ for my $router (@running_routers) {
+ my $hash;
+ if ($router =~ /^\$/) {
+ $hash = substr($router, 1);
+ } else {
+ $hash = $router_hashes{$router};
+ if (!defined $hash) {
+ warn ("No hash known for $router\n");
+ next;
+ };
+ }
+
+ if (!defined $router_desc{$hash}->{'port80'}) {
+ warn ("port 80 not defined for $router (this most likely means it was in running-routers but there was no server descriptor)\n");
+ next;
+ };
+ if (!defined $router_desc{$hash}->{'capacity'}) {
+ warn ("capacity not defined for $router (this most likely means it was in running-routers but there was no server descriptor)\n");
+ next;
+ };
+
+ my $fast = 0;
+ if ($router_desc{$hash}->{'capacity'} eq 'U' || # in earlier times, all nodes where fast
+ $router_desc{$hash}->{'capacity'} >= $MIN_BANDWIDTH_FOR_FAST) {
+ $fast = 1;
+ };
+
+
+ if ($router =~ /^\$/) {
+ push @unverified_routers, $hash;
+ push @fast_unverified_routers, $hash if $fast;
+ } else {
+ push @verified_routers, $hash;
+ push @verified_routers_port80, $hash if ($router_desc{$hash}->{'port80'});
+
+ push @fast_verified_routers, $hash if $fast;
+ push @fast_verified_routers_port80, $hash if ($router_desc{$hash}->{'port80'} && $fast);
+ }
+
+ if (!defined $last_node{$hash} || $dir_published > $last_node{$hash}) {
+ push @{$updates{$hash}}, $dir_published.':'.
+ ($router =~ /^\$/ ? '0:1' : '1:0').':'.
+ $router_desc{$hash}->{'port80'}.':'.
+ $router_desc{$hash}->{'capacity'};
+ $last_node{$hash} = $dir_published;
+ }
+ }
+ if ($dir_published > $last) {
+ push @updateGlobal, $dir_published.':'.
+ (scalar @verified_routers).':'.
+ (scalar @unverified_routers).':'.
+ (scalar @verified_routers_port80).':'.
+ (scalar @fast_verified_routers).':'.
+ (scalar @fast_unverified_routers).':'.
+ (scalar @fast_verified_routers_port80);
+ $last = $dir_published
+ };
+
+ # update traffic stats for all routers
+ for my $hash (keys %history) {
+ my %hist;
+ for my $inout (qw{write read}) {
+ my $hist = $history{$hash}->{$inout.'_history'};
+ if (defined $hist) {
+ # 2004-09-26 01:45:45 (900 s) 9619165,12880477,10591411...
+ my ($time, $interval, $values) =
+ $hist =~ /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \((\d+) s\)\s?((?:\d+,)*\d+)?$/;
+ warn ("Could not parse history '$hist'\n"),next
+ unless defined $time;
+ my $stamp = parsedate($time);
+ warn ("Could not parse time in '$hist'\n"),next
+ unless defined $stamp;
+ next unless defined $values;
+ my @values = split /,/, $values;
+ for my $v (@values) {
+ $hist{$stamp}->{$inout} = $v;
+ $stamp -= $interval;
+ };
+ };
+ };
+ for my $stamp (sort {$a <=> $b} keys %hist) {
+ if (!defined $last_node{'TRAF-'.$hash} || $stamp > $last_node{'TRAF-'.$hash}) {
+ push @{$updates_traffic{$hash}}, $stamp.':'.
+ (defined $hist{$stamp}->{'write'} ? $hist{$stamp}->{'write'} : '').':'.
+ (defined $hist{$stamp}->{'read'} ? $hist{$stamp}->{'read'} : '');
+ $last_node{'TRAF-'.$hash} = $stamp;
+ };
+ };
+ };
+};
+
+if (scalar @updateGlobal != 0) {
+ check_exists_running($RRD, 1);
+ RRDs::update( $RRD, @updateGlobal );
+ my $err=RRDs::error;
+ warn "ERROR while updating $RRD: $err\n" if $err;
+};
+
+for my $router (keys %updates) {
+ next unless exists $hashes_router{$router};
+ my $rrd = $RRD_DIR.'/'.$router.'.rrd';
+ check_exists_running($rrd, 0);
+ RRDs::update( $rrd, @{$updates{$router}} );
+ my $err=RRDs::error;
+ warn "ERROR while updating $rrd: $err\n" if $err;
+ my (($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)) = localtime($last_node{$router});
+ my $stamp = sprintf("%04d%02d%02d%02d%02d.%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
+ print "Setting timestamp of $rrd to $stamp\n" if $VERBOSE;
+ system('touch', '-t', $stamp, $rrd);
+};
+
+for my $router (keys %updates_traffic) {
+ next unless exists $hashes_router{$router};
+ my $rrd = $RRD_DIR.'/TRAF-'.$router.'.rrd';
+ check_exists_traffic($rrd);
+ RRDs::update( $rrd, @{$updates_traffic{$router}} );
+ my $err=RRDs::error;
+ warn "ERROR while updating $rrd: $err\n" if $err;
+ my (($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)) = localtime($last_node{'TRAF-'.$router});
+ my $stamp = sprintf("%04d%02d%02d%02d%02d.%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
+ print "Setting timestamp of $rrd to $stamp\n" if $VERBOSE;
+ system('touch', '-t', $stamp, $rrd);
+};
+
+
+
+for my $hash (keys %hashes_router) {
+ my $f = $INDEX_DIR.'/'.$hash.".name";
+ open(I, ">$f") or warn ("Cannot open $f: $!\n"), next;
+ print I $hashes_router{$hash}->{'name'},"\n";
+ print I $hashes_router{$hash}->{'platform'},"\n";
+ print I $hashes_router{$hash}->{'published'},"\n";
+ close I;
+};