--- googlecode.com/svn/trunk/meteord 2006/11/20 18:05:33 5 +++ googlecode.com/svn/trunk/meteord 2006/12/08 16:52:58 9 @@ -1,315 +1,320 @@ -#!/usr/bin/perl -w -############################################################################### -# Meteor -# An HTTP server for the 2.0 web -# Copyright (c) 2006 contributing authors -# -# The Meteor daemon -# -############################################################################### -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation; either version 2 of the License, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# For more information visit www.meteorserver.org -# -############################################################################### - - -############################################################################### -# Configuration -############################################################################### - - use strict; - - use Meteor::Syslog; - - use Meteor::Socket; - use Meteor::Connection; - use Meteor::Controller; - use Meteor::Subscriber; - use Meteor::Channel; - use Meteor::Document; - use Meteor::Config; - - $::CRLF="\r\n"; # Line separator to be used throughout all modules - - our $CONTROL_QUEUE_SIZE=5; - our $SUBSCRIBER_QUEUE_SIZE=20; - - our $MAIN_LOOP_TIMEOUT=60; - our $AGE_CHECK_INTERVALL=60; - - our $MAX_EXIT_DELAY=120; - -############################################################################### -# Main -############################################################################### - - # - # Program name - # - $::PGM=$0; - $::PGM=~s/^.*\///; - - # - # Handle command line options and config file - # - Meteor::Config->setCommandLineParameters(@ARGV); - - # - # Do something about warn and die - # - unless($::CONF{'Debug'}) - { - $SIG{'__WARN__'}=\&Meteor::Syslog::myWarn; - $SIG{'__DIE__'}=\&Meteor::Syslog::myDie; - } - - &::syslog('info',"$::PGM launched!"); - - # - # Daemonize - # - { - $0="$::PGM daemon"; - - unless($::CONF{'Debug'}) - { - # close standard file descriptors - close(STDIN); - close(STDOUT); - close(STDERR); - chdir("/"); - umask(0); - # fork and exit parent - exit if fork; - setpgrp(0, $$) if defined $SIG{TTOU}; - $SIG{TTOU}='ignore' if defined $SIG{TTOU}; - - # Avoid 'stdin reopened for output' warning with newer perls - open(NULL,'/dev/null'); - if(0); - - open(OUT,">/var/run/$::PGM.pid"); - print OUT "$$\n"; - close(OUT); - } - else - { - print "$::PGM PID: $$\n"; - } - } - - # - # Signal handlers - # - $::HUP=$::TERM=$::USR1=$::USR2=0; - $SIG{'HUP'}=sub{$::HUP=1}; - $SIG{'TERM'}=sub{$::TERM=1}; - $SIG{'USR1'}=sub{$::USR1=1}; - $SIG{'USR2'}=sub{$::USR2=1}; - - # - # Run server - # - my $con_counter=0; - my $con; - - my $controlServer=Meteor::Socket->newServer( - $::CONF{'ControllerPort'}, - $CONTROL_QUEUE_SIZE, - $::CONF{'ControllerIP'} - ); - my $controlServerFN=$controlServer->fileno(); - - my $subscriberServer=Meteor::Socket->newServer( - $::CONF{'SubscriberPort'}, - $SUBSCRIBER_QUEUE_SIZE, - $::CONF{'SubscriberIP'} - ); - my $subscriberServerFN=$subscriberServer->fileno(); - - my $serverVector=''; - vec($serverVector,$controlServerFN,1)=1; - vec($serverVector,$subscriberServerFN,1)=1; - - my $lastAgeCheck=time; - - my $nextPing=undef; - if(exists($::CONF{'PingInterval'}) && $::CONF{'PingInterval'}>2) - { - $nextPing=$::CONF{'PingInterval'}+$lastAgeCheck; - } - - while(!$::TERM) - { - eval - { - while(!$::TERM) - { - my $rVec=$serverVector; - my $wVec=''; - my $eVec=''; - - my $rout; - my $wout; - my $eout; - - Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec); - - my $timeout=$MAIN_LOOP_TIMEOUT; - if(defined($nextPing)) - { - $timeout=$nextPing-time; - } - - my $result=0; - if($timeout>0) - { - $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timeout); - } - - if($result>0) - { - if(vec($rout,$controlServerFN,1)) - { - Meteor::Controller->newFromServer($controlServer); - } - if(vec($rout,$subscriberServerFN,1)) - { - Meteor::Subscriber->newFromServer($subscriberServer); - } - - Meteor::Connection->checkAllHandleBits($rout,$wout,$eout); - } - elsif($result<0) - { - &::syslog('crit',"Select failed: $!"); - sleep(30); - } - - if($::HUP) - { - $::HUP=0; - - &::syslog('info',"Received SIGHUP, re-reading config and clearing document cache!"); - - Meteor::Config->readConfig(); - Meteor::Config->updateConfig(); - - Meteor::Document->clearDocuments() - } - - if($::USR1) - { - $::USR1=0; - - &::syslog('info',"Received SIGUSR1, clearing channel buffers!"); - - Meteor::Channel->clearAllBuffers(); - } - - if($::USR2) - { - $::USR2=0; - - &::syslog('info',"Received SIGUSR2, clearing document cache!"); - - Meteor::Document->clearDocuments() - } - - my $t=time; - if($t>$lastAgeCheck+$AGE_CHECK_INTERVALL) - { - my $minTimeStap=time-$::CONF{'MaxMessageAge'}; - Meteor::Channel->trimMessageStoresByTimestamp($minTimeStap); - $lastAgeCheck=time; - $t=$lastAgeCheck; - - Meteor::Subscriber->checkPersistentConnectionsForMaxTime(); - } - - if(defined($nextPing) && $nextPing<=$t) - { - $nextPing=undef; - - Meteor::Subscriber->pingPersistentConnections(); - - if(exists($::CONF{'MaxMessageAge'}) && $::CONF{'MaxMessageAge'}>2) - { - $nextPing=$::CONF{'PingInterval'}+time; - } - } - } - }; - unless($::TERM) - { - &::syslog('alert',"$::PGM loop died (will restart in 2 seconds): $@"); - sleep(2); - } - } - - # - # Proper shutdown - # - if($::TERM) - { - &::syslog('info',"Received SIGTERM, begin shutdown!"); - - $subscriberServer->close(); - $controlServer->close(); - - unlink("/var/run/$::PGM.pid") unless($::CONF{'Debug'}); - - Meteor::Connection->closeAllConnections(); - - my $timoutAt=time+$MAX_EXIT_DELAY; - - while(Meteor::Connection->connectionCount() && time<$timoutAt) - { - my $rVec=''; - my $wVec=''; - my $eVec=''; - - my $rout; - my $wout; - my $eout; - - Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec); - - my $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timoutAt-time); - - if($result>0) - { - Meteor::Connection->checkAllHandleBits($rout,$wout,$eout); - } - } - - if(my $cnt=Meteor::Connection->connectionCount()) - { - &::syslog('info',"$cnt client(s) unresponsive, will shutdown anyway"); - - exit(1); - } - - &::syslog('info',"shutdown succeeded"); - - exit(0); - } - - &::syslog('emerg',"$::PGM loop exited"); - -1; +#!/usr/bin/perl -w +############################################################################### +# Meteor +# An HTTP server for the 2.0 web +# Copyright (c) 2006 contributing authors +# +# The Meteor daemon +# +# Main program should call Meteor::Config::setCommandLineParameters(@ARGV),. +# Afterwards anybody can access $::CONF{}, where +# is any valid parameter (except 'Help') listed in the +# @DEFAULTS array below. +# +############################################################################### +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# For more information visit www.meteorserver.org +# +############################################################################### + + +############################################################################### +# Configuration +############################################################################### + + use strict; + + use Meteor::Syslog; + + use Meteor::Socket; + use Meteor::Connection; + use Meteor::Controller; + use Meteor::Subscriber; + use Meteor::Channel; + use Meteor::Document; + use Meteor::Config; + + $::CRLF="\r\n"; # Line separator to be used throughout all modules + + our $CONTROL_QUEUE_SIZE=5; + our $SUBSCRIBER_QUEUE_SIZE=20; + + our $MAIN_LOOP_TIMEOUT=60; + our $AGE_CHECK_INTERVALL=60; + + our $MAX_EXIT_DELAY=120; + +############################################################################### +# Main +############################################################################### + + # + # Program name + # + $::PGM=$0; + $::PGM=~s/^.*\///; + + # + # Handle command line options and config file + # + Meteor::Config->setCommandLineParameters(@ARGV); + + # + # Do something about warn and die + # + unless($::CONF{'Debug'}) + { + $SIG{'__WARN__'}=\&Meteor::Syslog::myWarn; + $SIG{'__DIE__'}=\&Meteor::Syslog::myDie; + } + + &::syslog('info',"$::PGM launched!"); + + # + # Daemonize + # + { + $0="$::PGM daemon"; + + unless($::CONF{'Debug'}) + { + # close standard file descriptors + close(STDIN); + close(STDOUT); + close(STDERR); + chdir("/"); + umask(0); + # fork and exit parent + exit if fork; + setpgrp(0, $$) if defined $SIG{TTOU}; + $SIG{TTOU}='ignore' if defined $SIG{TTOU}; + + # Avoid 'stdin reopened for output' warning with newer perls + open(NULL,'/dev/null'); + if(0); + + open(OUT,">/var/run/$::PGM.pid"); + print OUT "$$\n"; + close(OUT); + } + else + { + print "$::PGM PID: $$\n"; + } + } + + # + # Signal handlers + # + $::HUP=$::TERM=$::USR1=$::USR2=0; + $SIG{'HUP'}=sub{$::HUP=1}; + $SIG{'TERM'}=sub{$::TERM=1}; + $SIG{'USR1'}=sub{$::USR1=1}; + $SIG{'USR2'}=sub{$::USR2=1}; + + # + # Run server + # + my $con_counter=0; + my $con; + + my $controlServer=Meteor::Socket->newServer( + $::CONF{'ControllerPort'}, + $CONTROL_QUEUE_SIZE, + $::CONF{'ControllerIP'} + ); + my $controlServerFN=$controlServer->fileno(); + + my $subscriberServer=Meteor::Socket->newServer( + $::CONF{'SubscriberPort'}, + $SUBSCRIBER_QUEUE_SIZE, + $::CONF{'SubscriberIP'} + ); + my $subscriberServerFN=$subscriberServer->fileno(); + + my $serverVector=''; + vec($serverVector,$controlServerFN,1)=1; + vec($serverVector,$subscriberServerFN,1)=1; + + my $lastAgeCheck=time; + + my $nextPing=undef; + if(exists($::CONF{'PingInterval'}) && $::CONF{'PingInterval'}>2) + { + $nextPing=$::CONF{'PingInterval'}+$lastAgeCheck; + } + + while(!$::TERM) + { + eval + { + while(!$::TERM) + { + my $rVec=$serverVector; + my $wVec=''; + my $eVec=''; + + my $rout; + my $wout; + my $eout; + + Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec); + + my $timeout=$MAIN_LOOP_TIMEOUT; + if(defined($nextPing)) + { + $timeout=$nextPing-time; + } + + my $result=0; + if($timeout>0) + { + $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timeout); + } + + if($result>0) + { + if(vec($rout,$controlServerFN,1)) + { + Meteor::Controller->newFromServer($controlServer); + } + if(vec($rout,$subscriberServerFN,1)) + { + Meteor::Subscriber->newFromServer($subscriberServer); + } + + Meteor::Connection->checkAllHandleBits($rout,$wout,$eout); + } + elsif($result<0) + { + &::syslog('crit',"Select failed: $!"); + sleep(30); + } + + if($::HUP) + { + $::HUP=0; + + &::syslog('info',"Received SIGHUP, re-reading config and clearing document cache!"); + + Meteor::Config->readConfig(); + Meteor::Config->updateConfig(); + + Meteor::Document->clearDocuments() + } + + if($::USR1) + { + $::USR1=0; + + &::syslog('info',"Received SIGUSR1, clearing channel buffers!"); + + Meteor::Channel->clearAllBuffers(); + } + + if($::USR2) + { + $::USR2=0; + + &::syslog('info',"Received SIGUSR2, clearing document cache!"); + + Meteor::Document->clearDocuments() + } + + my $t=time; + if($t>$lastAgeCheck+$AGE_CHECK_INTERVALL) + { + my $minTimeStap=time-$::CONF{'MaxMessageAge'}; + Meteor::Channel->trimMessageStoresByTimestamp($minTimeStap); + $lastAgeCheck=time; + $t=$lastAgeCheck; + + Meteor::Subscriber->checkPersistentConnectionsForMaxTime(); + } + + if(defined($nextPing) && $nextPing<=$t) + { + $nextPing=undef; + + Meteor::Subscriber->pingPersistentConnections(); + + if(exists($::CONF{'MaxMessageAge'}) && $::CONF{'MaxMessageAge'}>2) + { + $nextPing=$::CONF{'PingInterval'}+time; + } + } + } + }; + unless($::TERM) + { + &::syslog('alert',"$::PGM loop died (will restart in 2 seconds): $@"); + sleep(2); + } + } + + # + # Proper shutdown + # + if($::TERM) + { + &::syslog('info',"Received SIGTERM, begin shutdown!"); + + $subscriberServer->close(); + $controlServer->close(); + + unlink("/var/run/$::PGM.pid") unless($::CONF{'Debug'}); + + Meteor::Connection->closeAllConnections(); + + my $timoutAt=time+$MAX_EXIT_DELAY; + + while(Meteor::Connection->connectionCount() && time<$timoutAt) + { + my $rVec=''; + my $wVec=''; + my $eVec=''; + + my $rout; + my $wout; + my $eout; + + Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec); + + my $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timoutAt-time); + + if($result>0) + { + Meteor::Connection->checkAllHandleBits($rout,$wout,$eout); + } + } + + if(my $cnt=Meteor::Connection->connectionCount()) + { + &::syslog('info',"$cnt client(s) unresponsive, will shutdown anyway"); + + exit(1); + } + + &::syslog('info',"shutdown succeeded"); + + exit(0); + } + + &::syslog('emerg',"$::PGM loop exited"); + +1; ############################################################################EOF \ No newline at end of file