]> git.etc.gen.nz Git - spong.git/commitdiff
make update, bb_update and query processes forking to scale better.
authorStephen L Johnson <sjohnson@monsters.org>
Mon, 3 Apr 2000 16:47:41 +0000 (16:47 +0000)
committerStephen L Johnson <sjohnson@monsters.org>
Mon, 3 Apr 2000 16:47:41 +0000 (16:47 +0000)
src/spong-server.pl

index ee34cd5f6c6c604584e96d03b370cecdff5c7d1c..aa51bba7b815ae1b1ccbfaf235e00b8689514d67 100755 (executable)
@@ -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
 # ---------------------------------------------------------------------------