#!/usr/bin/perl
# use strict;
# site: www.jb200.com
use FCGI;
use Getopt::Long;
use IO::All;
use Socket;
sub init {
GetOptions( "h" => $help,
"verbose!"=>$verbose,
"pid=s" => $filepid,
"l=s" => $logfile,
"S:s" => $unixsocket,
"P:i" => $unixport) or usage();
usage() if $help;
print " Starting
nginx-fcgin" if $verbose;
print " Running with $> UID" if $verbose;
print " Perl $]" if $verbose;
# if ( $> == "0" ) {
# print "ntERRORtRunning as a root!n";
# print "tSuggested not to do so !!!nn";
# exit 1;
# }
if ( ! $logfile ) {
print "ntERRORt log file must declaredn"
. "tuse $0 with option -l filenamenn";
exit 1;
}
print " Using log file $logfilen" if $verbose;
"nn" >> io($logfile);
addlog($logfile, "Starting Nginx-cfgi");
addlog($logfile, "Running with $> UID");
addlog($logfile, "Perl $]");
addlog($logfile, "Testing socket options");
if ( ($unixsocket && $unixport) || (!($unixsocket) && !($unixport)) ) {
print "ntERRORtOnly one option can be u
sed!n";
print "tSuggested (beacuse of speed) is usage UNIX socket -S nn";
exit 1;
}
if ($unixsocket) {
print " Daemon listening at UNIX socket $unixsocketn" if $versbose;
addlog($logfile, "Deamon listening at UNIX socket $unixsocket");
} else {
print " Daemon listening at TCP/IP socket *:$unixportn" if $verbose;
#
addlog($logfile, "Daemon listening at TCP/IP socket *:$unixport");
}
if ( -e $filepid ) {
print "ntERRORt PID file $filepid already existsnn";
addlog($logfile, "Can not use PID file $filepid, already exists.");
exit 1;
}
if ( $unixsocket ) {
print " Creating UNIX socketn" if $verbose;
$socket = FCGI::OpenSocket( $unixsocket, 10 );
if ( !$socket) {
print " Couldn't create socketn";
addlog($logfile, "Couldn't create socket");
exit 1;
}
print " Using UNIX socket $unixsocketn" if $verbose;
} else {
print " Creating TCP/IP socketn" if $verbose;
$portnumber = ":".$unixport;
$socket = FCGI::OpenSocket( $unixport, 10 );
if ( !$socket ) {
print " Couldn't create socketn";
addlog($logfile, "Couldn't create socket");
exit 1;
}
print " Using port $unixportn" if $verbose;
}
addlog($logfile, "Socket created");
if ( ! $filepid ) {
print "ntERRORt PID file must declaredn"
. "tuse $0 with option -pid filenamenn";
exit 1;
}
print " Using PID file $filepidn" if $verbose;
addlog($logfile, "Using PID file $filepid");
my $pidnumber = $$;
$pidnumber > io($filepid);
print " PID number $$n" if $verbose;
addlog($logfile, "PID number $pidnumber");
}
sub addzero {
my ($date) = shift;
if ($date < 10) {
return "0$date";
}
return $date;
}
sub logformat {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$iddst) = localtime(time);
my $datestring;
$year += 1900;
$mon++;
$mon = addzero($mon);
$mday = addzero($mday);
$min = addzero($min);
$datestring = "$year-$mon-$mday $hour:$min";
return($datestring);
}
sub addlog {
my ($log_file, $log_message) = @_;
my $curr_time = logformat();
my $write_message = "[$curr_time] $log_message";
$write_message >> io($log_file);
"n" >> io($log_file);
}
sub printerror {
my $message = @_;
print "n Nginx
fastcgitERRORn"
. "t $messagenn";
exit 1;
}
sub usage {
print "n Nginx FastCGI n"
. "ntusage: $0 [-h] -S string -P intn"
. "nt-htt: this (help) message"
. "nt-S pathtt: path for UNIX socket"
. "nt-P porttt: port number"
. "nt-p filett: path for pid file"
. "nt-l filett: path for logfile"
. "nntexample: $0 -S /var/run/nginx-perl_cgi.sock -l /var/log/nginx/nginx-cfgi.log -pid /var/run/nginx-fcgi.pidnn";
exit 1;
}
init;
exit unless $@ =~ /^fakeexit/;
} ;
# fork part
my $pid = fork();
if( $pid == 0 ) {
&main;
exit 0;
}
print " Forking worker process with PID $pidn" if $verbose;
addlog($logfile, "Forking worker process with PID $pid");
print " Update PID file $filepidn" if $verbose;
addlog($logfile, "Update PID file $filepid");
$pid > io($filepid);
print " Worker process running.n" if $verbose;
addlog ($logfile, "Parent process $$ is exiting");
exit 0;
sub main {
$request = FCGI::Request( *STDIN, *STDOUT, *STDERR, %req_params, $socket );
if ($request) { request_loop()};
FCGI::CloseSocket( $socket );
}
sub request_loop {
while( $request->Accept() >= 0 ) {
# processing any STDIN input from WebServer (for CGI-POST actions)
$stdin_passthrough = '';
$req_len = 0 + $req_params{'CONTENT_LENGTH'};
if (($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){
while ($req_len) {
$stdin_passthrough .= getc(STDIN);
$req_len--;
}
}
# running the cgi app
if ( (-x $req_params{SCRIPT_FILENAME}) &&
(-s $req_params{SCRIPT_FILENAME}) &&
(-r $req_params{SCRIPT_FILENAME})
){
foreach $key ( keys %req_params){
$ENV{$key} = $req_params{$key};
}
if ( $verbose ) {
addlog($logfile, "running $req_params{SCRIPT_FILENAME}");
}
# http://perldoc.perl.org/perlipc.html#Safe-Pipe-Opens
#
#open $cgi_app, '-|', $req_params{SCRIPT_FILENAME}, $stdin_passthrough or print("Content-type: text/plainrnrn"); print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !n"; # addlog($logfile, "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !");
open $cgi_app, '-|', "echo '$stdin_passthrough' | '$req_params{SCRIPT_FILENAME}'" or print("Content-type: text/plainrnrn"); print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !n"; # addlog($logfile, "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !");
if ($cgi_app) {
print <$cgi_app>;
close $cgi_app;
}
} else {
print("Content-type: text/plainrnrn");
print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.n";
addlog($logfile, "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.");
}
}
}