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

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

  ViewVC Help
Powered by ViewVC 1.1.26