@@ -, +, @@ --- C4/SIP/SIPServer.pm | 114 +++++++++++++++++++++++++++++++--------------------- etc/SIPconfig.xml | 20 ++++----- 2 files changed, 80 insertions(+), 54 deletions(-) --- a/C4/SIP/SIPServer.pm +++ a/C4/SIP/SIPServer.pm @@ -6,7 +6,6 @@ use warnings; use FindBin qw($Bin); use lib "$Bin"; use Sys::Syslog qw(syslog); -use Net::Server::PreFork; use IO::Socket::INET; use Socket qw(:DEFAULT :crlf); require UNIVERSAL::require; @@ -17,7 +16,7 @@ use C4::SIP::Sip::Checksum qw(checksum verify_cksum); use C4::SIP::Sip::MsgType qw( handle login_core ); use C4::SIP::Sip qw( read_SIP_packet ); -use base qw(Net::Server::PreFork); +use base qw(Net::Server::Fork); use constant LOG_SIP => "local6"; # Local alias for the logging facility @@ -124,28 +123,26 @@ sub process_request { sub raw_transport { my $self = shift; - my ($input); my $service = $self->{service}; while (!$self->{account}) { - local $SIG{ALRM} = sub { die "raw_transport Timed Out!\n"; }; - syslog("LOG_DEBUG", "raw_transport: timeout is %d", $service->{timeout}); - $input = read_SIP_packet(*STDIN); - if (!$input) { - # EOF on the socket - syslog("LOG_INFO", "raw_transport: shutting down: EOF during login"); - return; - } - $input =~ s/[\r\n]+$//sm; # Strip off trailing line terminator(s) - last if C4::SIP::Sip::MsgType::handle($input, $self, LOGIN); + my $input = read_request(); + if (!$input) { + # EOF on the socket + syslog("LOG_INFO", "raw_transport: shutting down: EOF during login"); + return; + } + $input =~ s/[\r\n]+$//sm; # Strip off trailing line terminator(s) + last if C4::SIP::Sip::MsgType::handle($input, $self, LOGIN); } syslog("LOG_DEBUG", "raw_transport: uname/inst: '%s/%s'", - $self->{account}->{id}, - $self->{account}->{institution}); + $self->{account}->{id}, + $self->{account}->{institution}); $self->sip_protocol_loop(); syslog("LOG_INFO", "raw_transport: shutting down"); + return; } sub get_clean_string { @@ -230,6 +227,7 @@ sub telnet_transport { syslog("LOG_DEBUG", "telnet_transport: uname/inst: '%s/%s'", $account->{id}, $account->{institution}); $self->sip_protocol_loop(); syslog("LOG_INFO", "telnet_transport: shutting down"); + return; } # @@ -241,8 +239,6 @@ sub sip_protocol_loop { my $self = shift; my $service = $self->{service}; my $config = $self->{config}; - my $timeout = $self->{service}->{timeout} || $config->{timeout} || 30; - my $input; # The spec says the first message will be: # SIP v1: SC_STATUS @@ -258,37 +254,65 @@ sub sip_protocol_loop { # # In short, we'll take any valid message here. #my $expect = SC_STATUS; - local $SIG{ALRM} = sub { die "SIP Timed Out!\n"; }; - my $expect = ''; - while (1) { - alarm $timeout; - $input = read_SIP_packet(*STDIN); - unless ($input) { - return; # EOF + while ( my $inputbuf = read_request() ) { + if ( !defined $inputbuf ) { + return; # EOF } - # begin input hacks ... a cheap stand in for better Telnet layer - $input =~ s/^[^A-z0-9]+//s; # Kill leading bad characters... like Telnet handshakers - $input =~ s/[^A-z0-9]+$//s; # Same on the end, should get DOSsy ^M line-endings too. - while (chomp($input)) {warn "Extra line ending on input";} - unless ($input) { - syslog("LOG_ERR", "sip_protocol_loop: empty input skipped"); + + unless ($inputbuf) { + syslog( "LOG_ERR", "sip_protocol_loop: empty input skipped" ); print("96$CR"); next; - } - # end cheap input hacks - my $status = handle($input, $self, $expect); - if (!$status) { - syslog("LOG_ERR", "sip_protocol_loop: failed to handle %s",substr($input,0,2)); - } - next if $status eq REQUEST_ACS_RESEND; - if ($expect && ($status ne $expect)) { - # We received a non-"RESEND" that wasn't what we were expecting. - syslog("LOG_ERR", "sip_protocol_loop: expected %s, received %s, exiting", $expect, $input); - } - # We successfully received and processed what we were expecting - $expect = ''; - alarm 0; - } + } + + # end cheap input hacks + my $status = C4::SIP::Sip::MsgType::handle( $inputbuf, $self, q{} ); + if ( !$status ) { + syslog( + "LOG_ERR", + "sip_protocol_loop: failed to handle %s", + substr( $inputbuf, 0, 2 ) + ); + } + next if $status eq REQUEST_ACS_RESEND; + } + return; +} + +sub read_request { + my $raw_length; + local $/ = "\015"; + + # proper SPEC: (octal) \015 = (hex) x0D = (dec) 13 = (ascii) carriage return + my $buffer = ; + if ( defined $buffer ) { + STDIN->flush(); # clear an extra linefeed + chomp $buffer; + syslog( "LOG_INFO", "read_SIP_packet, INPUT MSG: '$buffer'" ); + $raw_length = length $buffer; + $buffer =~ s/^\s*[^A-z0-9]+//s; +# Every line must start with a "real" character. Not whitespace, control chars, etc. + $buffer =~ s/[^A-z0-9]+$//s; + +# Same for the end. Note this catches the problem some clients have sending empty fields at the end, like ||| + $buffer =~ s/\015?\012//g; # Extra line breaks must die + $buffer =~ s/\015?\012//s; # Extra line breaks must die + $buffer =~ s/\015*\012*$//s; + + # treat as one line to include the extra linebreaks we are trying to remove! + } + else { + syslog( 'LOG_DEBUG', 'EOF returned on read' ); + return; + } + my $len = length $buffer; + if ( $len != $raw_length ) { + my $trim = $raw_length - $len; + syslog( "LOG_DEBUG", "read_SIP_packet, trimmed $trim character(s) " ); + } + + syslog( "LOG_INFO", "INPUT MSG: '$buffer'" ); + return $buffer; } 1; --- a/etc/SIPconfig.xml +++ a/etc/SIPconfig.xml @@ -3,7 +3,7 @@ @@ -13,15 +13,17 @@ log_file='Sys::Syslog' syslog_ident='koha_sip' syslog_facility='local6' + setsid="1" /> + - --