From: Mike Rylander Date: Wed, 11 Sep 2013 19:52:00 +0000 (-0400) Subject: Add support for the "Multiplex" personality X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=d4c80992d7456ce28af8d01446a5abe498854c22;p=working%2FSIPServer.git Add support for the "Multiplex" personality Signed-off-by: Mike Rylander --- diff --git a/SIPServer.pm b/SIPServer.pm index ff80f38..7bdc5b1 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; @@ -142,6 +156,115 @@ 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_connection { + my $self = shift; + my $mux = shift; + my $fh = shift; + + my $service; + my $sockname; + my ($sockaddr, $port, $proto); + my $transport; + + $self->{config} = $config; + + $sockaddr = $self->{net_server}{server}->{sockaddr}; + $port = $self->{net_server}{server}->{sockport}; + $proto = $self->{net_server}{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"; + } + + $transport = $transports{ $self->{service}->{transport} }; + + $active_connections{fileno($fh)} = { complete => 0, transport => $transport, net_server => bless({%$self}, ref($self)) }; + + if ( !defined($transport) ) { + syslog("LOG_WARNING", "Unknown transport '%s', dropping", $service->{transport}); + return; + } + +} + + +sub mux_input { + my $mself = shift; + my $mux = shift; + my $fh = shift; + + # check for kids that went away + REAPER(); + + my $connection = $active_connections{fileno($fh)}; + my $self = $connection->{net_server}; + + if (!$connection->{complete}) { # log them in + my $transport = $connection->{transport}; + + &$transport($self); + + $self->{ils}->disconnect() if (UNIVERSAL::can($self->{ils},'disconnect')); + $connection->{ils} = ref($self->{ils}); + delete $$self{ils}; + + $connection->{complete} = 1; + + return; + } + + 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} = $connection->{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 # diff --git a/SIPconfig.xml b/SIPconfig.xml index e5feefd..2989be8 100644 --- a/SIPconfig.xml +++ b/SIPconfig.xml @@ -1,8 +1,10 @@ + +