From: Mike Rylander Date: Wed, 11 Sep 2013 19:52:00 +0000 (-0400) Subject: LP#1339190 Add support for the "Multiplex" personality X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=70456ab85e5c0a0a807e0b7698b16deb97b3c4ee;p=working%2FSIPServer.git LP#1339190 Add support for the "Multiplex" personality Signed-off-by: Mike Rylander Signed-off-by: Bill Erickson --- diff --git a/SIPServer.pm b/SIPServer.pm index b5da1dc..1572895 100644 --- a/SIPServer.pm +++ b/SIPServer.pm @@ -1,7 +1,9 @@ # # Copyright (C) 2006-2008 Georgia Public Library Service +# Copyright (C) 2013 Equinox Software, Inc. # # Author: David J. Fiander +# Author: Mike Rylander # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -23,6 +25,7 @@ use strict; use warnings; use Exporter; use Sys::Syslog qw(syslog); +use Net::Server::Multiplex; use Net::Server::PreFork; use Net::Server::Proto; use IO::Socket::INET; @@ -82,14 +85,24 @@ push @parms, "syslog_facility=" . LOG_SIP; # -# Server Management: set parameters for the Net::Server::PreFork -# module. The module silently ignores parameters that it doesn't +# Server Management: set parameters for the Net::Server personality +# chosen, defaulting to PreFork. +# +# The PreFork module silently ignores parameters that it doesn't # recognize, and complains about invalid values for parameters # that it does. # +# The Fork module only cares about max_servers, for our purposes, which +# defaults to 256. +# +# The Multiplex module ignores all runtime params, and triggers an +# alternate implementation of the processing loop. See the Net::Server +# personality documentation for details. +# if (defined($config->{'server-params'})) { while (my ($key, $val) = each %{$config->{'server-params'}}) { push @parms, $key . '=' . $val; + @ISA = ('Net::Server::'.$val) if ($key eq 'personality'); } } @@ -104,7 +117,8 @@ SIPServer->run(@parms); # # process_request is the callback used by Net::Server to handle -# an incoming connection request. +# an incoming connection request when the peronsality is either +# Fork or PreFork. sub process_request { my $self = shift; @@ -145,12 +159,119 @@ sub process_request { syslog("LOG_INFO", '%s: shutting down', $transport); } +# mux_input is the callback used by Net::Server to handle +# an incoming connection request when the peronsality is +# Multiplex. + +my %kid_hash; +my $kid_count; + +sub REAPER { + for (keys(%kid_hash)) { + if ( my $reaped = waitpid($_, &WNOHANG) > 0 ) { + # Mourning... done. + $kid_count--; + delete $kid_hash{$_}; + } + } + $SIG{CHLD} = &REAPER(); +} + +my %active_connections; +sub mux_input { + my $mself = shift; + my $mux = shift; + my $fh = shift; + + my $self; + my $conn_id = fileno($fh); + + # check for kids that went away + REAPER(); + + + if (!$active_connections{$conn_id}) { # Brand new connection, log them in + $self = $mself->{net_server}; + + my ($sockaddr, $port, $proto); + + $self->{config} = $config; + + $sockaddr = $self->{server}->{sockaddr}; + $port = $self->{server}->{sockport}; + $proto = $self->{server}->{client}->NS_proto(); + + syslog('LOG_INFO', "Inbound connection from $sockaddr on port $port and proto $proto"); + + $self->{service} = $config->find_service( $sockaddr, $port, $proto ); + + if (! defined($self->{service})) { + syslog( "LOG_ERR", "process_request: Unrecognized server connection: %s:%s/%s", + $sockaddr, $port, $proto ); + die "process_request: Bad server connection"; + } + + my $transport = $transports{ $self->{service}->{transport} }; + + if ( !defined($transport) ) { + syslog("LOG_WARNING", "Unknown transport, dropping"); + return; + } + + &$transport($self, $fh); + + $active_connections{$conn_id} = + { id => $conn_id, + transport => $transport, + net_server => bless({%$self}, ref($self)) + }; + + # Evergreen, at least, needs a chance to clean up before forking for other requests + $self->{ils}->disconnect() if (UNIVERSAL::can($self->{ils},'disconnect')); + + # Stash the ILS module somewhere handy for later + $active_connections{$conn_id}->{ils} = ref($self->{ils}); + delete $$self{ils}; + + return; + } + + $self = $active_connections{$conn_id}->{net_server}; + + my $pid = fork(); + die "Cannot fork: $!" unless (defined($pid) && $pid > -1); + + 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); + $input =~ s/[\r\n]+$//sm; # Strip off any trailing line ends + + my $status = Sip::MsgType::handle($input, $self, ''); + + if (!$status) { + syslog("LOG_ERR", "raw_transport: failed to handle %s", substr($input,0,2)); + die "sip_protocol_loop: failed Sip::MsgType::handle('$input', $self, '')"; + } + + exit(0); + + } else { # in parent + $kid_count++; + $kid_hash{$pid} = 1; + } + +} + # # Transports # sub raw_transport { my $self = shift; + my $fh ||= *STDIN; my ($uid, $pwd); my $input; my $service = $self->{service}; @@ -164,7 +285,7 @@ sub raw_transport { while ($strikes--) { alarm $timeout; - $input = Sip::read_SIP_packet(*STDIN); + $input = Sip::read_SIP_packet($fh); alarm 0; if (!$input) { @@ -203,6 +324,7 @@ sub raw_transport { sub telnet_transport { my $self = shift; + my $fh ||= *STDIN; my ($uid, $pwd); my $strikes = 3; my $account = undef; @@ -220,12 +342,12 @@ sub telnet_transport { while ($strikes--) { print "login: "; alarm $timeout; - $uid = ; + $uid = <$fh>; alarm 0; print "password: "; alarm $timeout; - $pwd = ; + $pwd = <$fh>; alarm 0; $uid =~ s/[\r\n]+$//; diff --git a/SIPconfig.xml b/SIPconfig.xml index f9e3cf3..6f4a04a 100644 --- a/SIPconfig.xml +++ b/SIPconfig.xml @@ -1,8 +1,10 @@ + +