/[echolot]/trunk/pingd
ViewVC logotype

Contents of /trunk/pingd

Parent Directory Parent Directory | Revision Log Revision Log


Revision 121 - (hide annotations) (download)
Sun Jul 7 01:12:00 2002 UTC (10 years, 10 months ago) by weasel
File size: 15185 byte(s)
Check for resurrection
1 weasel 1 #!/usr/bin/perl -wT
2    
3     # (c) 2002 Peter Palfrader <peter@palfrader.org>
4 weasel 121 # $Id: pingd,v 1.21 2002/07/07 01:11:59 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 XML::Parser;
209     use XML::Dumper;
210     use Getopt::Long;
211 weasel 54 use English;
212 weasel 91 use Carp;
213 weasel 34 use lib qw{ . lib };
214 weasel 1 use Echolot::Config;
215     use Echolot::Globals;
216     use Echolot::Storage::File;
217 weasel 15 use Echolot::Scheduler;
218 weasel 1 use Echolot::Conf;
219     use Echolot::Mailin;
220 weasel 15 use Echolot::Pinger;
221 weasel 34 use Echolot::Stats;
222 weasel 54 use Echolot::Commands;
223 weasel 106 use Echolot::Thesaurus;
224 weasel 1
225     $ENV{'PATH'} = '/bin:/usr/bin';
226     delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
227    
228 weasel 54
229 weasel 117 my $VERSION = '2.0beta1';
230    
231    
232 weasel 88 my $redirected_stdio = 0;
233 weasel 54
234     sub setSigHandlers() {
235     $SIG{'HUP'} = sub {
236 weasel 115 print "Got SIGHUP. scheduling readcommands\n";
237 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() );
238 weasel 88 if ($redirected_stdio) {
239     close STDOUT;
240     close STDERR;
241     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
242     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
243     };
244 weasel 54 };
245     $SIG{'INT'} = sub {
246     print "Got SIGINT. scheduling exit\n";
247 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
248 weasel 54 };
249     $SIG{'QUIT'} = sub {
250     print "Got SIGQUIT. scheduling exit\n";
251 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
252 weasel 54 };
253     $SIG{'TERM'} = sub {
254     print "Got SIGTERM. scheduling exit\n";
255 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
256 weasel 54 };
257 weasel 34 };
258 weasel 54
259 weasel 88
260    
261 weasel 54 sub commit_prospective_address() {
262     Echolot::Globals::get()->{'storage'}->commit_prospective_address();
263 weasel 34 };
264 weasel 60 sub expire() {
265     Echolot::Globals::get()->{'storage'}->expire();
266     };
267 weasel 54
268    
269    
270    
271    
272 weasel 94 sub command_adddelete(@) {
273     my $command = shift @_;
274 weasel 88 my @argv = @_;
275 weasel 54
276 weasel 94 die ("command_adddelete requires command\n") unless defined $command;
277 weasel 88 die ("add requires argument <address>\n") unless scalar @argv;
278 weasel 75 my @addresses;
279 weasel 88 for my $address (@argv) {
280 weasel 75 die ("argument <address> is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
281     push @addresses, $address;
282     };
283     for my $address (@addresses) {
284 weasel 94 Echolot::Commands::addCommand("$command $address");
285 weasel 75 };
286 weasel 88 };
287    
288     sub command_set(@) {
289     my @argv = @_;
290    
291 weasel 75 my @settings;
292 weasel 88 while (scalar @argv && $argv[0] =~ /^(showit|pingit|fetch)=(on|off)$/) {
293     push @settings, $argv[0];
294     shift @argv;
295 weasel 75 };
296    
297     my @addresses;
298 weasel 88 for my $address (@argv) {
299 weasel 75 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
300     push @addresses, $address;
301     };
302    
303 weasel 88 for my $address (@argv) {
304 weasel 75 for my $setting (@settings) {
305     Echolot::Commands::addCommand("set $address $setting");
306     };
307     };
308 weasel 88 };
309    
310 weasel 103 sub command_setremailercaps(@) {
311     my @argv = @_;
312 weasel 94
313 weasel 103 my @caps;
314     for my $caps (@argv) {
315     my ($remailer_nick, $remailer_address) = ($caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix);
316     die ("caps '$caps' is not a valid remailer caps line\n") unless (defined $remailer_nick && defined $remailer_address);
317     push @caps, {
318     address => $remailer_address,
319     caps => $caps };
320     };
321     for my $caps (@caps) {
322     Echolot::Commands::addCommand("setremailercaps ".$caps->{'address'}." ".$caps->{'caps'});
323     };
324     };
325 weasel 94
326 weasel 103 sub command_deleteremailercaps(@) {
327     my @argv = @_;
328    
329     my @addresses;
330     for my $address (@argv) {
331     die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
332     push @addresses, $address;
333     };
334    
335     for my $address (@argv) {
336     Echolot::Commands::addCommand("deleteremailercaps $address");
337     };
338     };
339    
340    
341 weasel 88 sub pid_exists() {
342     return (-e Echolot::Config::get()->{'pidfile'});
343     };
344    
345     sub daemon_run() {
346     die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
347     if pid_exists();
348     open (PIDFILE, '>'.Echolot::Config::get()->{'pidfile'}) or
349 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
350 weasel 88 print PIDFILE "$PROCESS_ID ".Echolot::Globals::get()->{'hostname'}." ".time()."\n";
351     close PIDFILE;
352    
353 weasel 60 Echolot::Globals::initStorage();
354 weasel 54 setSigHandlers();
355 weasel 1
356 weasel 94 Echolot::Globals::get()->{'scheduler'} = new Echolot::Scheduler;
357     my $scheduler = Echolot::Globals::get()->{'scheduler'};
358 weasel 83 $scheduler->add('exit' , -1 , 0, 'exit' );
359     $scheduler->add('readcommands' , -1 , 0, \&Echolot::Commands::processCommands );
360 weasel 1
361 weasel 83 $scheduler->add('processmail' , Echolot::Config::get()->{'processmail'} , 0, \&Echolot::Mailin::process );
362     $scheduler->add('ping' , Echolot::Config::get()->{'pinger_interval'} , 0, \&Echolot::Pinger::send_pings );
363 weasel 107 $scheduler->add('buildstats' , Echolot::Config::get()->{'buildstats'} , 0, \&Echolot::Stats::build_stats );
364     $scheduler->add('buildkeys' , Echolot::Config::get()->{'buildkeys'} , 0, \&Echolot::Stats::build_keys );
365 weasel 106 $scheduler->add('buildthesaurus' , Echolot::Config::get()->{'build_thesaurus'} , 0, \&Echolot::Thesaurus::build_thesaurus );
366 weasel 54
367 weasel 83 $scheduler->add('commitprospectives' , Echolot::Config::get()->{'commitprospectives'} , 0, \&commit_prospective_address );
368     $scheduler->add('expire' , Echolot::Config::get()->{'expire'} , 0, \&expire );
369     $scheduler->add('getkeyconf' , Echolot::Config::get()->{'getkeyconf'} , 0, \&Echolot::Conf::send_requests );
370 weasel 121 $scheduler->add('check_resurrection' , Echolot::Config::get()->{'check_resurrection'} , 0, \&Echolot::Conf::check_resurrection );
371 weasel 54
372     $scheduler->run();
373    
374     Echolot::Globals::get()->{'storage'}->commit();
375     Echolot::Globals::get()->{'storage'}->finish();
376 weasel 88
377     unlink (Echolot::Config::get()->{'pidfile'}) or
378     cluck ("Cannot unlink pidfile ".Echolot::Config::get()->{'pidfile'});
379     };
380    
381     sub send_sig($) {
382     my ($sig) = @_;
383    
384 weasel 107 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' does not exist\n")
385 weasel 88 unless pid_exists();
386     open (PIDFILE, '<'.Echolot::Config::get()->{'pidfile'}) or
387 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
388 weasel 88 my $line = <PIDFILE>;
389     close PIDFILE;
390    
391     my ($pid, $host, $time) = $line =~ /^(\d+) \s+ (\S+) \s+ (\d+) \s* $/x or
392 weasel 91 croak ("Cannot parse pidfile '$line'\n");
393 weasel 88 my $sent = kill $sig, $pid;
394     ($sent == 1) or
395 weasel 91 croak ("Did not send signal $sig to exactly one process but $sent. (pidfile reads $line)\n");
396 weasel 88 };
397    
398     sub daemon_hup() {
399     send_sig(1);
400     };
401    
402     sub daemon_stop() {
403     send_sig(15);
404     };
405    
406 weasel 91 sub make_dirs() {
407     for my $dir (
408     Echolot::Config::get()->{'resultdir'},
409 weasel 106 Echolot::Config::get()->{'thesaurusdir'},
410 weasel 91 Echolot::Config::get()->{'private_resultdir'},
411     Echolot::Config::get()->{'gnupghome'},
412     Echolot::Config::get()->{'tmpdir'},
413     Echolot::Config::get()->{'storage'}->{'File'}->{'basedir'}
414     ) {
415     if ( ! -d $dir ) {
416     mkdir ($dir) or
417     croak ("Cannot create directory $dir: $!\n");
418     };
419     };
420     for my $dir (
421     Echolot::Config::get()->{'mailindir'},
422     Echolot::Config::get()->{'mailindir'}.'/cur',
423     Echolot::Config::get()->{'mailindir'}.'/tmp',
424     Echolot::Config::get()->{'mailindir'}.'/new',
425     Echolot::Config::get()->{'mailerrordir'},
426     Echolot::Config::get()->{'mailerrordir'}.'/cur',
427     Echolot::Config::get()->{'mailerrordir'}.'/tmp',
428     Echolot::Config::get()->{'mailerrordir'}.'/new'
429     ) {
430     if ( ! -d $dir ) {
431     mkdir ($dir, 0700) or
432     croak ("Cannot create directory $dir: $!\n");
433     };
434     };
435     };
436 weasel 88
437 weasel 91
438    
439    
440    
441    
442    
443    
444    
445    
446    
447    
448 weasel 88 my $params;
449     Getopt::Long::config('bundling');
450     if (!GetOptions (
451     'help' => \$params->{'help'},
452 weasel 117 'version' => \$params->{'version'},
453 weasel 88 'verbose' => \$params->{'verbose'},
454 weasel 94 'nohup' => \$params->{'nohup'},
455 weasel 88 'detach' => \$params->{'detach'},
456     )) {
457     die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
458     };
459     if ($params->{'help'}) {
460 weasel 115 print ("Usage: $PROGRAM_NAME [options] command\n");
461     print ("See man pingd or perldoc pingd for more info.\n");
462 weasel 117 print ("echolot $VERSION - (c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
463     print ("http://savannah.gnu.org/projects/echolot/\n");
464 weasel 88 exit 0;
465     };
466 weasel 117 if ($params->{'version'}) {
467     print ("echolot $VERSION\n");
468     print ("(c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
469     print ("http://savannah.gnu.org/projects/echolot/\n");
470     exit 0;
471     };
472 weasel 88
473     my $COMMAND = shift @ARGV;
474     die ("command required\n") unless defined $COMMAND;
475    
476    
477     Echolot::Config::init( $params );
478     chdir( Echolot::Config::get()->{'homedir'} );
479     Echolot::Globals::init();
480    
481    
482 weasel 94 if ($COMMAND eq 'add' || $COMMAND eq 'delete') {
483     command_adddelete($COMMAND, @ARGV);
484     if (!$params->{'nohup'} && pid_exists()) {
485 weasel 88 daemon_hup()
486     } else {
487     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
488     };
489     } elsif ($COMMAND eq 'set') {
490     command_set(@ARGV);
491 weasel 94 if (!$params->{'nohup'} && pid_exists()) {
492 weasel 88 daemon_hup()
493     } else {
494     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
495     };
496 weasel 103 } elsif ($COMMAND eq 'setremailercaps') {
497     command_setremailercaps(@ARGV);
498     if (!$params->{'nohup'} && pid_exists()) {
499     daemon_hup()
500     } else {
501     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
502     };
503     } elsif ($COMMAND eq 'deleteremailercaps') {
504     command_deleteremailercaps(@ARGV);
505     if (!$params->{'nohup'} && pid_exists()) {
506     daemon_hup()
507     } else {
508     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
509     };
510 weasel 94 } elsif ($COMMAND eq 'getkeyconf') {
511     Echolot::Commands::addCommand("getkeyconf");
512     if (!$params->{'nohup'} && pid_exists()) {
513     daemon_hup()
514     } else {
515     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
516     };
517 weasel 88 } elsif ($COMMAND eq 'process') {
518     daemon_hup();
519     } elsif ($COMMAND eq 'stop') {
520     daemon_stop();
521     } elsif ($COMMAND eq 'start') {
522 weasel 103 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
523     if pid_exists();
524 weasel 91 make_dirs();
525 weasel 88 if ($params->{'detach'}) {
526     print "Detaching.\n";
527     unless (fork()) {
528     close STDOUT;
529     close STDERR;
530     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
531     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
532     close STDIN;
533     $redirected_stdio = 1;
534 weasel 105 print "Startup at ".scalar localtime().".\n";
535 weasel 88 daemon_run();
536 weasel 105 print "done at ".scalar localtime().".\n";
537 weasel 88 };
538     } else {
539     daemon_run();
540     };
541 weasel 81 } elsif ($COMMAND eq 'dumpconf') {
542     Echolot::Config::dump();
543 weasel 75 } elsif ($COMMAND eq 'convert') {
544     Echolot::Globals::initStorage();
545     setSigHandlers();
546    
547     Echolot::Globals::get()->{'storage'}->convert();
548    
549     Echolot::Globals::get()->{'storage'}->commit();
550     Echolot::Globals::get()->{'storage'}->finish();
551 weasel 54 } else {
552     die ("Command $COMMAND unknown");
553     };
554    
555 weasel 34 exit 0;
556 weasel 1
557     # vim: set ts=4 shiftwidth=4:

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5