Facebook
From Soiled Hedgehog, 3 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 101
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. use IO::Socket::INET;
  6. use IO::Socket qw(AF_INET AF_UNIX SOCK_STREAM SHUT_WR);
  7. use Socket qw(:crlf);
  8. use IO::Select;
  9. use IO::Socket::UNIX qw( SOCK_STREAM SOMAXCONN );
  10. use XML::LibXML;
  11. use Data::Dump qw(dump);
  12. use Data::Dumper;
  13. use autodie;
  14.  
  15. use lib 'lib';
  16.  
  17. binmode STDERR, ':utf8';
  18.  
  19. #This is a self service proxy server for communication between the Koha REST "sipmessages" endpoint
  20. #and between a sipserver via Socket::INET sockets.
  21.  
  22. #Sipserver's service parameter must be set: client_timeout="0" in SIPconfig.xml for this script to work properly!
  23. #Self check device handles timeouts.
  24.  
  25. #While we attempt to write things to read-side through socket, if the socket of read-side already closed,
  26. #the write-side would got a signal SIGPIPE, that causes write-side killed by SIGPIPE.
  27. #????Prevents server from shutting down
  28. $SIG{PIPE} = 'IGNORE';
  29.  
  30. $SIG{'TSTP'} = 'IGNORE';    # Ctrl-Z disabled
  31.  
  32. if (defined $ENV{'DEBUG'})
  33. {
  34.         *STDERR = $ENV{'DEBUG'};
  35.         print STDERR "DEBUG found \n";
  36. }
  37. else {
  38.         print STDERR "$ENV{'DEBUG'} no log var found.\n";
  39. }
  40.  
  41. #Get command line argument (the sipdevice name = xml login parameter)
  42. my $device = shift or die "Usage: $0 SIPDEVICELOGINNAME\n";
  43.  
  44. print STDERR "Starting proxy server for device $device: \n";
  45.  
  46. my ( $proxyhost, $proxyport, $siphost, $sipport ) = getConfig($device);
  47.  
  48. #TODO change into var/spool/ in sipdevices.xml
  49.  
  50. $| = 1;    # Autoflush
  51.  
  52. #Needs to be a plain IO::Socket so we can use $client_socket->shutdown(SHUT_RD) and (SHUT_WR)to end
  53. #reading/writing to sipserver without problems and preserving socket connection
  54.  
  55. my $server = IO::Socket->new(
  56.         Domain    => AF_INET,
  57.         Type      => SOCK_STREAM,
  58.         Proto     => 'tcp',
  59.         LocalHost => $proxyhost,
  60.         LocalPort => $proxyport,
  61.         ReusePort => 1,
  62.         KeepAlive => 0,
  63.         Listen    => 5
  64. ) || die "Can't open proxy socket for $device: $@";
  65.  
  66. #handle signals
  67. #TODO CTRL+C sends an emtpy message to sipserver
  68. $SIG{TERM} = $SIG{INT} = $SIG{HUP} = sub {
  69.         print STDERR ("SIGTERM - External termination request. Leaving...");
  70.         if ($server) {
  71.                 print STDERR "Closing server socket. \n";
  72.                 $server->shutdown(SHUT_RDWR);
  73.                 $server->close;
  74.                 exit;
  75.         }
  76.         else {
  77.                 exit;
  78.         }
  79. };
  80.  
  81. #Socket:INET to sipserver
  82. my $sipsocket = IO::Socket::INET->new(
  83.  
  84.         PeerHost  => $siphost,
  85.         PeerPort  => $sipport,
  86.         Proto     => 'tcp',
  87.         KeepAlive => 1,
  88.         Reuse     => 1
  89.  
  90. ) or die "Couldn't be a tcp server on port '$sipport' : $@\n";
  91.  
  92. print STDERR "Waiting for tcp to connect to $proxyport\n";
  93.  
  94. while (1) {
  95.  
  96.         my $client_socket = $server->accept();
  97.  
  98.         #?
  99.         #my $sip_socket = $sipsocket->accept();
  100.  
  101.         print STDERR "Socket has connected\n";
  102.  
  103.         connection( $client_socket, $sipsocket );
  104.  
  105. }
  106.  
  107. $server->close;
  108.  
  109. sub connection {
  110.  
  111.         my $client_socket = shift;
  112.         $client_socket->autoflush(1);
  113.         my $sipsock = shift;
  114.         $sipsock->autoflush(1);
  115.  
  116.         if ( $sipsock->connected ) {
  117.                 print STDERR "Connection to SIP socket OK. \n";
  118.         }
  119.  
  120.         else {
  121.                 #???????????????????????
  122.                 #How to test if sipserver socket has disconnected
  123.                 print STDERR "Sip socket closed!";
  124.                 my $sipsocket = IO::Socket::INET->new(
  125.  
  126.                         PeerHost  => '10.0.3.217',
  127.                         PeerPort  => 6009,
  128.                         Proto     => 'tcp',
  129.                         KeepAlive => 1,
  130.                         Reuse     => 1
  131.  
  132.                 ) or die "Couldn't be a tcp server on port 6009 : $@\n";
  133.         }
  134.  
  135.         while (1) {
  136.  
  137.                 if ( $sipsock->connected ) {
  138.  
  139.                         #Still connected to SIP socket
  140.  
  141.                         my $data     = "";
  142.                         my $respdata = "";
  143.  
  144.                         $data = <$client_socket>;
  145.  
  146.                         #end reading from socket. $CR etc do not work.
  147.                         $client_socket->shutdown(SHUT_RD);
  148.                         $client_socket->flush;
  149.  
  150.                         if ( $data eq "" ) {
  151.                                 print STDERR "Empty request!"
  152.  
  153.                                   #return;
  154.                         }
  155.  
  156.                         print STDERR ">>>>>> Sending: $data\n";
  157.  
  158.                         print $sipsock $data;
  159.  
  160.                         $sipsock->recv( $respdata, 1024 );
  161.                         $sipsock->flush;
  162.  
  163.                         print STDERR "<<<<<< Received from SIPserver: $respdata\n\n";
  164.  
  165.                         ######Handle empty message ---_> next message needs a fresh connection
  166.                         ######Is this a failsafe in sipserver?
  167.                         if ( $respdata eq "" ) {
  168.                                 print STDERR "Sip server returned no data (bad device login mes/sipserver down?) $data\n";
  169.                                 my $errordata = "Disconnected!";
  170.  
  171.                                 #Send disconnect info to REST
  172.                                 print $client_socket $errordata . $CR;
  173.  
  174.                                 #end writing to socket
  175.                                 $client_socket->shutdown(SHUT_WR);
  176.  
  177.                                 #?
  178.                                 $client_socket->shutdown(SHUT_RDWR)
  179.                                   ;    # we stopped using this socket
  180.                                 $client_socket->close;
  181.                                 print STDERR "Sipserver disconnected. Exiting...\n";
  182.                                 exit;
  183.                         }
  184.                         else {
  185.                                 print $client_socket $respdata . $CR;
  186.                         }
  187.  
  188.                         ######Handle empty message -> next message needs a fresh connection -> restart proxy server
  189.  
  190.                         #end writing to socket
  191.                         $client_socket->shutdown(SHUT_WR);
  192.                         $client_socket->shutdown(SHUT_RDWR);  # we stopped using this socket
  193.                         $client_socket->close;
  194.  
  195.                         print STDERR "Sipserver response message passed to REST endpoint. Done. Listening...  \n\n";
  196.                         return;
  197.                 }
  198.  
  199.                 else {
  200.                         print STDERR "Sipserver socket Disconnected\n";
  201.  
  202.                         #Try to establish a new fresh connection or die?
  203.                         exit;
  204.  
  205.                 }
  206.         }
  207.  
  208. }
  209.  
  210. sub getConfig {
  211.  
  212.         #reads sip server info from config file and returns socket setup parameters
  213.        
  214.         my $device = shift;
  215.  
  216.         my ( $proxyhost, $proxyport, $host, $port );
  217.  
  218.         my $dom =
  219.           XML::LibXML->load_xml(
  220.                 location => "/home/koha/Koha/koha-tmpl/sipdevices.xml" );
  221.  
  222.         foreach my $sipserver ( $dom->findnodes( '//' . $device ) ) {
  223.                
  224.                 $proxyhost = $sipserver->findvalue('./proxyhost');
  225.                
  226.                 $proxyport = $sipserver->findvalue('./proxyport');
  227.  
  228.                 $host = $sipserver->findvalue('./host');
  229.  
  230.                 $port = $sipserver->findvalue('./port');
  231.  
  232.                 if ( $host && $port ) {
  233.                         print STDERR "Found config: '$host' '$port'  in sipdevices.xml. \n";
  234.                 }
  235.                 else {
  236.                         die "Missing parameters for '$device' in sipconfig.xml \n";
  237.                 }
  238.  
  239.         }
  240.  
  241.         return $proxyhost, $proxyport, $host, $port;
  242.  
  243. }
  244.  
  245.