From: Stephen L Johnson Date: Mon, 3 Apr 2000 16:47:41 +0000 (+0000) Subject: make update, bb_update and query processes forking to scale better. X-Git-Tag: spong-2_7-alpha5~25 X-Git-Url: http://git.etc.gen.nz/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=525ee70b319a004c3fdea73387a5aef777888bbf;p=spong.git make update, bb_update and query processes forking to scale better. --- diff --git a/src/spong-server.pl b/src/spong-server.pl index ee34cd5..aa51bba 100755 --- a/src/spong-server.pl +++ b/src/spong-server.pl @@ -33,7 +33,10 @@ use IO::Socket; use Config; use Time::Local; use Getopt::Long; -use POSIX; +use POSIX qw(:sys_wait_h); + +my $numchild; +$MAX_CHILDREN = 10; $debug = $restart = $kill = 0; @@ -157,13 +160,14 @@ sub usage { sub listen_for_clients { my ( $sock, $client ); - # Set up the socket to listen to + $SIG{'CHLD'} = 'IGNORE'; $SIG{'PIPE'} = 'IGNORE'; $SIG{'TERM'} = $SIG{'HUP'} = $SIG{'QUIT'} = sub { &debug('spong client caught QUIT signal, exiting',3); undef $sock; exit; }; + # Set up the socket to listen to $sock = IO::Socket::INET->new( Listen => SOMAXCONN, LocalPort => $main::SPONG_CLIENT_PORT, Proto => 'tcp', @@ -204,11 +208,12 @@ sub listen_for_clients { sub listen_for_updates { + $SIG{'CHLD'} = 'IGNORE'; $SIG{'PIPE'} = 'IGNORE'; $SIG{'QUIT'} = sub {&debug('spong updates caught QUIT signal, exiting'); - close SERVER; exit;}; + close $sock; exit;}; $SIG{'HUP'} = sub {&debug('spong updates caught HUP signal, exiting'); - close SERVER; exit;}; + close $sock; exit;}; # Set up the socket to listen to @@ -224,49 +229,66 @@ sub listen_for_updates { &debug( "update server socket setup, listening for connections" ); while( 1 ) { + + $0 = "spong-server (spong-update) accepting connections on $SPONG_UPDATE_PORT"; + + # Try to accept the next connection next unless ( $client = $sock->accept() ); + my $paddr = $client->peerhost(); &debug("Connection from $paddr",6); + $0 = "spong-server (spong-update) connection from $paddr"; # &validate_connection( $paddr ); - need to do something here... - # Read all from the client, and disconnect, we process the message next. - - my( $header, $ok ) = ( "", 0 ); - my( $message, $cnt, $line ) = ( "", "", "" ); - - # Set an alarm on this block in case the client runs into problems - eval - { - local $SIG{'ALRM'} = sub { die; }; - alarm($SPONG_SERVER_ALARM) if $SPONG_SERVER_ALARM; - - $header = <$client>; chomp $header; - &debug("msg header = $header",6); - while( defined( $line = <$client> ) ) { - last if ($cnt += length($line)) > 100000; - $message .= $line; - } - - alarm(0); - $ok = 1; - }; - undef $client; - - if ( ! $ok ) { - &error( "ss_update: Connection from $paddr timed out" ); - next; - } - - # Now depending on what kind of message it is, pass it off to a routine - # that can process the message. Currently valid messages are "status", - # "ack", "config", and "stat". - - if( $header =~ /^status\b/ ) { &save_status( $header, $message ); next; } - if( $header =~ /^ack-del\b/ ) { &del_ack( $header, $message ); next; } - if( $header =~ /^ack\b/ ) { &save_ack( $header, $message ); next; } - # if( $header =~ /^config\b/ ) { &save_config( $header, $message ); } - # if( $header =~ /^stat\b/ ) { &save_stat( $header, $message ); } + # Now fork and allow the kid to process the message + my $pid = fork(); + if ( ! defined $pid) { &error("listen_for_updates: Could not fork: $!"); } + elsif ( $pid ) { } # I'm the parent + else { # I'm the kid + + # Read all from the client, and disconnect + + my( $header, $ok ) = ( "", 0 ); + my( $message, $cnt, $line ) = ( "", "", "" ); + + # Set an alarm on this block in case the client runs into problems + eval + { + local $SIG{'ALRM'} = sub { die; }; + alarm($SPONG_SERVER_ALARM) if $SPONG_SERVER_ALARM; + + $header = <$client>; chomp $header; + &debug("msg header = $header",6); + while( defined( $line = <$client> ) ) { + last if ($cnt += length($line)) > 100000; + $message .= $line; + } + + alarm(0); + $ok = 1; + }; + undef $client; + + if ( ! $ok ) { + &error( "ss_update: Connection from $paddr timed out" ); + exit; + } + + # Now depending on what kind of message it is, pass it off to a routine + # that can process the message. Currently valid messages are "status", + # "ack", "config", and "stat". + + if( $header =~ /^status\b/ ) { &save_status( $header, $message ); } + if( $header =~ /^ack-del\b/ ) { &del_ack( $header, $message ); } + if( $header =~ /^ack\b/ ) { &save_ack( $header, $message ); } + # if( $header =~ /^config\b/ ) { &save_config( $header, $message ); } + # if( $header =~ /^stat\b/ ) { &save_stat( $header, $message ); } + + exit; + } # End child processing + } continue { +# undef $client; } } @@ -279,6 +301,7 @@ sub listen_for_updates { sub listen_for_bb_updates { + $SIG{'CHLD'} = 'IGNORE'; $SIG{'PIPE'} = 'IGNORE'; $SIG{'TERM'} = $SIG{'HUP'} = $SIG{'QUIT'} = sub { &debug('spong updates caught signal, exiting',3); @@ -298,44 +321,59 @@ sub listen_for_bb_updates { &debug( "bb update server socket setup, listening for connections" ); while( 1 ) { + + $0 = "spong-server (spong-bb-update) accepting connections on $SPONG_BB_UPDATE_PORT"; + + # Try to accept the next connection next unless ( $client = $sock->accept() ); + my $paddr = $client->peerhost(); + &debug("Connection from $paddr",6); + $0 = "spong-server (spong-bb-update) connection from $paddr"; # &validate_connection( $paddr ); - need to do something here... - # Read all from the client, and disconnect, we process the message next. - my( $header, $ok ) = ( "", 0 ); - my( $message, $cnt, $line ) = ( "", "", "" ); + # Now fork and allow the kid to process the message + my $pid = fork(); + if ( ! defined $pid) { &error("listen_for_bb_updates: Coulnd not fork: $!"); } + elsif ( $pid ) { } # I'm the parent + else { # I'm the child - eval { - local $SIG{'ALRM'} = sub { die; }; - alarm($SPONG_SERVER_ALARM) if $SPONG_SERVER_ALARM; + # Read all from the client, and disconnect, + my( $header, $ok ) = ( "", 0 ); + my( $message, $cnt, $line ) = ( "", "", "" ); - $header = <$client>; chomp $header; - while( defined( $line = <$client> ) ) { - last if ($cnt += length($line)) > 100000; - $message .= $line; - } + eval { + local $SIG{'ALRM'} = sub { die; }; + alarm($SPONG_SERVER_ALARM) if $SPONG_SERVER_ALARM; - $ok = 1; - }; - alarm(0); - undef $client; + $header = <$client>; chomp $header; + while( defined( $line = <$client> ) ) { + last if ($cnt += length($line)) > 100000; + $message .= $line; + } - if ( ! $ok ) { - &error( "ss_update: Connection from $paddr timed out" ); - next; - } + $ok = 1; + alarm(0); + }; + undef $client; - &debug($message,8); + if ( ! $ok ) { + &error( "ss_update: Connection from $paddr timed out" ); + exit; + } - # Now depending on what kind of message it is, pass it off to a routine - # that can process the message. + &debug($message,8); - if( $header =~ /^status\b/ ) { - &save_bb_status( $header, $message ); - next; + # Now depending on what kind of message it is, pass it off to a routine + # that can process the message. + + if( $header =~ /^status\b/ ) { + &save_bb_status( $header, $message ); + } + + exit; } } } @@ -348,6 +386,7 @@ sub listen_for_bb_updates { sub listen_for_queries { + $SIG{'CHLD'} = 'IGNORE'; $SIG{'PIPE'} = 'IGNORE'; $SIG{'TERM'} = $SIG{'HUP'} = $SIG{'QUIT'} = sub { &debug('spong updates caught QUIT signal, exiting',3); @@ -376,45 +415,60 @@ sub listen_for_queries { $main::SERVICES{$service}=1;}} $next_update =+ 15 * 60; } + + next unless ( $client = $sock->accept() ); + my $paddr = $client->peerhost(); + &debug("[$$] update: Connection from $paddr",6); + $0 = "spong-server (query) connection from $paddr"; # &validate_connection( $paddr ); - need to do something here... - # Read the entire query from the client, don't disconnect like we do with - # updates however, as we need to send back some information. Query - # requests are simple one line messages. - my $header = <$client>; chomp $header; $header =~ s/\r//; - my( $query, $hosts, $type, $view, $other ) = - ( $header =~ /^(\w+)\s+\[([^\]]*)\]\s+(\w+)\s+(\w+)\b\s*(.*)$/ ); + # Now fork and allow the kid to process the message + my $pid = fork(); + if ( ! defined $pid) { &error("list_for_queries: Could not fork: $!"); } + elsif ($pid) { } # I'm the parent, do nothing + else { # I'm the kid - # Now depending on what kind of request it is, pass it off to a routine - # that can process the message. + # Read the entire query from the client, don't disconnect like we do + # with updates however, as we need to send back some information. + # Query requests are simple one line messages. - my( @args ) = ( $hosts, $type, $view ); # Just shortens up the code... - my $output = select $client; + my $header = <$client>; chomp $header; $header =~ s/\r//; + my( $query, $hosts, $type, $view, $other ) = + ( $header =~ /^(\w+)\s+\[([^\]]*)\]\s+(\w+)\s+(\w+)\b\s*(.*)$/ ); - &debug( "[$$] showing $query information for $hosts [$type:$view]" ); + # Now depending on what kind of request it is, pass it off to a routine + # that can process the message. - if( $query eq "problems" ) { &show_problems( @args ); } -# Disabled for now into all of Herbie's web enchanges are added -# if( $query eq "warnings" ) { &show_warnings( @args ); } - if( $query eq "summary" ) { &show_summary( @args ); } - if( $query eq "history" ) { &show_history( @args ); } - if( $query eq "host" ) { &show_host( @args ); } - if( $query eq "services" ) { &show_services( @args ); } - if( $query eq "acks" ) { &show_acks( @args ); } - if( $query eq "stats" ) { &show_stats( @args ); } - if( $query eq "config" ) { &show_config( @args ); } - if( $query eq "info" ) { &show_info( @args ); } - if( $query eq "service" ) { &show_service( @args, $other ); } - if( $query eq "histservice" ) { &show_hist_service( @args, $other ); } - if( $query eq "overview" ) { &show_overview( @args, $other ); } - if( $query eq "ovproblems" ) { &show_ovproblems( @args, $other ); } + my( @args ) = ( $hosts, $type, $view ); # Just shortens up the code... + my $output = select $client; - undef $client; - select $output; + &debug( "[$$] showing $query information for $hosts [$type:$view]" ); + + if( $query eq "problems" ) { &show_problems( @args ); } +# Disabled for now into all of Herbie's web enchanges are added +# if( $query eq "warnings" ) { &show_warnings( @args ); } + if( $query eq "summary" ) { &show_summary( @args ); } + if( $query eq "history" ) { &show_history( @args ); } + if( $query eq "host" ) { &show_host( @args ); } + if( $query eq "services" ) { &show_services( @args ); } + if( $query eq "acks" ) { &show_acks( @args ); } + if( $query eq "stats" ) { &show_stats( @args ); } + if( $query eq "config" ) { &show_config( @args ); } + if( $query eq "info" ) { &show_info( @args ); } + if( $query eq "service" ) { &show_service( @args, $other ); } + if( $query eq "histservice" ) { &show_hist_service( @args, $other ); } + if( $query eq "overview" ) { &show_overview( @args, $other ); } + if( $query eq "ovproblems" ) { &show_ovproblems( @args, $other ); } + + undef $client; + select $output; + exit; + + } # End of kid processing } } @@ -1303,7 +1357,7 @@ sub chld_handler { &debug( 'Shutting down, not restarting children',2); return; } - &debug( "caught CHLD signal, restarting child..." ); + &debug( "caught CHLD signal, exit status $?, restarting " ); while( my($name,$proc) = each %PROCS ) { if ( $pid == $proc->{'pid'} ) { @@ -1322,6 +1376,25 @@ sub chld_handler { } +# Child reaper for the forking server processes. It just reaps expired +# child processes to prevent zombies from accumulating. + +sub reaper { + my $kid; + + $kid = wait(); + $main::numchild--; + &debug("reaped kid $kid, # of child = $main::numchild"); + +# while( ($kid = waitpid(-1,&WNOHANG)) > 0 ) { +# $main::numchild--; +# &debug("reaped kid $kid, # of child = $main::numchild"); +# } + + # Reinstate signal handler in cae system uses sysV libs + $SIG{'CHLD'} = \&reaper; +} + # --------------------------------------------------------------------------- # Load all of the data functions into the DATAFUNCS registry # ---------------------------------------------------------------------------