/[echolot]/trunk/pingd
ViewVC logotype

Contents of /trunk/pingd

Parent Directory Parent Directory | Revision Log Revision Log


Revision 115 - (hide annotations) (download)
Sat Jul 6 21:35:04 2002 UTC (10 years, 11 months ago) by weasel
File size: 14582 byte(s)
Find config file automagically
1 weasel 1 #!/usr/bin/perl -wT
2    
3     # (c) 2002 Peter Palfrader <peter@palfrader.org>
4 weasel 115 # $Id: pingd,v 1.19 2002/07/06 21:35:04 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 94 =item --nohup
144 weasel 88
145 weasel 103 Usefull only when passwd with the B<add>, B<set>, B<setremailercaps>,
146     B<deleteremailercaps> or B<getkeyconf> command.
147 weasel 88
148 weasel 94 Don't send a HUP signal to the daemon which instructs it to process the
149     commands after adding the command to the task list.
150 weasel 88
151 weasel 94 Per default such a signal is sent.
152    
153 weasel 88 =item --detach
154    
155     Usefull only when passwd with the B<start> command.
156    
157     Tell B<pingd> to detach.
158    
159 weasel 54 =back
160    
161     =head1 FILES
162    
163 weasel 115 The configuration file is searched in those places in that order:
164 weasel 54
165 weasel 115 =over
166    
167     =item the file pointed to by the B<ECHOLOT_CONF> environment variable
168    
169     =item `pwd`/pingd.conf
170    
171     =item $HOME/echolot/pingd.conf
172    
173     =item $HOME/pingd.conf
174    
175     =item $HOME/.pingd.conf
176    
177     =item /etc/pingd.conf
178    
179     =back
180    
181 weasel 88 =head1 SIGNALS
182    
183 weasel 103 On B<SIGINT>, B<SIGQUIT>, and B<SIGTERM> B<pingd> will schedule a shutdown
184     for as soon as the current actions are finished or immediatly if no actions are
185     currently beeing processed. It will then write all metadata and pingdata to
186 weasel 88 disk and close all files cleanly before exiting.
187    
188     On B<SIGHUP> <pingd> will execute any pending commands from the commands file
189     (B<commands.txt> per default). It also closes and reopens the file 'output'
190     which is used for stdout and stderr in case the daemon was told to detach.
191     This can be used if you want to rotate that file.
192    
193 weasel 54 =head1 AUTHOR
194    
195 weasel 103 Peter Palfrader E<lt>peter@palfrader.orgE<gt>
196 weasel 54
197     =head1 BUGS
198    
199 weasel 103 Please report them at E<lt>URL:http://savannah.gnu.org/bugs/?group=echolotE<gt>
200 weasel 54
201     =cut
202    
203 weasel 1 use strict;
204     use XML::Parser;
205     use XML::Dumper;
206     use Getopt::Long;
207 weasel 54 use English;
208 weasel 91 use Carp;
209 weasel 34 use lib qw{ . lib };
210 weasel 1 use Echolot::Config;
211     use Echolot::Globals;
212     use Echolot::Storage::File;
213 weasel 15 use Echolot::Scheduler;
214 weasel 1 use Echolot::Conf;
215     use Echolot::Mailin;
216 weasel 15 use Echolot::Pinger;
217 weasel 34 use Echolot::Stats;
218 weasel 54 use Echolot::Commands;
219 weasel 106 use Echolot::Thesaurus;
220 weasel 1
221     $ENV{'PATH'} = '/bin:/usr/bin';
222     delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
223    
224 weasel 54
225 weasel 88 my $redirected_stdio = 0;
226 weasel 54
227     sub setSigHandlers() {
228     $SIG{'HUP'} = sub {
229 weasel 115 print "Got SIGHUP. scheduling readcommands\n";
230 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() );
231 weasel 88 if ($redirected_stdio) {
232     close STDOUT;
233     close STDERR;
234     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
235     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
236     };
237 weasel 54 };
238     $SIG{'INT'} = sub {
239     print "Got SIGINT. scheduling exit\n";
240 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
241 weasel 54 };
242     $SIG{'QUIT'} = sub {
243     print "Got SIGQUIT. scheduling exit\n";
244 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
245 weasel 54 };
246     $SIG{'TERM'} = sub {
247     print "Got SIGTERM. scheduling exit\n";
248 weasel 94 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
249 weasel 54 };
250 weasel 34 };
251 weasel 54
252 weasel 88
253    
254 weasel 54 sub commit_prospective_address() {
255     Echolot::Globals::get()->{'storage'}->commit_prospective_address();
256 weasel 34 };
257 weasel 60 sub expire() {
258     Echolot::Globals::get()->{'storage'}->expire();
259     };
260 weasel 54
261    
262    
263    
264    
265 weasel 94 sub command_adddelete(@) {
266     my $command = shift @_;
267 weasel 88 my @argv = @_;
268 weasel 54
269 weasel 94 die ("command_adddelete requires command\n") unless defined $command;
270 weasel 88 die ("add requires argument <address>\n") unless scalar @argv;
271 weasel 75 my @addresses;
272 weasel 88 for my $address (@argv) {
273 weasel 75 die ("argument <address> is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
274     push @addresses, $address;
275     };
276     for my $address (@addresses) {
277 weasel 94 Echolot::Commands::addCommand("$command $address");
278 weasel 75 };
279 weasel 88 };
280    
281     sub command_set(@) {
282     my @argv = @_;
283    
284 weasel 75 my @settings;
285 weasel 88 while (scalar @argv && $argv[0] =~ /^(showit|pingit|fetch)=(on|off)$/) {
286     push @settings, $argv[0];
287     shift @argv;
288 weasel 75 };
289    
290     my @addresses;
291 weasel 88 for my $address (@argv) {
292 weasel 75 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
293     push @addresses, $address;
294     };
295    
296 weasel 88 for my $address (@argv) {
297 weasel 75 for my $setting (@settings) {
298     Echolot::Commands::addCommand("set $address $setting");
299     };
300     };
301 weasel 88 };
302    
303 weasel 103 sub command_setremailercaps(@) {
304     my @argv = @_;
305 weasel 94
306 weasel 103 my @caps;
307     for my $caps (@argv) {
308     my ($remailer_nick, $remailer_address) = ($caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix);
309     die ("caps '$caps' is not a valid remailer caps line\n") unless (defined $remailer_nick && defined $remailer_address);
310     push @caps, {
311     address => $remailer_address,
312     caps => $caps };
313     };
314     for my $caps (@caps) {
315     Echolot::Commands::addCommand("setremailercaps ".$caps->{'address'}." ".$caps->{'caps'});
316     };
317     };
318 weasel 94
319 weasel 103 sub command_deleteremailercaps(@) {
320     my @argv = @_;
321    
322     my @addresses;
323     for my $address (@argv) {
324     die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
325     push @addresses, $address;
326     };
327    
328     for my $address (@argv) {
329     Echolot::Commands::addCommand("deleteremailercaps $address");
330     };
331     };
332    
333    
334 weasel 88 sub pid_exists() {
335     return (-e Echolot::Config::get()->{'pidfile'});
336     };
337    
338     sub daemon_run() {
339     die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
340     if pid_exists();
341     open (PIDFILE, '>'.Echolot::Config::get()->{'pidfile'}) or
342 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
343 weasel 88 print PIDFILE "$PROCESS_ID ".Echolot::Globals::get()->{'hostname'}." ".time()."\n";
344     close PIDFILE;
345    
346 weasel 60 Echolot::Globals::initStorage();
347 weasel 54 setSigHandlers();
348 weasel 1
349 weasel 94 Echolot::Globals::get()->{'scheduler'} = new Echolot::Scheduler;
350     my $scheduler = Echolot::Globals::get()->{'scheduler'};
351 weasel 83 $scheduler->add('exit' , -1 , 0, 'exit' );
352     $scheduler->add('readcommands' , -1 , 0, \&Echolot::Commands::processCommands );
353 weasel 1
354 weasel 83 $scheduler->add('processmail' , Echolot::Config::get()->{'processmail'} , 0, \&Echolot::Mailin::process );
355     $scheduler->add('ping' , Echolot::Config::get()->{'pinger_interval'} , 0, \&Echolot::Pinger::send_pings );
356 weasel 107 $scheduler->add('buildstats' , Echolot::Config::get()->{'buildstats'} , 0, \&Echolot::Stats::build_stats );
357     $scheduler->add('buildkeys' , Echolot::Config::get()->{'buildkeys'} , 0, \&Echolot::Stats::build_keys );
358 weasel 106 $scheduler->add('buildthesaurus' , Echolot::Config::get()->{'build_thesaurus'} , 0, \&Echolot::Thesaurus::build_thesaurus );
359 weasel 54
360 weasel 83 $scheduler->add('commitprospectives' , Echolot::Config::get()->{'commitprospectives'} , 0, \&commit_prospective_address );
361     $scheduler->add('expire' , Echolot::Config::get()->{'expire'} , 0, \&expire );
362     $scheduler->add('getkeyconf' , Echolot::Config::get()->{'getkeyconf'} , 0, \&Echolot::Conf::send_requests );
363 weasel 54
364     $scheduler->run();
365    
366     Echolot::Globals::get()->{'storage'}->commit();
367     Echolot::Globals::get()->{'storage'}->finish();
368 weasel 88
369     unlink (Echolot::Config::get()->{'pidfile'}) or
370     cluck ("Cannot unlink pidfile ".Echolot::Config::get()->{'pidfile'});
371     };
372    
373     sub send_sig($) {
374     my ($sig) = @_;
375    
376 weasel 107 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' does not exist\n")
377 weasel 88 unless pid_exists();
378     open (PIDFILE, '<'.Echolot::Config::get()->{'pidfile'}) or
379 weasel 91 croak ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
380 weasel 88 my $line = <PIDFILE>;
381     close PIDFILE;
382    
383     my ($pid, $host, $time) = $line =~ /^(\d+) \s+ (\S+) \s+ (\d+) \s* $/x or
384 weasel 91 croak ("Cannot parse pidfile '$line'\n");
385 weasel 88 my $sent = kill $sig, $pid;
386     ($sent == 1) or
387 weasel 91 croak ("Did not send signal $sig to exactly one process but $sent. (pidfile reads $line)\n");
388 weasel 88 };
389    
390     sub daemon_hup() {
391     send_sig(1);
392     };
393    
394     sub daemon_stop() {
395     send_sig(15);
396     };
397    
398 weasel 91 sub make_dirs() {
399     for my $dir (
400     Echolot::Config::get()->{'resultdir'},
401 weasel 106 Echolot::Config::get()->{'thesaurusdir'},
402 weasel 91 Echolot::Config::get()->{'private_resultdir'},
403     Echolot::Config::get()->{'gnupghome'},
404     Echolot::Config::get()->{'tmpdir'},
405     Echolot::Config::get()->{'storage'}->{'File'}->{'basedir'}
406     ) {
407     if ( ! -d $dir ) {
408     mkdir ($dir) or
409     croak ("Cannot create directory $dir: $!\n");
410     };
411     };
412     for my $dir (
413     Echolot::Config::get()->{'mailindir'},
414     Echolot::Config::get()->{'mailindir'}.'/cur',
415     Echolot::Config::get()->{'mailindir'}.'/tmp',
416     Echolot::Config::get()->{'mailindir'}.'/new',
417     Echolot::Config::get()->{'mailerrordir'},
418     Echolot::Config::get()->{'mailerrordir'}.'/cur',
419     Echolot::Config::get()->{'mailerrordir'}.'/tmp',
420     Echolot::Config::get()->{'mailerrordir'}.'/new'
421     ) {
422     if ( ! -d $dir ) {
423     mkdir ($dir, 0700) or
424     croak ("Cannot create directory $dir: $!\n");
425     };
426     };
427     };
428 weasel 88
429 weasel 91
430    
431    
432    
433    
434    
435    
436    
437    
438    
439    
440 weasel 88 my $params;
441     Getopt::Long::config('bundling');
442     if (!GetOptions (
443     'help' => \$params->{'help'},
444     'verbose' => \$params->{'verbose'},
445 weasel 94 'nohup' => \$params->{'nohup'},
446 weasel 88 'detach' => \$params->{'detach'},
447     )) {
448     die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
449     };
450     if ($params->{'help'}) {
451 weasel 115 print ("Usage: $PROGRAM_NAME [options] command\n");
452     print ("See man pingd or perldoc pingd for more info.\n");
453 weasel 88 exit 0;
454     };
455    
456     my $COMMAND = shift @ARGV;
457     die ("command required\n") unless defined $COMMAND;
458    
459    
460     Echolot::Config::init( $params );
461     chdir( Echolot::Config::get()->{'homedir'} );
462     Echolot::Globals::init();
463    
464    
465 weasel 94 if ($COMMAND eq 'add' || $COMMAND eq 'delete') {
466     command_adddelete($COMMAND, @ARGV);
467     if (!$params->{'nohup'} && pid_exists()) {
468 weasel 88 daemon_hup()
469     } else {
470     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
471     };
472     } elsif ($COMMAND eq 'set') {
473     command_set(@ARGV);
474 weasel 94 if (!$params->{'nohup'} && pid_exists()) {
475 weasel 88 daemon_hup()
476     } else {
477     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
478     };
479 weasel 103 } elsif ($COMMAND eq 'setremailercaps') {
480     command_setremailercaps(@ARGV);
481     if (!$params->{'nohup'} && pid_exists()) {
482     daemon_hup()
483     } else {
484     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
485     };
486     } elsif ($COMMAND eq 'deleteremailercaps') {
487     command_deleteremailercaps(@ARGV);
488     if (!$params->{'nohup'} && pid_exists()) {
489     daemon_hup()
490     } else {
491     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
492     };
493 weasel 94 } elsif ($COMMAND eq 'getkeyconf') {
494     Echolot::Commands::addCommand("getkeyconf");
495     if (!$params->{'nohup'} && pid_exists()) {
496     daemon_hup()
497     } else {
498     print "Don't forget to run $PROGRAM_NAME process. You may also use --hup in the future\n";
499     };
500 weasel 88 } elsif ($COMMAND eq 'process') {
501     daemon_hup();
502     } elsif ($COMMAND eq 'stop') {
503     daemon_stop();
504     } elsif ($COMMAND eq 'start') {
505 weasel 103 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
506     if pid_exists();
507 weasel 91 make_dirs();
508 weasel 88 if ($params->{'detach'}) {
509     print "Detaching.\n";
510     unless (fork()) {
511     close STDOUT;
512     close STDERR;
513     open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
514     open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
515     close STDIN;
516     $redirected_stdio = 1;
517 weasel 105 print "Startup at ".scalar localtime().".\n";
518 weasel 88 daemon_run();
519 weasel 105 print "done at ".scalar localtime().".\n";
520 weasel 88 };
521     } else {
522     daemon_run();
523     };
524 weasel 81 } elsif ($COMMAND eq 'dumpconf') {
525     Echolot::Config::dump();
526 weasel 75 } elsif ($COMMAND eq 'convert') {
527     Echolot::Globals::initStorage();
528     setSigHandlers();
529    
530     Echolot::Globals::get()->{'storage'}->convert();
531    
532     Echolot::Globals::get()->{'storage'}->commit();
533     Echolot::Globals::get()->{'storage'}->finish();
534 weasel 54 } else {
535     die ("Command $COMMAND unknown");
536     };
537    
538 weasel 34 exit 0;
539 weasel 1
540     # vim: set ts=4 shiftwidth=4:

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5