/[echolot]/trunk/pingd
ViewVC logotype

Contents of /trunk/pingd

Parent Directory Parent Directory | Revision Log Revision Log


Revision 123 - (hide annotations) (download)
Wed Jul 10 11:49:41 2002 UTC (10 years, 10 months ago) by weasel
File size: 15151 byte(s)
Moved from XML to Data::Dumper
1 weasel 1 #!/usr/bin/perl -wT
2    
3     # (c) 2002 Peter Palfrader <peter@palfrader.org>
4 weasel 123 # $Id: pingd,v 1.22 2002/07/10 11:49:41 weasel Exp $
5 weasel 1 #
6    
7 weasel 54 =pod
8    
9     =head1 NAME
10    
11     pingd - echolot ping daemon
12    
13     =head1 SYNOPSIS
14    
15     =over
16    
17     =item B<pingd> B<start>
18    
19     =item B<pingd> B<stop>
20    
21 weasel 88 =item B<pingd> B<process>
22    
23 weasel 75 =item B<pingd> B<add> I<address> [I<address> ...]
24 weasel 54
25 weasel 94 =item B<pingd> B<delete> I<address> [I<address> ...]
26    
27 weasel 75 =item B<pingd> B<set> option=value [option=value..] I<address> [I<address> ...]
28    
29 weasel 103 =item B<pingd> B<setremailercaps> I<capsstring>
30    
31     =item B<pingd> B<deleteremailercaps> I<address>
32    
33 weasel 94 =item B<pingd> B<getkeyconf>
34    
35 weasel 81 =item B<pingd> B<dumpconf>
36    
37 weasel 54 =back
38    
39     =head1 DESCRIPTION
40    
41     pingd is a the heart of echolot. Echolot is a pinger for anonymous remailers.
42    
43     A Pinger in the context of anonymous remailers is a program that regularily
44     sends messages through remailers to check their reliability. It then calculates
45     reliability statistics which are used by remailer clients to choose the chain
46     of remailers to use.
47    
48     Additionally it collects configuration parameters and keys of all remailers and
49     offers them in a format readable by remailer clients.
50    
51     When called without parameters pingd schedules tasks like sending pings,
52     processing incoming mail and requesting remailer-xxx data and runs them in
53     configurable intervalls.
54    
55     =head1 COMMANDS
56    
57     =over
58    
59     =item B<start>
60    
61     Start the ping daemon.
62    
63     =item B<stop>
64    
65     Send the running pingd process a SIGTERM.
66    
67 weasel 88 =item B<process>
68    
69     Sends a HUP signal to the daemon which instructs it to process the commands.
70    
71     For other affects of sending the HUP Signal see the SIGNALS section below.
72    
73 weasel 75 =item B<add> I<address> [I<address> ...]
74 weasel 54
75     Add I<address> to the list of remailers to query for
76     keys and confs.
77    
78 weasel 94 =item B<delete> I<address> [I<address> ...]
79    
80     Delete I<address> from the list of remailers to query for
81     keys and confs. Delete all statistics and key for that remailer.
82    
83 weasel 75 =item B<set> option=value [option=value..] I<address> [I<address> ...]
84    
85     Possible options and values:
86    
87     =over
88    
89     =item B<showit=>{B<on>,B<off>}
90    
91     Set B<showit> (show remailer in mlist, rlist etc.) for remailer I<address> to
92     either B<on> or B<off>.
93    
94     =item B<pingit=>{B<on>,B<off>}
95    
96     Set B<pingit> (send out pings to that remailer) for remailer I<address> to
97     either B<on> or B<off>.
98    
99     =item B<fetch=>{B<on>,B<off>}
100    
101     Set B<fetch> (fetch remailer-key and remailer-conf) for remailer I<address> to
102     either B<on> or B<off>.
103    
104     =back
105    
106 weasel 103 =item B<setremailercaps> I<capsstring>
107    
108     Some remailers (Mixmaster V2 - currently lcs and passthru2) don't return a
109     useable remailer-conf message. For such remailers you need to set it manually.
110    
111     For instance:
112    
113     ./pingd setremailercaps '$remailer{"passthru2"} = "<mixer@immd1.informatik.uni-erlangen.de> mix middle";'
114     ./pingd setremailercaps '$remailer{"lcs"} = "<mix@anon.lcs.mit.edu> mix klen1000";'
115    
116     =item B<deleteremailercaps> I<address>
117    
118     Delete remailer-conf data for I<address>. The config data will be reset from
119     the next valid remailer-conf reply by the remailer.
120    
121 weasel 94 =item B<getkeyconf>
122    
123     Send a command to immediatly request keys and configuration from remailers.
124    
125 weasel 81 =item B<dumpconf>
126    
127     Dumps the current configuration to standard output.
128    
129 weasel 103 =back
130    
131 weasel 54 =head1 OPTIONS
132    
133 weasel 81 =over
134 weasel 54
135 weasel 81 =item --verbose
136    
137     Verbose mode. Causes B<pingd> to print debugging messages about its progress.
138    
139     =item --help
140    
141     Print a short help and exit sucessfully.
142    
143 weasel 117 =item --version
144    
145     Print version number and exit sucessfully.
146    
147 weasel 94 =item --nohup
148 weasel 88
149 weasel 103 Usefull only when passwd with the B<add>, B<set>, B<setremailercaps>,
150     B<deleteremailercaps> or B<getkeyconf> command.
151 weasel 88
152 weasel 94 Don't send a HUP signal to the daemon which instructs it to process the
153     commands after adding the command to the task list.
154 weasel 88
155 weasel 94 Per default such a signal is sent.
156    
157 weasel 88 =item --detach
158    
159     Usefull only when passwd with the B<start> command.
160    
161     Tell B<pingd> to detach.
162    
163 weasel 54 =back
164    
165     =head1 FILES
166    
167 weasel 115 The configuration file is searched in those places in that order:
168 weasel 54
169 weasel 115 =over
170    
171     =item the file pointed to by the B<ECHOLOT_CONF> environment variable
172    
173     =item `pwd`/pingd.conf
174    
175     =item $HOME/echolot/pingd.conf
176    
177     =item $HOME/pingd.conf
178    
179     =item $HOME/.pingd.conf
180    
181     =item /etc/pingd.conf
182    
183     =back
184    
185 weasel 88 =head1 SIGNALS
186    
187 weasel 103 On B<SIGINT>, B<SIGQUIT>, and B<SIGTERM> B<pingd> will schedule a shutdown
188     for as soon as the current actions are finished or immediatly if no actions are
189     currently beeing processed. It will then write all metadata and pingdata to
190 weasel 88 disk and close all files cleanly before exiting.
191    
192     On B<SIGHUP> <pingd> will execute any pending commands from the commands file
193     (B<commands.txt> per default). It also closes and reopens the file 'output'
194     which is used for stdout and stderr in case the daemon was told to detach.
195     This can be used if you want to rotate that file.
196    
197 weasel 54 =head1 AUTHOR
198    
199 weasel 103 Peter Palfrader E<lt>peter@palfrader.orgE<gt>
200 weasel 54
201     =head1 BUGS
202    
203 weasel 103 Please report them at E<lt>URL:http://savannah.gnu.org/bugs/?group=echolotE<gt>
204 weasel 54
205     =cut
206    
207 weasel 1 use strict;
208     use Getopt::Long;
209 weasel 54 use English;
210 weasel 91 use Carp;
211 weasel 34 use lib qw{ . lib };
212 weasel 1 use Echolot::Config;
213     use Echolot::Globals;
214     use Echolot::Storage::File;
215 weasel 15 use Echolot::Scheduler;
216 weasel 1 use Echolot::Conf;
217     use Echolot::Mailin;
218 weasel 15 use Echolot::Pinger;
219 weasel 34 use Echolot::Stats;
220 weasel 54 use Echolot::Commands;
221 weasel 106 use Echolot::Thesaurus;
222 weasel 1
223     $ENV{'PATH'} = '/bin:/usr/bin';
224     delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
225    
226 weasel 54
227 weasel 117 my $VERSION = '2.0beta1';
228    
229    
230 weasel 88 my $redirected_stdio = 0;
231 weasel 54
232     sub setSigHandlers() {
233     $SIG{'HUP'} = sub {
234 weasel 115 print "Got SIGHUP. scheduling readcommands\n";
235 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() );
236 weasel 88 if ($redirected_stdio) {
237     close STDOUT;
238     close STDERR;
239     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
240     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
241     };
242 weasel 54 };
243     $SIG{'INT'} = sub {
244     print "Got SIGINT. scheduling exit\n";
245 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
246 weasel 54 };
247     $SIG{'QUIT'} = sub {
248     print "Got SIGQUIT. scheduling exit\n";
249 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
250 weasel 54 };
251     $SIG{'TERM'} = sub {
252     print "Got SIGTERM. scheduling exit\n";
253 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
254 weasel 54 };
255 weasel 34 };
256 weasel 54
257 weasel 88
258    
259 weasel 54 sub commit_prospective_address() {
260     Echolot::Globals::get()->{'storage'}->commit_prospective_address();
261 weasel 34 };
262 weasel 60 sub expire() {
263     Echolot::Globals::get()->{'storage'}->expire();
264     };
265 weasel 54
266    
267    
268    
269    
270 weasel 94 sub command_adddelete(@) {
271     my $command = shift @_;
272 weasel 88 my @argv = @_;
273 weasel 54
274 weasel 94 die ("command_adddelete requires command\n") unless defined $command;
275 weasel 88 die ("add requires argument <address>\n") unless scalar @argv;
276 weasel 75 my @addresses;
277 weasel 88 for my $address (@argv) {
278 weasel 75 die ("argument <address> is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
279     push @addresses, $address;
280     };
281     for my $address (@addresses) {
282 weasel 94 Echolot::Commands::addCommand("$command $address");
283 weasel 75 };
284 weasel 88 };
285    
286     sub command_set(@) {
287     my @argv = @_;
288    
289 weasel 75 my @settings;
290 weasel 88 while (scalar @argv && $argv[0] =~ /^(showit|pingit|fetch)=(on|off)$/) {
291     push @settings, $argv[0];
292     shift @argv;
293 weasel 75 };
294    
295     my @addresses;
296 weasel 88 for my $address (@argv) {
297 weasel 75 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
298     push @addresses, $address;
299     };
300    
301 weasel 88 for my $address (@argv) {
302 weasel 75 for my $setting (@settings) {
303     Echolot::Commands::addCommand("set $address $setting");
304     };
305     };
306 weasel 88 };
307    
308 weasel 103 sub command_setremailercaps(@) {
309     my @argv = @_;
310 weasel 94
311 weasel 103 my @caps;
312     for my $caps (@argv) {
313     my ($remailer_nick, $remailer_address) = ($caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix);
314     die ("caps '$caps' is not a valid remailer caps line\n") unless (defined $remailer_nick && defined $remailer_address);
315     push @caps, {
316     address => $remailer_address,
317     caps => $caps };
318     };
319     for my $caps (@caps) {
320     Echolot::Commands::addCommand("setremailercaps ".$caps->{'address'}." ".$caps->{'caps'});
321     };
322     };
323 weasel 94
324 weasel 103 sub command_deleteremailercaps(@) {
325     my @argv = @_;
326    
327     my @addresses;
328     for my $address (@argv) {
329     die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
330     push @addresses, $address;
331     };
332    
333     for my $address (@argv) {
334     Echolot::Commands::addCommand("deleteremailercaps $address");
335     };
336     };
337    
338    
339 weasel 88 sub pid_exists() {
340     return (-e Echolot::Config::get()->{'pidfile'});
341     };
342    
343     sub daemon_run() {
344     die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
345     if pid_exists();
346     open (PIDFILE, '>'.Echolot::Config::get()->{'pidfile'}) or
347 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
348 weasel 88 print PIDFILE "$PROCESS_ID ".Echolot::Globals::get()->{'hostname'}." ".time()."\n";
349     close PIDFILE;
350    
351 weasel 60 Echolot::Globals::initStorage();
352 weasel 54 setSigHandlers();
353 weasel 1
354 weasel 94 Echolot::Globals::get()->{'scheduler'} = new Echolot::Scheduler;
355     my $scheduler = Echolot::Globals::get()->{'scheduler'};
356 weasel 83 $scheduler->add('exit' , -1 , 0, 'exit' );
357     $scheduler->add('readcommands' , -1 , 0, \&Echolot::Commands::processCommands );
358 weasel 1
359 weasel 83 $scheduler->add('processmail' , Echolot::Config::get()->{'processmail'} , 0, \&Echolot::Mailin::process );
360     $scheduler->add('ping' , Echolot::Config::get()->{'pinger_interval'} , 0, \&Echolot::Pinger::send_pings );
361 weasel 107 $scheduler->add('buildstats' , Echolot::Config::get()->{'buildstats'} , 0, \&Echolot::Stats::build_stats );
362     $scheduler->add('buildkeys' , Echolot::Config::get()->{'buildkeys'} , 0, \&Echolot::Stats::build_keys );
363 weasel 106 $scheduler->add('buildthesaurus' , Echolot::Config::get()->{'build_thesaurus'} , 0, \&Echolot::Thesaurus::build_thesaurus );
364 weasel 54
365 weasel 83 $scheduler->add('commitprospectives' , Echolot::Config::get()->{'commitprospectives'} , 0, \&commit_prospective_address );
366     $scheduler->add('expire' , Echolot::Config::get()->{'expire'} , 0, \&expire );
367     $scheduler->add('getkeyconf' , Echolot::Config::get()->{'getkeyconf'} , 0, \&Echolot::Conf::send_requests );
368 weasel 121 $scheduler->add('check_resurrection' , Echolot::Config::get()->{'check_resurrection'} , 0, \&Echolot::Conf::check_resurrection );
369 weasel 54
370     $scheduler->run();
371    
372     Echolot::Globals::get()->{'storage'}->commit();
373     Echolot::Globals::get()->{'storage'}->finish();
374 weasel 88
375     unlink (Echolot::Config::get()->{'pidfile'}) or
376     cluck ("Cannot unlink pidfile ".Echolot::Config::get()->{'pidfile'});
377     };
378    
379     sub send_sig($) {
380     my ($sig) = @_;
381    
382 weasel 107 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' does not exist\n")
383 weasel 88 unless pid_exists();
384     open (PIDFILE, '<'.Echolot::Config::get()->{'pidfile'}) or
385 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
386 weasel 88 my $line = <PIDFILE>;
387     close PIDFILE;
388    
389     my ($pid, $host, $time) = $line =~ /^(\d+) \s+ (\S+) \s+ (\d+) \s* $/x or
390 weasel 91 croak ("Cannot parse pidfile '$line'\n");
391 weasel 88 my $sent = kill $sig, $pid;
392     ($sent == 1) or
393 weasel 91 croak ("Did not send signal $sig to exactly one process but $sent. (pidfile reads $line)\n");
394 weasel 88 };
395    
396     sub daemon_hup() {
397     send_sig(1);
398     };
399    
400     sub daemon_stop() {
401     send_sig(15);
402     };
403    
404 weasel 91 sub make_dirs() {
405     for my $dir (
406     Echolot::Config::get()->{'resultdir'},
407 weasel 106 Echolot::Config::get()->{'thesaurusdir'},
408 weasel 91 Echolot::Config::get()->{'private_resultdir'},
409     Echolot::Config::get()->{'gnupghome'},
410     Echolot::Config::get()->{'tmpdir'},
411     Echolot::Config::get()->{'storage'}->{'File'}->{'basedir'}
412     ) {
413     if ( ! -d $dir ) {
414     mkdir ($dir) or
415     croak ("Cannot create directory $dir: $!\n");
416     };
417     };
418     for my $dir (
419     Echolot::Config::get()->{'mailindir'},
420     Echolot::Config::get()->{'mailindir'}.'/cur',
421     Echolot::Config::get()->{'mailindir'}.'/tmp',
422     Echolot::Config::get()->{'mailindir'}.'/new',
423     Echolot::Config::get()->{'mailerrordir'},
424     Echolot::Config::get()->{'mailerrordir'}.'/cur',
425     Echolot::Config::get()->{'mailerrordir'}.'/tmp',
426     Echolot::Config::get()->{'mailerrordir'}.'/new'
427     ) {
428     if ( ! -d $dir ) {
429     mkdir ($dir, 0700) or
430     croak ("Cannot create directory $dir: $!\n");
431     };
432     };
433     };
434 weasel 88
435 weasel 91
436    
437    
438    
439    
440    
441    
442    
443    
444    
445    
446 weasel 88 my $params;
447     Getopt::Long::config('bundling');
448     if (!GetOptions (
449     'help' => \$params->{'help'},
450 weasel 117 'version' => \$params->{'version'},
451 weasel 88 'verbose' => \$params->{'verbose'},
452 weasel 94 'nohup' => \$params->{'nohup'},
453 weasel 88 'detach' => \$params->{'detach'},
454     )) {
455     die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
456     };
457     if ($params->{'help'}) {
458 weasel 115 print ("Usage: $PROGRAM_NAME [options] command\n");
459     print ("See man pingd or perldoc pingd for more info.\n");
460 weasel 117 print ("echolot $VERSION - (c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
461     print ("http://savannah.gnu.org/projects/echolot/\n");
462 weasel 88 exit 0;
463     };
464 weasel 117 if ($params->{'version'}) {
465     print ("echolot $VERSION\n");
466     print ("(c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
467     print ("http://savannah.gnu.org/projects/echolot/\n");
468     exit 0;
469     };
470 weasel 88
471     my $COMMAND = shift @ARGV;
472     die ("command required\n") unless defined $COMMAND;
473    
474    
475     Echolot::Config::init( $params );
476     chdir( Echolot::Config::get()->{'homedir'} );
477     Echolot::Globals::init();
478    
479    
480 weasel 94 if ($COMMAND eq 'add' || $COMMAND eq 'delete') {
481     command_adddelete($COMMAND, @ARGV);
482     if (!$params->{'nohup'} && pid_exists()) {
483 weasel 88 daemon_hup()
484     } else {
485     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
486     };
487     } elsif ($COMMAND eq 'set') {
488     command_set(@ARGV);
489 weasel 94 if (!$params->{'nohup'} && pid_exists()) {
490 weasel 88 daemon_hup()
491     } else {
492     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
493     };
494 weasel 103 } elsif ($COMMAND eq 'setremailercaps') {
495     command_setremailercaps(@ARGV);
496     if (!$params->{'nohup'} && pid_exists()) {
497     daemon_hup()
498     } else {
499     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
500     };
501     } elsif ($COMMAND eq 'deleteremailercaps') {
502     command_deleteremailercaps(@ARGV);
503     if (!$params->{'nohup'} && pid_exists()) {
504     daemon_hup()
505     } else {
506     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
507     };
508 weasel 94 } elsif ($COMMAND eq 'getkeyconf') {
509     Echolot::Commands::addCommand("getkeyconf");
510     if (!$params->{'nohup'} && pid_exists()) {
511     daemon_hup()
512     } else {
513     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
514     };
515 weasel 88 } elsif ($COMMAND eq 'process') {
516     daemon_hup();
517     } elsif ($COMMAND eq 'stop') {
518     daemon_stop();
519     } elsif ($COMMAND eq 'start') {
520 weasel 103 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
521     if pid_exists();
522 weasel 91 make_dirs();
523 weasel 88 if ($params->{'detach'}) {
524     print "Detaching.\n";
525     unless (fork()) {
526     close STDOUT;
527     close STDERR;
528     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
529     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
530     close STDIN;
531     $redirected_stdio = 1;
532 weasel 105 print "Startup at ".scalar localtime().".\n";
533 weasel 88 daemon_run();
534 weasel 105 print "done at ".scalar localtime().".\n";
535 weasel 88 };
536     } else {
537     daemon_run();
538     };
539 weasel 81 } elsif ($COMMAND eq 'dumpconf') {
540     Echolot::Config::dump();
541 weasel 75 } elsif ($COMMAND eq 'convert') {
542     Echolot::Globals::initStorage();
543     setSigHandlers();
544    
545     Echolot::Globals::get()->{'storage'}->convert();
546    
547     Echolot::Globals::get()->{'storage'}->commit();
548     Echolot::Globals::get()->{'storage'}->finish();
549 weasel 54 } else {
550     die ("Command $COMMAND unknown");
551     };
552    
553 weasel 34 exit 0;
554 weasel 1
555     # vim: set ts=4 shiftwidth=4:

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5