use Net::Server::PreFork;
use Net::Server::Proto;
use IO::Socket::INET;
+use IO::String;
use Socket qw(:crlf);
use Data::Dumper; # For debugging
require UNIVERSAL::require;
+use POSIX qw/:sys_wait_h :errno_h/;
#use Sip qw(readline);
use Sip::Constants qw(:all);
sub REAPER {
for (keys(%kid_hash)) {
- if ( my $reaped = waitpid($_, &WNOHANG) > 0 ) {
+ if ( my $reaped = waitpid($_, WNOHANG) > 0 ) {
# Mourning... done.
$kid_count--;
delete $kid_hash{$_};
}
}
- $SIG{CHLD} = &REAPER();
+ $SIG{CHLD} = sub { REAPER() };
}
my %active_connections;
sub mux_input {
my $mself = shift;
my $mux = shift;
- my $fh = shift;
+ my $mux_fh = shift;
+ my $str_ref = shift;
- my $self;
- my $conn_id = fileno($fh);
+ # clone the mux string into a file handle
+ my $str_fh = IO::String->new(''.$$str_ref);
+
+ # clear read data from the mux string ref
+ $$str_ref = '';
+
+ my $conn_id = ''.$mux_fh;
# check for kids that went away
REAPER();
-
+ my $self;
if (!$active_connections{$conn_id}) { # Brand new connection, log them in
$self = $mself->{net_server};
if (! defined($self->{service})) {
syslog( "LOG_ERR", "process_request: Unrecognized server connection: %s:%s/%s",
$sockaddr, $port, $proto );
- die "process_request: Bad server connection";
+ syslog('LOG_ERR', "process_request: Bad server connection");
+ return;
}
my $transport = $transports{ $self->{service}->{transport} };
return;
}
- &$transport($self, $fh);
+ eval { &$transport($self, $str_fh) };
+ if ($@) {
+ syslog('LOG_ERR', "ILS login error: $@");
+ return;
+ }
$active_connections{$conn_id} =
{ id => $conn_id,
$active_connections{$conn_id}->{ils} = ref($self->{ils});
delete $$self{ils};
+ my $c = scalar(keys %active_connections);
+ syslog("LOG_DEBUG", "multi: new active connection; $c total");
+
return;
}
$self = $active_connections{$conn_id}->{net_server};
my $pid = fork();
- die "Cannot fork: $!" unless (defined($pid) && $pid > -1);
+ if (!defined($pid) or $pid < 0) {
+ syslog('LOG_ERR', "Unable to fork new child process $!");
+ return;
+ }
if ($pid == 0) { # in kid
# build the connection we deleted after logging in
$self->{ils} = $active_connections{$conn_id}->{ils}->new($self->{institution}, $self->{account});
- my $input = Sip::read_SIP_packet($fh);
+ # build the connection we deleted after logging in
+ my $input = Sip::read_SIP_packet($str_fh);
$input =~ s/[\r\n]+$//sm; # Strip off any trailing line ends
my $status = Sip::MsgType::handle($input, $self, '');
} else { # in parent
$kid_count++;
$kid_hash{$pid} = 1;
+ syslog("LOG_DEBUG", "multi: $conn_id forked child $pid; $kid_count total");
}
+}
+# client disconnected, remove the active connection
+sub mux_close {
+ my ($self, $mux, $fh) = @_;
+ delete $active_connections{''.$fh};
+ syslog("LOG_DEBUG", "multi: cleaning up child: $fh; ".
+ scalar(keys %active_connections)." remain");
}
+
#
# Transports
#
sub raw_transport {
my $self = shift;
- my $fh ||= *STDIN;
+ my $fh = shift || *STDIN;
+
my ($uid, $pwd);
my $input;
my $service = $self->{service};
syslog("LOG_DEBUG", "raw_transport: uname/inst: '%s/%s'",
$self->{account}->{id},
$self->{account}->{institution});
-
}
sub telnet_transport {
my $self = shift;
- my $fh ||= *STDIN;
+ my $fh = shift || *STDIN;
+
my ($uid, $pwd);
my $strikes = 3;
my $account = undef;