[Asterisk-Users] why $cdr{'CALLERID'} and $cdr{'DNID'} are empty in perl agi connected with asterisk manager

Kamran Ahmad p_kami at yahoo.com
Mon Jul 18 05:20:11 MST 2005


hello perl experts

i am working with "ast-rad-acc.pl" from
http://www.voip-info.org/tiki-index.php?page=PortaOne+Radius+auth

i dont know why $cdr{'DNID'} and $cdr{'CALLERID'}
under 'sub send_acc {' are empty. i m successfully
connected with asterisk manager and when call i hangup
my perl application is getting that all other thing
are ok but i dont know why only these two variables
are not working. other variables like CALLID,
ACCOUNTCODE, etc are ok but these two DNID and
CALLERID are empty

here is the code i am using with asterisk-CVS

#!/usr/bin/perl 
#
# Based on http://mail.newmmc.com/~wsmith/astcdr
author is unknown,
# found here
http://www.voip-info.org/wiki-Asterisk+AGI
#
# RADIUS Accounting By
# (c)2004 Porta Software Ltd. www.portaone.com
# Oleksandr Kapitanenko <kapitan at portaone.com>
#

use strict;
use Asterisk::Manager;
use Sys::Syslog;
use POSIX;
use Config::IniFiles;
use Authen::Radius;
Authen::Radius->load_dictionary;

# Lock file
#
my $lock_file = '/var/run/ast-rad-acc.pid';

# Config vars
#
my $runas_user = 'nobody';

my $ast_hostname = 'localhost';
my $ast_username = 'test';
my $ast_password = 'test';

my $monitor_dir = '/var/spool/asterisk/monitor';

# Read global RADIUS configuratuin from
extensions.conf
#
# I havte doing that but Asterisk manager interface
can not read global variables
#
my $config_dir = '/usr/local/etc/asterisk';

# Globals
#
my %channels;
my ($rad_serv, $rad_sec, $nas_ip);

# Check if already running
#
if( -e $lock_file ) {
   open(PID,$lock_file);
   my $pid=<PID>;
   close PID;
   chomp $pid;
   if( !-e "/proc/$pid" ) {
      print STDERR "Lock file present, but no process
with pid=$pid.\n";
      die "Can't delete lock file $lock_file\n" if
!unlink $lock_file;
      print STDERR "Lock file has been removed.\n";
   } else {
      die "Lockfile present, another copy is punning
pid=$pid\n";
   }
}

load_config();
my ($name, $passwd, $uid, $gid) =
getpwnam($runas_user) or die "$runas_user not in
passwd file";;

# Become daemon
#
my $pid;
if( !defined($pid = fork()) ) {
	die "cannot fork: $!";
} elsif ($pid) {
	# Create lockfile, and finish parent process
	#
	open(PID, "> $lock_file") || die "ast-rad-acc.pl:
Unable to create lockfile $lock_file\n";
	print PID "$pid";
	close PID;
	chown $uid, $gid, $lock_file;
	exit;
} else {
        # daemon
        setpgrp();
        select(STDERR); $| = 1;
        select(STDOUT); $| = 1;
	openlog('ast-rad-acc', 'cons,pid', 'daemon');
        syslog('notice', "RADIUS accounting for
Asterisk started");
}

# Install signall handler
#
$SIG{INT} = \&safe_exit;
$SIG{QUIT} = \&safe_exit;
$SIG{TERM} = \&safe_exit;
$SIG{HUP} = \&load_config;

# Drop privileges
#
setuid($uid);
$< = $uid;
$> = $uid;

my $astman = new Asterisk::Manager;
$astman->user($ast_username);
$astman->secret($ast_password);
$astman->host($ast_hostname);

my $ast_connected = 1;
while( 1 ) {
	if( $astman->connect ) {
		$ast_connected = 1;
		syslog('info', 'Connected to Asterisk!');
		$astman->setcallback('DEFAULT', \&status_callback);
		eval { $astman->eventloop; };
	} else {
		syslog('err', 'Could not connect to Asterisk!') if
$ast_connected;
		$ast_connected = 0;
	}
	sleep 1;
}

sub status_callback {
	my (%event) = @_;

	return unless defined(%event);

        foreach (keys %event) {
                syslog('debug', "$_: ". $event{$_} .
"\n" );
        }
        syslog('debug', "\n");

	
	for ($event{'Event'}) {
# Variable read example
#                print STDERR $astman->sendcommand(
Action => 'Getvar', Channel => $event{'Channel'},
Variable => 'DNID' );
		$event{'Callerid'} = $1 if defined
$event{'Callerid'}  && $event{'Callerid'} =~
/<(\d*)>/;
		/newchannel/i && do {
			my $call_origin = "originate";
			$call_origin = "answer" if $event{'State'} =~
/^Ring$/i;

			my $call_type = "VoIP";
                        $call_type = "Telephony" if
$event{'Channel'} =~
/^(Zap)|(VPB)|(phone)|(Modem)|(CAPI)|(mISDN)|(Console)/;
# session-protocol 
# other, cisco, h323, multicast, sipv2, sdp,
frf11-trunk, cisco-switched, MarsAnalog, C1000Isdn,
aal2-trunk
			my $protocol = 'other';
			$protocol = 'sipv2' if $event{'Channel'} =~
/^SIP/i;
			$protocol = 'h323' if $event{'Channel'} =~
/^h323/i;

			$channels{$event{'Channel'}} = { 
				'CHANNEL' => $event{'Channel'},
				'CALLERID' => $event{'Callerid'},
				'DNID' => $event{'DNID'},
				'UNIQUEID' => $event{'Uniqueid'},
				'CALL_START' => time(),
				'LINK_START' => time(),
				'LINK_END' => time(),
				'CALL_ORIGIN' => $call_origin,
				'CALL_TYPE' => $call_type,
				'CALL_PROTOCOL' => $protocol,
				'CALL_ID' => $event{'Uniqueid'},
				'RADIUS_Server' => $rad_serv,
				'RADIUS_Secret' => $rad_sec,
				'NAS_IP_Address' => $nas_ip
			};
			$channels{$event{'Channel'}}{'Remoteip'} =
$event{'Remoteip'} if defined $event{'Remoteip'};
		};

		/newexten/i && do {
			$channels{$event{'Channel'}}{'DNID'} =
$event{'DNID'} if defined $event{'DNID'};
			$channels{$event{'Channel'}}{'ACCOUNTCODE'} =
$event{'AppData'} 
				if defined $event{'Application'} &&
$event{'Application'} eq 'SetAccount';

                        if( defined
$event{'Application'} && $event{'Application'} eq
'SetVar') {
				my ( $_var, $_val ) = split(/=/,
$event{'AppData'});
				$channels{$event{'Channel'}}{$_var} = $_val;
			}
		};

                /Newcallerid/i && do {
                       
$channels{$event{'Channel'}}{'CALLERID'} =
$event{'Callerid'} if defined $event{'Callerid'};
                };

                /newstate/i && do {
                       
$channels{$event{'Channel'}}{'CALLERID'} =
$event{'Callerid'} if defined $event{'Callerid'};
			$channels{$event{'Channel'}}{'DNID'} =
$event{'DNID'} if defined $event{'DNID'};
                };

		/^link$/i && do {
			my $channel = $event{'Channel1'};
			return unless $channels{$channel};
			$channels{$channel}{'DSTCHANNEL'} =
$event{'Channel2'};
			$channels{$channel}{'LINK_START'} = time();
			$channels{$event{'Channel2'}}{'LINK_START'} =
time();
			$channels{$event{'Channel1'}}{'CALL_ID'} =
$event{'Uniqueid1'};
			$channels{$event{'Channel2'}}{'CALL_ID'} =
$event{'Uniqueid1'};
			$channels{$event{'Channel1'}}{'ACCOUNTCODE'} =
$channels{$event{'Channel1'}}{'CALLERID'}
				if !defined
$channels{$event{'Channel1'}}{'ACCOUNTCODE'}; 
			$channels{$event{'Channel2'}}{'ACCOUNTCODE'} =
$channels{$event{'Channel1'}}{'ACCOUNTCODE'};

			syslog('info', 'Link without uniqueid') unless
$channels{$channel}{'UNIQUE'};
			syslog('info', 'Link without channeld') unless
$channel;
			syslog('info', 'Link on undefined channel') unless
$channels{$channel};
			return unless($channel && $channels{$channel} &&
$channels{$channel}{'UNIQUEID'});
		};

		/^unlink$/i && do {
			my $channel = $event{'Channel1'};
			return unless $channels{$channel};
			$channels{$event{'Channel1'}}{'LINK_END'} = time();
			$channels{$event{'Channel2'}}{'LINK_END'} = time();

			syslog('info', 'UnLink without uniqueid') unless
$channels{$channel}{'UNIQUE'};
			syslog('info', 'UnLink without channeld') unless
$channel;
			syslog('info', 'UnLink on undefined channel')
unless $channels{$channel};

			return unless($channel && $channels{$channel} &&
$channels{$channel}{'UNIQUEID'});
		};

		/hangup/i && do {
			my $channel = $event{'Channel'};
			return unless $channels{$channel};
			$channels{$event{'Channel'}}{'CALL_END'} = time();
			$channels{$event{'Channel'}}{'CAUSE'} = 16;
			$channels{$event{'Channel'}}{'CAUSE'} =
$event{'Cause'} if defined $event{'Cause'};

			send_acc(%{$channels{$event{'Channel'}}});
			delete $channels{$event{'Channel'}};
		};

                /shutdown/i && do {
			die 'ast-rad-acc: Asterisk disconnect';	
                };

                /Reload/i && do {
                        load_config();
                };
	}
}

sub send_acc {
	my (%cdr) = @_;

my $r = new Authen::Radius(Host =>
$cdr{'RADIUS_Server'}, Secret =>
$cdr{'RADIUS_Secret'});
if( !defined $r ) {
	syslog('crit', "RADIUS host '$cdr{'RADIUS_Server'}'
ERROR");
	return;
}

$r->clear_attributes();
$r->add_attributes (
        { Name => 'NAS-IP-Address', Value =>
$cdr{'NAS_IP_Address'} },
	{ Name => 'NAS-Port-Name', Value => $cdr{'CHANNEL'}
},
        { Name => 'User-Name', Value =>
$cdr{'ACCOUNTCODE'} },
        { Name => 'Calling-Station-Id', Value =>
$cdr{'CALLERID'} },
        { Name => 'Called-Station-Id', Value =>
$cdr{'DNID'} },
        { Name => 'Acct-Status-Type', Value => 'Stop'
},
	{ Name => 'h323-call-type', Value =>
$cdr{'CALL_TYPE'} },
	{ Name => 'h323-call-origin', Value =>
$cdr{'CALL_ORIGIN'} },
	{ Name => 'h323-setup-time', Value =>
format_date($cdr{'CALL_START'}) },
        { Name => 'h323-connect-time', Value =>
format_date($cdr{'LINK_START'}) },
        { Name => 'h323-disconnect-time', Value =>
format_date($cdr{'LINK_END'}) },
        { Name => 'h323-disconnect-cause', Value =>
$cdr{'CAUSE'} },
        { Name => 'h323-voice-quality', Value => '0'
},
	{ Name => 'Cisco-AVPair', Value =>
"session-protocol=$cdr{'CALL_PROTOCOL'}" },
        { Name => 'Cisco-AVPair', Value =>
"call-id=$cdr{'CALL_ID'}" },
        { Name => 'Acct-Session-Time', Value =>
$cdr{'LINK_END'} - $cdr{'LINK_START'} },
);
$r->add_attributes ( { Name => 'h323-remote-address',
Value => $cdr{'Remoteip'} } ) if defined
$cdr{'Remoteip'};

$r->send_packet (ACCOUNTING_REQUEST) and my $type =
$r->recv_packet;
syslog('crit', "No responce from RADIUS server") if
!defined $type;
}

#
# sample '09:16:05 GMT Sat Dec 11 2004'
#
sub format_date {
	my ($date) = @_;
        return strftime "%H:%M:%S GMT %a %b %e %Y",
gmtime($date);
}

# Signal Handlers
#
sub safe_exit {
   my($sig) = @_;
   syslog('crit', "Caught a SIG$sig - shutting down");
   
   $astman->disconnect if $ast_connected;     
   unlink $lock_file or syslog('crit', "Unable to
create lockfile $lock_file\n");
   closelog();     
   exit;
}

sub load_config {
	my $conf=Config::IniFiles->new(-file =>
"$config_dir/extensions.conf");
	syslog('crit', "Config file error!") if !defined
$conf;

	$rad_serv = $conf->val('globals','RADIUS_Server');
	$rad_sec = $conf->val('globals','RADIUS_Secret');
	$nas_ip = $conf->val('globals','NAS_IP_Address');
	syslog('notice', "extensions.conf loaded");
}



__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 



More information about the asterisk-users mailing list