/[echolot]/trunk/pingd
ViewVC logotype

Contents of /trunk/pingd

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5