This commit was generated by cvs2svn to compensate for changes in r4407,
[freeside.git] / rt / bin / mason_handler.svc.in
1 #!@PERL@
2 # BEGIN BPS TAGGED BLOCK {{{
3
4 # COPYRIGHT:
5 #  
6 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
7 #                                          <jesse@bestpractical.com>
8
9 # (Except where explicitly superseded by other copyright notices)
10
11
12 # LICENSE:
13
14 # This work is made available to you under the terms of Version 2 of
15 # the GNU General Public License. A copy of that license should have
16 # been provided with this software, but in any event can be snarfed
17 # from www.gnu.org.
18
19 # This work is distributed in the hope that it will be useful, but
20 # WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 # General Public License for more details.
23
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
28
29 # CONTRIBUTION SUBMISSION POLICY:
30
31 # (The following paragraph is not intended to limit the rights granted
32 # to you to modify and distribute this software under the terms of
33 # the GNU General Public License and is only of importance to you if
34 # you choose to contribute your changes and enhancements to the
35 # community by submitting them to Best Practical Solutions, LLC.)
36
37 # By intentionally submitting any modifications, corrections or
38 # derivatives to this work, or any other work intended for use with
39 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
40 # you are the copyright holder for those contributions and you grant
41 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
42 # royalty-free, perpetual, license to use, copy, create derivative
43 # works based on those contributions, and sublicense and distribute
44 # those contributions and any derivatives thereof.
45
46 # END BPS TAGGED BLOCK }}}
47
48 =head1 NAME
49
50 mason_handler.svc - Win32 IIS Service handler for RT
51
52 =head1 SYNOPSIS
53
54     perl mason_handler.svc --install    # install as service
55     perl mason_handler.svc --deinstall  # deinstall this service
56     perl mason_handler.svc --help       # show this help
57     perl mason_handler.svc              # launch handler from command line
58
59 =head1 DESCRIPTION
60
61 This script manages a stand-alone FastCGI server, and populates the necessary
62 registry settings to run it with Microsoft IIS Server 4.0 or above.
63
64 Before running it, you need to install the B<FCGI> module from CPAN, as well as
65 B<Win32::Daemon> from L<http://www.roth.net/perl/Daemon/> if you want to install
66 itself as a service.
67
68 This script will automatically create a virtual directory under the IIS root;
69 its name is taken from C<$WebPath> in the F<RT_Config.pm> file.  Additionally,
70 please install the ISAPI binary from L<http://www.caraveo.com/fastcgi/> and set
71 up an ISAPI Script Map that maps F<.html> files to F<isapi_fcgi.dll>.
72
73 Once the service is launched (either via C<net start RTFastCGI> or by running
74 C<perl mason_handler.svc>), a FCGI server will start and bind to port C<8284>
75 (mnemonics: the ASCII value of C<R> and C<T>); the ISAPI handler's C<BindPath>
76 registry setting will also be automatically populated.
77
78 =cut
79
80 package RT::Mason;
81
82 use strict;
83 use File::Basename;
84 use vars '$Handler';
85 require (dirname(__FILE__) . '/webmux.pl');
86
87 use Cwd;
88 use File::Spec;
89
90 use Win32;
91 use Win32::Process;
92 use Win32::Service;
93 use Win32::TieRegistry;
94
95 my $ProcessObj;
96
97 BEGIN {
98     my $runsvc = sub {
99         Win32::Process::Create(
100             $ProcessObj, $^X, "$^X $0 --run", 0, NORMAL_PRIORITY_CLASS, "."
101         ) or do {
102             die Win32::FormatMessage( Win32::GetLastError() );
103         };
104
105         chdir File::Basename::dirname($0);
106         my $path = Cwd::cwd();
107         $path =~ s|/|\\|g;
108         $path =~ s|bin$|share\\html|;
109
110         $Win32::TieRegistry::Registry->{
111             'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\'.
112             'W3SVC\Parameters\Virtual Roots\\'
113         }->{$RT::WebPath || '/'} = "$path,,205";
114             
115         $Win32::TieRegistry::Registry->{
116             'HKEY_LOCAL_MACHINE\Software\FASTCGI\.html\\'
117         }->{'BindPath'} = $ENV{'FCGI_SOCKET_PATH'};
118
119         Win32::Service::StartService(Win32::NodeName, 'W3SVC');
120     };
121     
122     if ($ARGV[0] eq '--deinstall') {
123         chdir File::Basename::dirname($0);
124         my $path = Cwd::cwd();
125         $path =~ s|/|\\|g;
126
127         require Win32::Daemon;
128         Win32::Daemon::DeleteService('RTFastCGI');
129         warn "Service 'RTFastCGI' successfully deleted.\n";
130         exit;
131     }
132     elsif ($ARGV[0] eq '--install') {
133         chdir File::Basename::dirname($0);
134         my $path = Cwd::cwd();
135         $path =~ s|/|\\|g;
136
137         require Win32::Daemon;
138         Win32::Daemon::DeleteService('RTFastCGI');
139         
140         my $rv = Win32::Daemon::CreateService( {
141             machine =>  '',
142             name    =>  'RTFastCGI',
143             display =>  'RT FastCGI Handler',
144             path    =>  $^X,
145             user    =>  '',
146             pwd     =>  $path,
147             description => 'Enables port 8284 as the RT FastCGI handler.',
148             parameters  => File::Spec->catfile(
149                     $path, File::Basename::basename($0)
150             ) . ' --service',
151         } );
152     
153         if ($rv) {
154             warn "Service 'RTFastCGI' successfully created.\n";
155         }
156         else {
157             warn "Failed to add service: " . Win32::FormatMessage(
158                 Win32::Daemon::GetLastError()
159             ) . "\n";
160         }
161         exit;
162     }
163     elsif ($ARGV[0] eq '--service') {
164         require Win32::Daemon;
165
166         my $PrevState = Win32::Daemon::SERVICE_START_PENDING();
167         Win32::Daemon::StartService() or die $^E;
168
169         while ( 1 ) {
170             my $State = Win32::Daemon::State();
171             last if $State == Win32::Daemon::SERVICE_STOPPED();
172             
173             if ( $State == Win32::Daemon::SERVICE_START_PENDING() ) {
174                 $runsvc->();
175                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
176                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
177             }
178             elsif ( $State == Win32::Daemon::SERVICE_CONTINUE_PENDING() ) {
179                 $ProcessObj->Resume;
180                 Win32::Daemon::State( Win32::Daemon::SERVICE_RUNNING() );
181                 $PrevState = Win32::Daemon::SERVICE_RUNNING();
182             }
183             elsif ( $State == Win32::Daemon::SERVICE_STOP_PENDING() ) {
184             $ProcessObj->Kill(0);
185                 Win32::Daemon::State( Win32::Daemon::SERVICE_STOPPED() );
186                 $PrevState = Win32::Daemon::SERVICE_STOPPED();
187             }
188             elsif ( $State == Win32::Daemon::SERVICE_RUNNING() ) {
189                 my $Message = Win32::Daemon::QueryLastMessage(1);
190                 if ( $Message == Win32::Daemon::SERVICE_CONTROL_INTERROGATE() ) {
191                     Win32::Daemon::State( $PrevState );
192                 }
193                 elsif ( $Message == Win32::Daemon::SERVICE_CONTROL_SHUTDOWN() ) {
194                     Win32::Daemon::State( Win32::Daemon::SERVICE_STOP_PENDING(), 15000 );
195                 }
196                 elsif ( $Message != Win32::Daemon::SERVICE_CONTROL_NONE() ) {
197                     Win32::Daemon::State( $PrevState );
198                 }
199             }
200             
201             Win32::Sleep( 1000 );
202         }
203                 
204         Win32::Daemon::StopService();
205         exit;
206     }
207     elsif ($ARGV[0] eq '--help') {
208         system("perldoc $0");
209         exit;
210     }
211     elsif ($ARGV[0] ne '--run') {
212         $SIG{__DIE__} = sub { $ProcessObj->Kill(0) if $ProcessObj };
213         $runsvc->();
214         warn "RT FastCGI Handler launched. Press [Enter] to terminate...\n";
215         <STDIN>;
216         exit;
217     }
218 }
219
220 ###############################################################################
221
222 warn "Begin listening on $ENV{'FCGI_SOCKET_PATH'}\n";
223
224 require CGI::Fast;
225
226 RT::Init();
227
228 # Response loop
229 while( my $cgi = CGI::Fast->new ) {
230     my $comp = $ENV{'PATH_INFO'};
231
232     $comp = $1 if ($comp =~ /^(.*)$/);
233     $comp =~ s|^$RT::WebPath\b||i;
234     $comp .= "index.html" if ($comp =~ /\/$/);
235     $comp =~ s/.pl$/.html/g;
236     
237     warn "Serving $comp\n";
238
239     $Handler->handle_cgi($comp);
240     RT::Interface::Web::Handler->CleanupRequest();
241     # _should_ always be tied
242 }
243
244 1;
245
246 =head1 AUTHORS
247
248 Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
249
250 =head1 COPYRIGHT
251
252 Copyright 2002 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.
253
254 This program is free software; you can redistribute it and/or 
255 modify it under the same terms as Perl itself.
256
257 See L<http://www.perl.com/perl/misc/Artistic.html>
258
259 =cut