$ref->{poolObj} = $clientPool;
exit 1 if ($clientPool->startPool(baseThreads => 10, moduleName => "SERVER::Main", subName => "clientThreadPool", values => $ref));
####
# Open Server Socket
my $sock = IO::Socket::INET->new(Proto => 'tcp',
LocalAddr => $servername,
LocalPort => $port,
Listen => SOMAXCONN,
Reuse => 1,
Blocking => 0);
our $selSock = IO::Select->new($sock);
#some more code is here, like initializing our db connection, and log4perl logger
while(my @ready = $selSock->can_read) {
foreach $_ (@ready) {
if ($_ == $sock) {
$logger->info("Base socket is " . $sock);
$logger->info("Adding new socket");
#create a new socket
my $newSock = $sock->accept or die;
$logger->info("Added new socket " . $newSock);
$selSock->add($newSock);
my $fd = fileno $newSock;
my $address = inet_ntoa($newSock->peeraddr);
# enqueue client connection to be processed
my @values = ($fd, $address);
if ($clientPool->queueJob(queueValues => \@values)) {
$logger->error("Failed to queue client connection");
# trash packets received from client
my $trash = <$newSock>;
send($newSock, "*** ENQUEUE_FAILED ***", 0);
send($newSock, "*** ZERO_BYTES_LEFT ***", 0);
$selSock->remove($newSock);
shutdown($newSock, 2);
close $newSock;
}
}
}
}
##
##
my $fd = @$work[0];
our $clientaddr = @$work[1];
my $selSock = $main::selSock;
# open file handle to read from... if fail to read error
# error can not be reported back to end user
# check has been implemented so dev can identify problem by error msg in server log
unless (open $fh, '+<&=' . $fd) {
$logger->error("Unable to open file handle for socket: $!");
$vars{poolObj}->setDone;
next;
}
# Get the password sent by client
my $clientpass = <$fh>;
##
##
# create and add socket file handle so it can be checked within the while loop
my $select = IO::Select->new();
$select->add($fh);
my $last = 1;
while ($last) {
my $subroutineCall;
my $command;
my $completeLine = "";
# check if anything is ready to be received from client
my @ready = $select->can_read(.1);
next unless (@ready);
# loop while receiving from the client untill a full msg has been received as identified by our flags
while (defined (my $line = <$fh>)) {
if ($line =~ /\*\*\* CLOSE_CONNECTION_CLIENT \*\*\*\n$/) {
$logger->info("Client closed connection to the server");
$last = 0;
$selSock->remove($fh);
shutdown($fh, 2);
close $fh;
last;
}
$completeLine .= $line;
if ($completeLine =~ /(.+) \*\*\* COMMAND_INPUT \*\*\* (.+) \*\*\* COMMAND_INPUT_END \*\*\*\n$/is) {
$subroutineCall = $1;
$command = $2;
$logger->info("Processing message \"" . $command . "\"");
last;
}
}
if ($last) {
#checking if the subroutine call is defined, if not, it kills that client connection (for cases of closing out of a client window and it sending the empty string)
if(defined($subroutineCall)){
$logger->debug("Calling subroutine '${subroutineCall}'");
my ($string) = executeCommand(subCall => $subroutineCall, command => $command);
send($fh, "$string\n*** ZERO_BYTES_LEFT ***" , 0);
}else{
$logger->info("Undefined subroutine passed, closing client connection.");
$last = 0;
$selSock->remove($fh);
shutdown($fh, 2);
close $fh;
last;
}
}
}
##
##
# execute the command and save results in a file handle to reduce memory usage
if (($head =~ /.+/) && ($tail =~ /.+/)) {
my @lastLines = ();
my $length;
open (my $fh, $vars{cmd} . " 2>&1|") or die;
while (<$fh>) {
#$logger->info($fh . " " . $_);
if ($_ =~ /$tail/ims) { #found the last line, terminate loop, do not append the output
$tailFound = 1;
last;
}
if($headFound){ #the header line is already found and ignored, so safe to apprend output
$output .= $_;
}
if (!$headFound and $_ =~ /$head/ims) { #next lines will be the matched output
$headFound = 1;
}
#keeps track of the most recent N lines
push(@lastLines, $_);
my $length = @lastLines;
if($length >= $vars{lastNLines}){
shift(@lastLines);
}
#$output .= $_;
}
unless ($headFound && $tailFound) {
$output = "\n\nCould not match command output. Printing the last $vars{lastNLines} lines:\n";
$output .= join("", @lastLines);
}
close ($fh);
} else {
open (my $fh, $vars{cmd} . " 2>&1|") or die;
while (<$fh>) {
#$logger->info($fh . " " . $_);
$output .= $_;
}
close ($fh);
}