diff options
Diffstat (limited to 'fs_selfservice/freeside-selfservice-server')
-rw-r--r-- | fs_selfservice/freeside-selfservice-server | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/fs_selfservice/freeside-selfservice-server b/fs_selfservice/freeside-selfservice-server new file mode 100644 index 000000000..6146d3752 --- /dev/null +++ b/fs_selfservice/freeside-selfservice-server @@ -0,0 +1,198 @@ +#!/usr/bin/perl -w +# +# freeside-selfservice-server + +# alas, much false laziness with freeside-queued and fs_signup_server. at +# least it is slated to replace fs_{signup,passwd,mailadmin}_server +# should probably generalize the version in here, or better yet use +# Proc::Daemon or somesuch + +use strict; +use vars qw( $kids $max_kids $shutdown $log_file ); +use vars qw($ssh_pid); +use Fcntl qw(:flock); +use POSIX qw(setsid); +use IO::Handle; +use Storable qw(nstore_fd fd_retrieve); +use Net::SSH qw(sshopen2); +use FS::UID qw(adminsuidsetup); + +#use Tie::RefHash; +#use FS::Conf; +#use FS::Record qw( qsearch qsearchs ); +#use FS::cust_main_county; +#use FS::cust_main; +#use FS::Msgcat qw(gettext); + +$shutdown = 0; +$max_kids = '10'; #? +$kids = 0; + +my $user = shift or die &usage; +my $machine = shift or die &usage; +my $pid_file = "/var/run/freeside-selfservice-server.$user.pid"; +#my $pid_file = "/var/run/freeside-selfservice-server.$user.pid"; $FS::UID::datasrc not posible, but should include machine name at least, hmm + +&init($user); + +my $clientd = "/usr/local/sbin/freeside-selfservice-clientd"; #better name? + +my %dispatch = ( + 'signup' => \&signup, + #'signup_init' => 'signup_init', + 'passwd' => \&passwd, + +); + +my $warnkids=0; +while (1) { + my($reader, $writer) = (new IO::Handle, new IO::Handle); + warn "connecting to $machine"; + $ssh_pid = sshopen2($machine,$reader,$writer,$clientd); + + warn "entering main loop"; + while (1) { + + warn "waiting for packet from client"; + my $packet = eval { + local $SIG{__DIE__}; + local $SIG{ALRM} = sub { die "alarm\n" }; #NB: \n required + alarm 5; + my $p = fd_retrieve($reader); + alarm 0; + $p; + }; + if ($@) { + die $@ unless $@ eq "alarm\n"; + #timeout + next unless $shutdown; + &shutdown; + } + warn "packet received"; + + #prevent runaway forking + my $warnkids = 0; + while ( $kids >= $max_kids ) { + warn "WARNING: maximum $kids children reached" unless $warnkids++; + sleep 1; + } + + warn "forking child"; + defined( my $pid = fork ) or die "can't fork: $!"; + if ( $pid ) { + warn "child $pid spawned"; + $kids++; + } else { #kid time + + #get new db handle + $FS::UID::dbh->{InactiveDestroy} = 1; + forksuidsetup($user); + + my $sub = $dispatch{$packet->{_packet}}; + my $rv; + if ( $sub ) { + warn "calling $sub handler"; + $rv = &{$sub}($packet); + } else { + warn my $error = "WARNING: unknown packet type ". $packet->{_packet}; + $rv = { _error => $error }; + } + $rv->{_token} = $packet->{_token}; #identifier + + warn "sending response"; + flock($writer, LOCK_EX); #acquire write lock + nstore_fd($rv, $writer) or die "can't send response: $!"; + $writer->flush; + flock($writer, LOCK_UN); #release write lock + + warn "child exiting"; + exit; #end-of-kid + } + + } + +} + +### +# utility subroutines +### + +sub init { + my $user = shift; + + chdir "/" or die "Can't chdir to /: $!"; + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + defined(my $pid = fork) or die "Can't fork: $!"; + if ( $pid ) { + print "freeside-selfservice-server to $machine started with pid $pid\n"; #logging to $log_file + exit unless $pid_file; + my $pidfh = new IO::File ">$pid_file" or exit; + print $pidfh "$pid\n"; + exit; + } + + sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } + $SIG{CHLD} = \&REAPER; + + $shutdown = 0; + $SIG{HUP} = sub { warn "SIGHUP received; shutting down\n"; $shutdown++; }; + $SIG{INT} = sub { warn "SIGINT received; shutting down\n"; $shutdown++; }; + $SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $shutdown++; }; + $SIG{QUIT} = sub { warn "SIGQUIT received; shutting down\n"; $shutdown++; }; + $SIG{PIPE} = sub { warn "SIGPIPE received; shutting down\n"; $shutdown++; }; + + $> = $FS::UID::freeside_uid unless $>; + $< = $>; + $ENV{HOME} = (getpwuid($>))[7]; #for ssh + adminsuidsetup $user; + + #$log_file = "/usr/local/etc/freeside/selfservice.". $FS::UID::datasrc; #MACHINE NAME + $log_file = "/usr/local/etc/freeside/selfservice.$machine.log"; + + open STDOUT, '>/dev/null' + or die "Can't write to /dev/null: $!"; + setsid or die "Can't start a new session: $!"; + open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; + + $SIG{__DIE__} = \&_die; + $SIG{__WARN__} = \&_logmsg; + + warn "freeside-selfservice-server starting\n"; + +} + +sub shutdown { + my $wait = 12; #wait up to 1 minute + while ( $kids && $wait-- ) { + warn "waiting for $kids children to terminate"; + sleep 5; + } + warn "abandoning $kids children" if $kids; + kill 'TERM', $ssh_pid if $ssh_pid; + die "exiting"; +} + +sub _die { + my $msg = shift; + unlink $pid_file if -e $pid_file; + _logmsg($msg); +} + +sub _logmsg { + chomp( my $msg = shift ); + my $log = new IO::File ">>$log_file"; + flock($log, LOCK_EX); + seek($log, 0, 2); + print $log "[server] [". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n"; + flock($log, LOCK_UN); + close $log; +} + +sub usage { + die "Usage:\n\n fs_signup_server user machine\n"; +} + +### +# handlers... should go in their own files eventually... +### + |