diff options
Diffstat (limited to '_misc/snapshot.pl')
-rwxr-xr-x | _misc/snapshot.pl | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/_misc/snapshot.pl b/_misc/snapshot.pl new file mode 100755 index 0000000..3cbb9d7 --- /dev/null +++ b/_misc/snapshot.pl @@ -0,0 +1,538 @@ +#!/usr/bin/env perl +#ver 0.11 (C)Cyr +use strict; +use warnings; +use diagnostics; +use IO::Socket; +use Convert::ASN1; + +#use Data::Dumper; +use Carp; +use POSIX; +my $CSTAapdu; +my $socket; +my @devices; +my @calls; + +sub deviceNumber { + my $deviceNumber = shift; + if ( defined $deviceNumber->{deviceNumber} ) { + $deviceNumber = $deviceNumber->{deviceNumber}; + my $deviceType = $deviceNumber & 0xFFFF0000; + if ( $deviceType == 0x1310000 ) { + $deviceType = 'CO'; + } + elsif ( $deviceType == 0x1210000 ) { + $deviceType = 'PS'; + } + elsif ( $deviceType == 0x1110000 ) { + $deviceType = 'EXT'; + } + $deviceNumber = $deviceNumber & 0x0000FFFF; + return $deviceType . sprintf( "%03s", $deviceNumber ); + } + elsif ( defined $deviceNumber->{dialingNumber} ) { + return $deviceNumber->{dialingNumber}; + } +} + +sub localConnectionInfo { + my $localConnectionInfo = shift; + if ( $localConnectionInfo == 0 ) { + return 'null'; + } + elsif ( $localConnectionInfo == 1 ) { + return 'initiated'; + } + elsif ( $localConnectionInfo == 2 ) { + return 'alerting'; + } + elsif ( $localConnectionInfo == 3 ) { + return 'connected'; + } + elsif ( $localConnectionInfo == 4 ) { + return 'hold'; + } + elsif ( $localConnectionInfo == 5 ) { + return 'queued'; + } + elsif ( $localConnectionInfo == 6 ) { + return 'fail'; + } + else { return $localConnectionInfo } +} + +sub decode_msg_header { + my $bin = shift; + my $len = unpack( 'n', $bin ); + return $len; +} + +sub encode_msg_header { + my $len = shift; + die "Message larger than allowed!" unless ( $len <= 240 ); + my $bin = pack( 'n', $len ); + return $bin; +} + +sub convert_to_hex { + my $pdu = $_[0]; + my $hexdata = unpack( 'H*', $pdu ); + $hexdata =~ tr/a-z/A-Z/; + $hexdata =~ s/(..)/$1 /g; + $hexdata =~ s/ $//g; + return $hexdata; +} + +sub send_pdu { + my $pdu = $_[0]; + my $header = encode_msg_header( length($pdu) ); + $socket->write($header); + $socket->write($pdu); + + # my $hexdata = convert_to_hex($pdu); + # print("SENT: [$hexdata]\n"); +} + +sub csta_connect { + my %args = %{ $_[0] }; + open_csta_socket( $args{host}, $args{port} ); + + # A-ASSOCIATE Request + my $pdu = +"602380020780A10706052B0C00815ABE14281206072B0C00821D8148A007A0050303000800"; + $pdu = pack( 'H*', $pdu ); + send_pdu($pdu); + + # A-ASSOCIATE Result + $pdu = receive_stuff(); + my $hexdata = convert_to_hex($pdu); + if ( $hexdata =~ /A2 03 02 01 01/ ) { + print "rejected-permanent\n"; + exit 0; + } + + #SystemStatus Request + $pdu = receive_stuff(); + my $out = $CSTAapdu->decode($pdu); + my $invokeID = $out->{svcRequest}->{invokeID}; + SystemStatusResult($invokeID); +} + +sub open_csta_socket { + my $host = shift; + my $port = shift; + $socket = new IO::Socket::INET( + PeerAddr => $host, + PeerPort => $port, + Blocking => 1, + Proto => 'tcp' + ) || die "Error creating socket: $!\n"; + $socket->autoflush(1); + print("opened a connection to $host on port $port\n"); +} + +sub receive_stuff { + my $header = ''; + my $pdu = ''; + my $nbytes = $socket->sysread( $header, 2 ); + if ( $nbytes == 1 ) { # фрагмент пакета + my $header2; + my $nbytes2 = $socket->sysread( $header2, 1 ); + $header = $header . $header2; + $nbytes = 2; + } + croak "Didn't receive the specified amount of data (2 bytes)!\n" . chr(7) + unless ( $nbytes == 2 ); + my $len = decode_msg_header($header); + $nbytes = $socket->sysread( $pdu, $len ); + if ( $nbytes < $len ) { # фрагмент пакета + my $pdu2; + my $nbytes2 = $socket->sysread( $pdu2, $len - $nbytes ); + $pdu = $pdu . $pdu2; + $nbytes = $nbytes + $nbytes2; + } + croak "Didn't receive the specified amount of data ($len bytes)!\n" . chr(7) + unless ( $nbytes == $len ); + + # my $hexdata = convert_to_hex($pdu); + # print("RECEIVED:[$hexdata]\n"); + return $pdu; +} + +sub GetSystemData { + my $DeviceCategory = shift; + + #EXT=5 + #CO =2 + my $pdu = $CSTAapdu->encode( + { + svcRequest => { + invokeID => 4, + serviceID => 51, + serviceArgs => { + privateData => { + private => { + kmeSystemData => { + getSystemData => { + request => { + deviceList => { + category => { + standardDevice => + $DeviceCategory + } + } + } + } + } + } + } + } + } + } + ); + + #my $pdu = "A11602020602020133300DA40BA009A407A105A0030A010".$DeviceCategory; + #$pdu = pack('H*', $pdu); + send_pdu($pdu); + + # getSystemDataPosAck + $pdu = receive_stuff(); + my $out = $CSTAapdu->decode($pdu); + my $crossRefID = + $out->{svcResult}->{result}->{serviceResult}->{extensions} + ->{privateData}[0]->{private}->{kmeSystemData}->{getSystemDataPosAck}; + my $lastSegment = 0; + + # systemDataLinkedReply + while ( !$lastSegment ) { + $pdu = receive_stuff(); + my $out = $CSTAapdu->decode($pdu); + my $systemDataLinkedReply = + $out->{svcRequest}->{serviceArgs}->{privateData}->{private} + ->{kmeSystemData}->{systemDataLinkedReply}; + if ( defined $systemDataLinkedReply ) { + if ( $systemDataLinkedReply->{crossRefID} cmp $crossRefID ) { next } + $lastSegment = $systemDataLinkedReply->{lastSegment}; + foreach my $KmeDeviceStateEntry ( + @{ $systemDataLinkedReply->{sysData}->{deviceList} } ) + { + if ( $KmeDeviceStateEntry->{status} == 0 ) { + print "device:", $KmeDeviceStateEntry->{number}, "\n"; + push @devices, + ( $KmeDeviceStateEntry->{device}->{deviceIdentifier} + ->{deviceNumber} ); + } + } + } + } +} + +sub SnapshotDeviceRequest { + my $device = shift; + my $pdu = $CSTAapdu->encode( + { + svcRequest => { + invokeID => 9, + serviceID => 74, + serviceArgs => { + snapshotObject => + { deviceIdentifier => { deviceNumber => $device } } + } + } + } + ); + + #$device = sprintf("%08X",$device); + #print("SnapshotDeviceRequest: $device\n"); + #my $pdu = "A11002010202014A300830068104".$device; + #$pdu = pack('H*', $pdu); + send_pdu($pdu); +} + +sub SnapshotDeviceResult { + my $refSnapshotDeviceResult = shift; + my $refsnapshotData = + ( $refSnapshotDeviceResult->{crossRefIDorSnapshotData}->{snapshotData} ); + foreach my $SnapshotDeviceResponseInfo ( @{$refsnapshotData} ) { + my $callID = + $SnapshotDeviceResponseInfo->{connectionIdentifier}->{both}->{callID}; + my $deviceID = deviceNumber( + $SnapshotDeviceResponseInfo->{connectionIdentifier}->{both} + ->{deviceID}->{staticID}->{deviceIdentifier} ); + foreach my $LocalConnectionState ( + @{ + $SnapshotDeviceResponseInfo->{localCallState} + ->{compoundCallState} + } + ) + { + my $ConnectionState = localConnectionInfo($LocalConnectionState); + push @calls, [ $callID, $deviceID, $ConnectionState ]; + } + + } +} + +sub SystemStatusResult { + my $invokeID = shift; + my $pdu = $CSTAapdu->encode( + { + svcResult => { + invokeID => $invokeID, + result => { serviceID => 211, serviceResult => { noData => 1 } } + } + } + ); + send_pdu($pdu); # send SystemStatus Result +} + +# parse ASN.1 desciptions +my $asn = Convert::ASN1->new; + +#$asn->configure(tagdefault=>'EXPLICIT'); +$asn->prepare(<<ASN1) or die "prepare: ", $asn->error; +CSTAapdu ::= CHOICE { + svcRequest ROIVapdu, + svcResult RORSapdu +-- svcError ROERapdu, +-- svcReject RORJapdu +} +ROIVapdu ::= [1] IMPLICIT SEQUENCE { + invokeID INTEGER, + serviceID INTEGER, + serviceArgs ANY DEFINED BY serviceID +} +RORSapdu ::= [2] IMPLICIT SEQUENCE { + invokeID INTEGER, + result SEQUENCE { + serviceID INTEGER, + serviceResult ANY DEFINED BY serviceID OPTIONAL + } +} +EscapeArgument ::= SEQUENCE +{ --escapeRegisterID EscapeRegisterID OPTIONAL, + --security CSTASecurityData OPTIONAL, + privateData CSTAPrivateData } + +CSTAPrivateData ::= CHOICE +{ string OCTET STRING, + private KmeSpecificPrivateData +} +KmeSpecificPrivateData ::= CHOICE +{ kmeSystemData [4] KmeSystemData +} +KmeSystemData ::= CHOICE +{ getSystemData [0] KmeGetSystemData, + systemDataLinkedReply [3] EXPLICIT KmeSystemDataLinkedReply, + getSystemDataPosAck [4] EXPLICIT KmeGetSystemDataPosAck +} +KmeGetSystemData ::= CHOICE +{ request KmeGetSystemDataReq --! +--result KmeGetSystemDataRsp +} +KmeGetSystemDataReq ::= CHOICE +{ +deviceList [4] KmeRequestedDevice --! +} +KmeRequestedDevice ::= CHOICE -- for GetSystemData.deviceList +{ --device [0] DeviceID, + category [1] KmeDeviceCategory} --! + +KmeDeviceCategory ::= CHOICE +{ standardDevice [0] EXPLICIT DeviceCategory--! + -- kmeDevice [1] KmeOtherDevice +} +DeviceCategory ::= ENUMERATED +{ acd (0), + group (1), + networkInterface (2), --! + park (3), + routeingDevice (4), + station (5), --! + voiceUnit (6), + other (7) +} +KmeSystemDataLinkedReply ::= SEQUENCE +{ crossRefID [0] EXPLICIT ServiceCrossRefID, + segmentID [1] EXPLICIT INTEGER, + lastSegment [2] EXPLICIT BOOLEAN, + sysData [3] EXPLICIT KmeGetSystemDataRsp OPTIONAL +} +ServiceCrossRefID ::= OCTET STRING + +KmeGetSystemDataPosAck ::= ServiceCrossRefID + +KmeGetSystemDataRsp ::= SEQUENCE +{ deviceList [38] EXPLICIT KmeDeviceStateList OPTIONAL +} +KmeDeviceStateList ::= SEQUENCE OF KmeDeviceStateEntry + +KmeDeviceStateEntry ::= SEQUENCE +{ device DeviceID, + number IA5String OPTIONAL, -- Ext No, CO No, Park Area No. + status KmeDeviceState +} +KmeDeviceState ::= ENUMERATED +{ ins (0), + ous (1) +} +EscapeResult ::= CHOICE +{ extensions CSTACommonArguments, + noData NULL +} +CSTACommonArguments ::= [APPLICATION 30] IMPLICIT SEQUENCE +{ privateData [1] IMPLICIT SEQUENCE OF CSTAPrivateData OPTIONAL } + +CSTAPrivateData ::= CHOICE +{ string OCTET STRING, + private KmeSpecificPrivateData +} + +--snapshotDevice OPERATION ::= +--{ ARGUMENT SnapshotDeviceArgument, +-- RESULT SnapshotDeviceResult +-- ERRORS {universalFailure} +-- CODE local: 74} + +SnapshotDeviceArgument ::= SEQUENCE +{ snapshotObject DeviceID} + +SnapshotDeviceResult ::= SEQUENCE +{ crossRefIDorSnapshotData + CHOICE + { serviceCrossRefID ServiceCrossRefID, + snapshotData SnapshotDeviceData + } +} + +ServiceCrossRefID ::= OCTET STRING + +SnapshotDeviceData ::= [APPLICATION 22] IMPLICIT SEQUENCE OF SnapshotDeviceResponseInfo + +SnapshotDeviceResponseInfo ::= SEQUENCE +{ connectionIdentifier ConnectionID, + localCallState CallState} + +ConnectionID ::= [APPLICATION 11] CHOICE +{ + deviceID [1] LocalDeviceID, + both SEQUENCE + { callID [0] IMPLICIT CallID, + deviceID [1] LocalDeviceID + } +} + +CallID ::= OCTET STRING + +LocalDeviceID ::= CHOICE +{ staticID DeviceID} + +DeviceID ::= SEQUENCE +{ deviceIdentifier CHOICE + { dialingNumber [0] IMPLICIT NumberDigits, + deviceNumber [1] IMPLICIT DeviceNumber, + other [6] IMPLICIT OtherPlan + } +} +OtherPlan ::= OCTET STRING + +NumberDigits ::= IA5String + +DeviceNumber ::= INTEGER + +CallState ::= CHOICE +{ compoundCallState [0] IMPLICIT CompoundCallState} + +CompoundCallState ::= SEQUENCE OF LocalConnectionState + +LocalConnectionState ::= [APPLICATION 14] IMPLICIT ENUMERATED +{ null (0), + initiated (1), + alerting (2), + connected (3), + hold (4), + queued (5), + fail (6) +} +systemStatus ::= CHOICE +{ ARGUMENT SystemStatusArg, + RESULT SystemStatusRes +-- ERRORS {universalFailure} +-- CODE local: 211 +} +SystemStatusArg ::= SEQUENCE +{ systemStatus SystemStatus} + +SystemStatusRes ::= CHOICE +{ noData NULL} + +SystemStatus ::= ENUMERATED +{ normal (2), + messageLost (3), + overloadReached (6) +} +ASN1 +my %serviceArgs = ( + 51 => 'EscapeArgument', + 74 => 'SnapshotDeviceArgument', + 211 => 'SystemStatusArg' +); +foreach ( keys %serviceArgs ) { + $asn->registertype( 'serviceArgs', $_, $asn->find( $serviceArgs{$_} ) ); +} +my %serviceResults = ( + 51 => 'EscapeResult', + 74 => 'SnapshotDeviceResult', + 211 => 'SystemStatusRes' +); +foreach ( keys %serviceResults ) { + $asn->registertype( 'serviceResult', $_, + $asn->find( $serviceResults{$_} ) ); +} +$CSTAapdu = $asn->find('CSTAapdu'); +csta_connect( { 'host' => '192.168.240.20', 'port' => 33333 } ); +GetSystemData(2); +GetSystemData(5); +my $maxCO = 0; +while (1) { + foreach my $number (@devices) { + SnapshotDeviceRequest($number); + } + undef @calls; + my $alldevices = $#devices + 1; + while ($alldevices) { + my $pdu = receive_stuff(); + my $out = $CSTAapdu->decode($pdu); + if ( defined $out->{svcRequest} ) { + my $serviceID = $out->{svcRequest}->{serviceID}; + my $invokeID = $out->{svcRequest}->{invokeID}; + if ( $serviceID == 211 ) { # if SystemStatus Request + SystemStatusResult($invokeID); + } + } + elsif ( defined $out->{svcResult} ) { + my $serviceResult = $out->{svcResult}->{result}->{serviceResult}; + my $serviceID = $out->{svcResult}->{result}->{serviceID}; + if ( $serviceID == 74 ) { + SnapshotDeviceResult($serviceResult); + $alldevices = $alldevices - 1; + } + } + } + my $CO = 0; + for (@calls) { + $CO++ if $_->[1] =~ /^CO/; + } + if ( $maxCO < $CO ) { + $maxCO = $CO; + print chr(7); + } + #system('CLS'); # for windows, 'clear' for linux + print strftime( "%H:%M:%S ", localtime ), "maxCO:", $maxCO, " CO:", $CO, + "\n"; + print "callID: deviceID: CallState:\n"; + printf( "%-8s%-10s%-10s\n", $_->[0], $_->[1], $_->[2] ) + for sort { $a->[0] cmp $b->[0] } @calls; + sleep 1; +} |