/[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

Contents of /trunk/meteord

Parent Directory Parent Directory | Revision Log Revision Log


Revision 67 - (show annotations)
Sat Mar 28 01:42:07 2009 UTC (10 years, 1 month ago) by dpavlin
File size: 9135 byte(s)
correct trunk
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

  ViewVC Help
Powered by ViewVC 1.1.26