aboutsummaryrefslogtreecommitdiff
path: root/_misc/snapshot.pl
diff options
context:
space:
mode:
Diffstat (limited to '_misc/snapshot.pl')
-rwxr-xr-x_misc/snapshot.pl538
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;
+}