Skip to content
Snippets Groups Projects
managerproxy.pl 6.99 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/perl -w 
    
    #
    #  Simple Asterisk Manager Proxy, Version 1.01
    #  2004-09-26
    
    Olle Johansson's avatar
    Olle Johansson committed
    #  Copyright (c) 2004 David C. Troy <dave@popvox.com>
    
    #
    #  This code is based on Flash Operator Panel 'op_server.pl'
    
    Olle Johansson's avatar
    Olle Johansson committed
    #  by Nicolas Gudino
    
    #  Copyright (C) 2004.
    
    Olle Johansson's avatar
    Olle Johansson committed
    #  David C. Troy <dave@popvox.com>
    #  Nicolas Gudino <nicolas@house.com.ar>
    
    #
    #  This program is free software, distributed under the terms of
    #  the GNU General Public License.
    #
    
    #  Security consideration: This script will open your manager port
    #  for unauthenticated logins. Be careful out there :-)
    
    #############################
    
    #############################
    # Perl Prerequisites
    #############################
    use strict;
    use IO::Socket;
    use IO::Select;
    use POSIX qw(setsid);
    
    #############################
    # User Configurable Options
    #############################
    
    # Configuration for logging in to your asterisk server
    # Check you Asterisk config file "manager.conf" for details
    
    my $manager_host = '127.0.0.1';
    my $manager_port = 5038;
    my $manager_user = 'your_username';
    my $manager_secret = 'your_secret';
    
    # Port For this proxy
    my $listen_port = 1234;
    my $manager_pid = "/var/run/asterisk_managerproxy.pid";
    
    
    #############################
    # Declarations
    #############################
    my %proxy_clients;
    my $O;
    my $p;
    my @S;
    my %blocks;
    my $debug = 0;
    
    $SIG{PIPE} = 'IGNORE';
    $SIG{INT}  = 'close_all';
    $SIG{USR1} = 'list_clients';
    
    if (defined($ARGV[0]))
    {
        if ($ARGV[0] eq "-d")
        {
            defined(my $pid = fork) or die "Can't Fork: $!";
            exit if $pid;
            setsid or die "Can't start a new session: $!";
    
            open MYPIDFILE, ">$manager_pid";
    
            print MYPIDFILE $$;
            close MYPIDFILE;
        }
    } else {
       $debug = 1;
    }
    
    
    # Connect to manager
    $p =
    
      new IO::Socket::INET->new(
                                PeerAddr => $manager_host,
                                PeerPort => $manager_port,
                                Proto    => "tcp",
                                Type     => SOCK_STREAM
    
      or die "\nCould not connect to Asterisk Manager Port at $manager_host\n";
    
    $p->autoflush(1);
    
    
    # Login to Manager
    send_command_to_manager( "Action: Login\r\nUsername: $manager_user\r\nSecret: $manager_secret\r\n\r\n" );
    
    # Start up listener for new connections
    my $m =
    
      new IO::Socket::INET(Listen => 1, LocalPort => $listen_port, ReuseAddr => 1)
    
      or die "\nCan't listen to port $listen_port\n";
    $O = new IO::Select();
    
    $O->add($m);
    $O->add($p);
    
    $/ = "\0";
    
    sub manager_reconnect()
    {
        my $attempt        = 1;
        my $total_attempts = 60;
    
        do
        {
            log_debug("** Attempt reconnection to manager port # $attempt", 16);
            $p =
    
              new IO::Socket::INET->new(
                                        PeerAddr => $manager_host,
                                        PeerPort => $manager_port,
                                        Proto    => "tcp",
                                        Type     => SOCK_STREAM
    
                                       );
            $attempt++;
    
            if ($attempt > $total_attempts)
    
            {
                die("!! Could not reconnect to Asterisk Manager port");
            }
            sleep(10);    # wait 10 seconds before trying to reconnect
        } until $p;
    
        $O->add($p);
    
        send_command_to_manager(
            "Action: Login\r\nUsername: $manager_user\r\nSecret: $manager_secret\r\n\r\n"
        );
    }
    
    # Loop, continuously processing new connections, input from those connections, and input from Manager conn
    while (1)
    {
    
        while (@S = $O->can_read)
    
        {
            foreach (@S)
            {
                if ($_ == $m)
                {
                    log_debug("** New client connection", 16);
    
                    my $C = $m->accept;
    
                    $proxy_clients{$C} = \$C;                
                    print "New Connection: $C\n" if $debug;
    
                    $O->add($C);
    
                } else {
                    # It's not a new client connection
                    my $i;
                    my $R = sysread($_, $i, 2);    # 2048; interleave every two bytes?
    
                    if (defined($R) && $R == 0)
    
                    {
                        # Confirm it's really dead by trying to write to it?
                        my $T = syswrite($_, ' ', 2);    # 2048
                        if (!defined($T))
                        {
                            # connection went away...
    
                            $O->remove($_);
                            $_->close;
    
    
                            # If we lost the socket for the Asterisk Mgr, then reconnect
                            if ($_ == $p)
                            {
                                log_debug(
                                         "** Asterisk Manager connection lost!!!!!",
                                         16);
                                manager_reconnect();
                            } else {
                                # Remove handle from proxy_clients hash
                                print "Closed Connection: $_\n" if $debug;
                                delete $proxy_clients{$_};
                            }
                        }
                    }
                    else  # Socket is active and we are ready to read something from it
                    {
                        $blocks{$_} .= $i;
                        next if ($blocks{$_} !~ /\r\n\r\n$/);
                        # do a 'next' unless we have completed a block; we are not ready to continue
    
                        # Process the completed block
                        # If block is from asterisk, send to clients
                        if ($_ == $p) {
                           # block is from asterisk, send to clients
                           print "asterisk: $_\n$blocks{$_}" if $debug;
                           my $cnt = 0;
                           foreach my $client (values %proxy_clients) {
                              print "writing to $$client...\n" if $debug;
                              syswrite($$client, $blocks{$_});
                              $cnt++;
                           }
                           print "sent block to $cnt clients\n" if $debug;
                        } else {
                           # Blocks are from clients, send to asterisk
                           syswrite($p, $blocks{$_});
                           print "client: $_\n$blocks{$_}\n" if $debug;
                        }
                        delete $blocks{$_};
    
                    } # end if read succeeded
                } # end if new client connection
    
            }    # end foreach @S -> can read
    
        }    # while can read
    }    # endless loop
    
    sub close_all
    {
        log_debug("Exiting...", 0);
    
    
        foreach my $hd ($O->handles)
    
            $O->remove($hd);
    
            close($hd);
        }
    
        exit(0);
    }
    
    sub send_command_to_manager
    {
        my $comando = shift;
        if (defined $p)
        {
            my @lineas = split("\r\n", $comando);
            foreach my $linea (@lineas)
            {
                syswrite($p, "$linea\r\n");
    
                log_debug("-> $linea", 2);
    
            }
            log_debug(" ", 2);
            syswrite($p, "\r\n");
        }
    }
    
    sub log_debug
    {
        my $texto = shift;
        $texto =~ s/\0//g;
        print "$texto\n" if $debug;
    }
    
    sub list_clients()
    {
       my $cnt = 0;
       foreach my $client (values %proxy_clients) {
          print "client: $$client\n";
          $cnt++;
       }
       print "$cnt clients.\n\n";
    }