/[meteor]/googlecode.com/svn/trunk/meteord
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /googlecode.com/svn/trunk/meteord

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 9 by andrew.betts, Fri Dec 8 16:52:58 2006 UTC revision 64 by andrew.betts, Mon Jan 19 11:19:41 2009 UTC
# Line 1  Line 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{<parameterName>}, where  
 #       <parameterName> 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');  
                         <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  
1    #!/usr/bin/perl -w
2    ###############################################################################
3    #   Meteor
4    #   An HTTP server for the 2.0 web
5    #   Copyright (c) 2006 contributing authors
6    #
7    #   The Meteor daemon
8    #
9    #       Main program should call Meteor::Config::setCommandLineParameters(@ARGV),.
10    #       Afterwards anybody can access $::CONF{<parameterName>}, where
11    #       <parameterName> is any valid parameter (except 'Help') listed in the
12    #       @DEFAULTS array below.
13    #
14    ###############################################################################
15    #
16    #   This program is free software; you can redistribute it and/or modify it
17    #   under the terms of the GNU General Public License as published by the Free
18    #   Software Foundation; either version 2 of the License, or (at your option)
19    #   any later version.
20    #
21    #   This program is distributed in the hope that it will be useful, but WITHOUT
22    #   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23    #   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
24    #   more details.
25    #
26    #   You should have received a copy of the GNU General Public License along
27    #   with this program; if not, write to the Free Software Foundation, Inc.,
28    #   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29    #
30    #   For more information visit www.meteorserver.org
31    #
32    ###############################################################################
33    
34    ###############################################################################
35    # meterod version
36    ################################################################################
37            
38            $::VERSION='1.06.04';
39            $::RELEASE_DATE='not yet released';
40    
41    ###############################################################################
42    # Configuration
43    ###############################################################################
44            
45            use strict;
46            
47            use Socket;
48            
49            use Meteor::Syslog;
50            
51            use Meteor::Socket;
52            use Meteor::Connection;
53            use Meteor::Controller;
54            use Meteor::Subscriber;
55            use Meteor::Channel;
56            use Meteor::Document;
57            use Meteor::Config;
58            
59            $::CRLF="\r\n";         # Line separator to be used throughout all modules
60            
61            our $CONTROL_QUEUE_SIZE=5;
62            our $SUBSCRIBER_QUEUE_SIZE=20;
63            
64            our $MAIN_LOOP_TIMEOUT=60;
65            our $AGE_CHECK_INTERVALL=60;
66            
67            our $MAX_EXIT_DELAY=120;
68            
69            our $UDP_MAX_MESSAGE_SIZE=8192;
70    
71    ###############################################################################
72    # Main
73    ###############################################################################
74            
75            #
76            # Record startup time
77            #
78            $::STARTUP_TIME=time;
79            $::STARTUP_TIME+=0; # avoid warning
80            
81            #
82            # Program name
83            #
84            $::PGM=$0;
85            $::PGM=~s/^.*\///;
86            
87            #
88            # Handle command line options and config file
89            #
90            Meteor::Config->setCommandLineParameters(@ARGV);
91            
92            #
93            # Do something about warn and die
94            #
95            unless($::CONF{'Debug'})
96            {
97                    $SIG{'__WARN__'}=\&Meteor::Syslog::myWarn;
98                    $SIG{'__DIE__'}=\&Meteor::Syslog::myDie;
99            }
100            
101            &::syslog('info',"$::PGM launched!");
102            
103            #
104            # Daemonize
105            #
106            {
107                    $0="$::PGM daemon";
108                    
109                    my $facility=$::CONF{'SyslogFacility'} || $Meteor::Syslog::DEFAULT_FACILITY;
110                    
111                    unless($::CONF{'Debug'} || $facility eq 'none')
112                    {
113                            # close standard file descriptors
114                            close(STDIN);
115                            close(STDOUT);
116                            close(STDERR);
117                            chdir("/");
118                            umask(0);
119    
120                            # fork and exit parent
121                            print STDERR "Exit: Fork\n";
122                            exit if fork;
123                            setpgrp(0, $$) if defined $SIG{TTOU};
124                            $SIG{TTOU}='ignore' if defined $SIG{TTOU};
125                            
126                            # Avoid 'stdin reopened for output' warning with newer perls
127                            open(NULL,'/dev/null');
128                            <NULL> if(0);
129                            open(OUT,">/var/run/$::PGM.pid");
130                            print OUT "$$\n";
131                            close(OUT);
132    
133                    }
134                    else
135                    {
136                            &::syslog('info',"PID\t%s",$$);
137                    }
138            }
139            
140            #
141            # Signal handlers
142            #
143            $::HUP=$::TERM=$::USR1=$::USR2=0;
144            $SIG{'HUP'}=sub{$::HUP=1};
145            $SIG{'TERM'}=sub{$::TERM=1};
146            $SIG{'USR1'}=sub{$::USR1=1};
147            $SIG{'USR2'}=sub{$::USR2=1};
148            $SIG{'PIPE'}=sub{&::syslog('info',"Signal PIPE received and ignored\n");};
149    
150            #
151            # Run server
152            #
153            my $con_counter=0;
154            my $con;
155            
156            my $controlServer=Meteor::Socket->newServer(
157                    $::CONF{'ControllerPort'},
158                    $CONTROL_QUEUE_SIZE,
159                    $::CONF{'ControllerIP'}
160            );
161            my $controlServerFN=$controlServer->fileno();
162            
163            my $subscriberServer=Meteor::Socket->newServer(
164                    $::CONF{'SubscriberPort'},
165                    $SUBSCRIBER_QUEUE_SIZE,
166                    $::CONF{'SubscriberIP'}
167            );
168            my $subscriberServerFN=$subscriberServer->fileno();
169            
170            my $udpServer=undef;
171            my $udpPort=$::CONF{'UDPPort'};
172            my $udpServerFN=undef;
173            if($udpPort && $udpPort>0)
174            {
175                    $udpServer=Meteor::Socket->newUDPServer(
176                            $udpPort,
177                            $::CONF{'UDPIP'}
178                    );
179                    $udpServerFN=$udpServer->fileno();
180            }
181            
182            my $serverVector='';
183            vec($serverVector,$controlServerFN,1)=1;
184            vec($serverVector,$subscriberServerFN,1)=1;
185            vec($serverVector,$udpServerFN,1)=1 if(defined($udpServerFN));
186            
187            my $lastAgeCheck=time;
188            
189            my $nextPing=undef;
190            if(exists($::CONF{'PingInterval'}) && $::CONF{'PingInterval'}>2)
191            {
192                    $nextPing=$::CONF{'PingInterval'}+$lastAgeCheck;
193            }
194            
195            while(!$::TERM)
196            {
197                    eval
198                    {
199                            while(!$::TERM)
200                            {
201    
202    
203                                    my $rVec=$serverVector;
204                                    my $wVec='';
205                                    my $eVec='';
206                            
207                                    my $rout;
208                                    my $wout;
209                                    my $eout;
210                            
211                                    Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec);
212                                    
213                                    my $timeout=$MAIN_LOOP_TIMEOUT;
214                                    if(defined($nextPing))
215                                    {
216                                            $timeout=$nextPing-time;
217                                    }
218                                    
219                                    my $result=0;
220                                    if($timeout>0)
221                                    {
222                                            $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timeout);
223                                    }
224                                    
225                                    if($result>0)
226                                    {
227                                            if(vec($rout,$controlServerFN,1))
228                                            {
229                                                    Meteor::Controller->newFromServer($controlServer);
230                                            }
231                                            if(vec($rout,$subscriberServerFN,1))
232                                            {
233                                                    Meteor::Subscriber->newFromServer($subscriberServer);
234                                            }
235                                            if(defined($udpServerFN) && vec($rout,$udpServerFN,1))
236                                            {
237                                                    &handleUPD($udpServer);
238                                            }
239                                            
240                                            Meteor::Connection->checkAllHandleBits($rout,$wout,$eout);
241                                    }
242                                    elsif($result<0)
243                                    {
244                                            &::syslog('crit',"Select failed: $!");
245                                            sleep(30);
246                                    }
247                                    
248                                    if($::HUP)
249                                    {
250                                            $::HUP=0;
251                                            
252                                            &::syslog('info',"Received SIGHUP, re-reading config and clearing document cache!");
253                                            
254                                            Meteor::Config->readConfig();
255                                            Meteor::Config->updateConfig();
256                                            
257                                            Meteor::Document->clearDocuments()
258                                    }
259                                    
260                                    if($::USR1)
261                                    {
262                                            $::USR1=0;
263                                            
264                                            &::syslog('info',"Received SIGUSR1, clearing channel buffers!");
265                                            
266                                            Meteor::Channel->clearAllBuffers();
267                                    }
268    
269                                    if($::USR2)
270                                    {
271                                            $::USR2=0;
272                                            
273                                            &::syslog('info',"Received SIGUSR2, clearing document cache!");
274                                            
275                                            Meteor::Document->clearDocuments()
276                                    }
277    
278                                    my $t=time;
279                                    if($t>$lastAgeCheck+$AGE_CHECK_INTERVALL)
280                                    {
281                                            my $minTimeStap=time-$::CONF{'MaxMessageAge'};
282                                            Meteor::Channel->trimMessageStoresByTimestamp($minTimeStap);
283                                            $lastAgeCheck=time;
284                                            $t=$lastAgeCheck;
285                                            
286                                            Meteor::Subscriber->checkPersistentConnectionsForMaxTime();
287                                            Meteor::Connection->destroyBadRequests();
288                                    }
289                                    
290                                    if(defined($nextPing) && $nextPing<=$t)
291                                    {
292                                            $nextPing=undef;
293                                            
294                                            Meteor::Subscriber->pingPersistentConnections();
295                                            
296                                            if(exists($::CONF{'MaxMessageAge'}) && $::CONF{'MaxMessageAge'}>2)
297                                            {
298                                                    $nextPing=$::CONF{'PingInterval'}+time;
299                                            }
300                                    }
301                            }
302                    };
303                    unless($::TERM)
304                    {
305                            &::syslog('alert',"$::PGM loop died (will restart in 2 seconds): $@");
306                            sleep(2);
307                    }
308            }
309            
310            #
311            # Proper shutdown
312            #
313            if($::TERM)
314            {
315                    &::syslog('info',"Received SIGTERM, begin shutdown!");
316                    
317                    $subscriberServer->close();
318                    $controlServer->close();
319                    
320                    unlink("/var/run/$::PGM.pid") unless($::CONF{'Debug'});
321                    
322                    Meteor::Connection->closeAllConnections();
323                    
324                    my $timoutAt=time+$MAX_EXIT_DELAY;
325                    
326                    while(Meteor::Connection->connectionCount() && time<$timoutAt)
327                    {
328                            my $rVec='';
329                            my $wVec='';
330                            my $eVec='';
331                            
332                            my $rout;
333                            my $wout;
334                            my $eout;
335                            
336                            Meteor::Connection->addAllHandleBits(\$rVec,\$wVec,\$eVec);
337                            
338                            my $result=&Meteor::Socket::sselect($rout=$rVec,$wout=$wVec,$eout=$eVec,$timoutAt-time);
339                            
340                            if($result>0)
341                            {
342                                    Meteor::Connection->checkAllHandleBits($rout,$wout,$eout);
343                            }
344                    }
345                    
346                    if(my $cnt=Meteor::Connection->connectionCount())
347                    {
348                            &::syslog('info',"$cnt client(s) unresponsive, will shutdown anyway");
349                            
350                            print STDERR "Exit: TERM Shutdown (unresponsive clients)\n";
351                            exit(1);
352                    }
353                    
354                    &::syslog('info',"shutdown succeeded");
355                    
356                    print STDERR "Exit: TERM Shutdown (clean)\n";
357                    exit(0);
358            }
359            
360            &::syslog('emerg',"$::PGM loop exited");
361    
362    ###############################################################################
363    # Subroutines
364    ###############################################################################
365    sub handleUPD {
366            $udpServer=shift;
367            
368            my $line;
369            my $hispaddr=recv($udpServer->{'handle'},$line,$::UDP_MAX_MESSAGE_SIZE,0);
370            
371            &::syslog('debug',"udp message received: %s",$line);
372            
373            return unless($line=~s/^(\S+)\s//);
374            
375            my $cmd=$1;
376            
377            if($cmd eq 'ADDMESSAGE')
378            {
379                    return unless($line=~s/^(\S+)\s//);
380                    
381                    my $channelName=$1;
382                    my $channel=Meteor::Channel->channelWithName($channelName);
383                    my $msg=$channel->addMessage($line);
384                    my $msgID=$msg->id();
385                    &::syslog('debug',"udp: new message added, ID %s",$msgID);
386            }
387    }
388    
389    1;
390    ############################################################################EOF

Legend:
Removed from v.9  
changed lines
  Added in v.64

  ViewVC Help
Powered by ViewVC 1.1.26