File Coverage

blib/lib/Net/TL1UDP.pm
Criterion Covered Total %
statement 15 108 13.8
branch 1 68 1.4
condition 0 30 0.0
subroutine 6 20 30.0
pod 13 13 100.0
total 35 239 14.6


line stmt bran cond sub pod time code
1             package Net::TL1UDP;
2            
3 1     1   47142 use strict;
  1         2  
  1         22  
4 1     1   4 use warnings;
  1         1  
  1         20  
5 1     1   466 use Socket;
  1         2584  
  1         331  
6            
7             BEGIN {
8 1     1   6 require Exporter;
9             # Set the version for version checking
10 1         2 our $VERSION = 1.02;
11             # Inherit from Exporter to export functions and variables
12 1         16 our @ISA = qw(Exporter);
13             # Functions and variables which are exported by default
14 1         1043 our @EXPORT = qw(
15             node_login
16             tl1_cmd
17             tl1_cmdf
18             debug_file
19             close_debug
20             retrieve_sid
21             retrieve_ctag
22             command_timeout
23             timeout_counter
24             inhibit_messages
25             sarb_retry_limit
26             sarb_retry_delay
27             logoff
28             );
29             }
30              
31             my $currentCTAG = 0; # Initialise the current CTAG value
32             my $sid = ''; # Initialise the SID value
33             my $timeout = 60; # Initialise the response timeout value
34             my $udpPort = 13001; # Initialise UDP port number
35             my $debug = 0; # Initialise the debug status
36             my $deviceIP = ''; # Initialise the device IP address
37             my $to_counter = 0; # Initialise the timeout counter value
38             my $inhibit_msgs = 1; # Initialise the inhibit messages status
39             my $loginOK = 0; # Initialise the logged in state
40             my $sarb_retries = 0; # Initialise the SARB retry limit
41             my $sarb_delay = 0; # Initialise the SARB retry delay value
42              
43             # Function to configure the debug file
44 0           sub debug_file {
45 0     0 1   my $filename = shift;
46 0 0         open (DEBUG, ">$filename") or die "File Error: $!";
47 0           $debug = 1;
48 1 50   1   22 END { close (DEBUG) if (defined (fileno (DEBUG))); }
49             }
50              
51             # Function to close the debug file before the script completes
52             sub close_debug {
53 0     0 1   $debug = 0;
54 0 0         close (DEBUG) if (defined (fileno (DEBUG)));
55             }
56              
57             # Function to retrieve the SID
58 0     0 1   sub retrieve_sid { return $sid; }
59              
60             # Function to return the current CTAG value
61 0     0 1   sub retrieve_ctag { return $currentCTAG; }
62              
63             # Function to retrieve or set the timeout value
64             sub command_timeout {
65             # If a value has been provided, set the timeout variable
66 0 0 0 0 1   $timeout = $_[0] if (scalar(@_) == 1 && $_[0] =~ /^\d+$/ && $_[0] > 0);
      0        
67 0           return $timeout;
68             }
69              
70             # Function to retrieve or set the timeout counter value
71             sub timeout_counter {
72             # If a value has been provided, set the counter variable
73 0 0 0 0 1   $to_counter = $_[0] if (scalar(@_) == 1 && $_[0] =~ /^\d+$/ && $_[0] >= 0);
      0        
74 0           return $to_counter;
75             }
76              
77             # Function to retrieve or set the SARB retry limit value
78             sub sarb_retry_limit {
79             # If a value has been provided, set the limit variable
80 0 0 0 0 1   $sarb_retries = $_[0] if (scalar(@_) == 1 && $_[0] =~ /^\d+$/);
81 0           return $sarb_retries;
82             }
83              
84             # Function to retrieve or set the SARB retry delay value
85             sub sarb_retry_delay {
86             # If a value has been provided, set the retry variable
87 0 0 0 0 1   $sarb_delay = $_[0] if (scalar(@_) == 1 && $_[0] =~ /^\d+$/);
88 0           return $sarb_delay;
89             }
90              
91             # Function to retrieve or set the inhibit messages value
92             sub inhibit_messages {
93             # If a value has been provided, set the inhibit messages value and,
94             # if logged into the node, send the allow or inhibit messages command
95 0 0 0 0 1   if (scalar(@_) == 1 && $_[0] =~ /^[01]$/) {
96 0           $inhibit_msgs = $_[0];
97 0 0         if ($loginOK) {
98 0 0         &tl1_cmd("INH-MSG-ALL::ALL;") if ($inhibit_msgs == 1);
99 0 0         &tl1_cmd("ALW-MSG-ALL::ALL;") if ($inhibit_msgs == 0);
100             }
101             }
102 0           return $inhibit_msgs;
103             }
104              
105             # Function to log into the device
106             sub node_login {
107 0 0 0 0 1   if (scalar(@_) == 3 && $_[0] =~ /^\w\S+[:]?\d*$/) {
108 0           my ($deviceInfo, $username, $password) = @_;
109 0 0         if ($deviceInfo =~ /:/) { ($deviceIP, $udpPort) = split (/:/, $deviceInfo); }
  0            
110 0           else { $deviceIP = $deviceInfo; }
111 0           my $login = &tl1_cmd("ACT-USER::${username}:::${password};");
112 0 0 0       if ($login && $login =~ /Logged On/i) {
113 0 0         if ($login =~ /\s+\w+\s+\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d/) {
114 0           ($sid) = $login =~ /\s+(\w+)\s\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d/;
115 0 0         &tl1_cmd("INH-MSG-ALL::ALL;") if ($inhibit_msgs);
116             }
117 0           $loginOK = 1;
118             }
119 0           else { &tl1_cmd("LOGOFF"); }
120             }
121 0           return $loginOK;
122             }
123              
124             # Function to log off of the device
125             sub logoff {
126 0 0   0 1   &tl1_cmd("ALW-MSG-ALL::ALL;") if ($inhibit_msgs);
127 0           &tl1_cmd("LOGOFF");
128             }
129              
130             # Function to send a command to, and receive the data from, the socket
131             sub tl1_cmd {
132 0 0   0 1   if ($deviceIP) {
133             # Get the command string
134 0           my $command_string = shift;
135             # Remove the semicolon at the end of the command if it exists
136 0 0         chop $command_string if (substr($command_string, -1) eq ';');
137             # Assign the command to an array
138 0           my @command = split(/:/, $command_string);
139             # Ensure the array contains at least four elements
140 0           push (@command, '') while (scalar(@command) < 4);
141             # Initialise the SARB retry variable
142 0           my $retries_remaining = $sarb_retries + 1;
143 0           while ($retries_remaining) {
144             # Increment the CTAG value
145 0           $currentCTAG++;
146             # Replace/add the current CTAG in/to the TL-1 command
147 0           $command[3] = $currentCTAG;
148 0           $command_string = join(':', @command);
149             # Add a semicolon to the end of the command
150 0           $command_string .= ';';
151             # Initialise data
152 0           my $data = ''; my $msg = '';
  0            
153 0           my $packed_ip = inet_aton($deviceIP);
154             # Print the Shelf IP and the TL-1 command in the debug file
155 0 0         print DEBUG "\n\n>>>>> DEVICE = $deviceIP\tCOMMAND = $command_string <<<<<\n\n" if ($debug);
156 0           send(TL1SOCKET, $command_string, 0, sockaddr_in($udpPort, $packed_ip));
157 0           eval {
158             # Capture alarm signal (to detect timeout)
159 0     0     local $SIG{ALRM} = sub { die "timed_out\n" };
  0            
160             # If the shelf does not respond in timeout secs, break out of the loop
161 0           alarm ($timeout);
162             # 5000 is the MAXIMUM data size
163 0           while (my $src = recv(TL1SOCKET, $msg, 5000, 0)) {
164 0           my ($srcPort, $srcAddr) = sockaddr_in($src);
165             # Print ALL received data in the debug file
166 0 0         print DEBUG $msg if ($debug);
167             # Only add data from correct IP address and port to $data
168 0 0 0       if ($srcAddr eq $packed_ip && $srcPort == $udpPort) {
169 0           $data .= $msg;
170             # Break from the loop when a proper response and a ";"
171             # (on a line by itself) is received
172 0 0         if ($msg =~ /^;$/m) {
173 0 0         if ($data =~ /$currentCTAG (COMPLD|DENY).+;/s) { last; }
  0            
174 0           else { $data = ""; }
175             }
176             # Reset the alarm signal
177 0           alarm ($timeout);
178             }
179             # Flag unsolicited responses in the debug file (info only)
180 0 0         else { print DEBUG "\n --- Unsolicited Response ---\n" if ($debug); }
181             }
182 0           alarm (0);
183             };
184             # If the timeout expired waiting for a response
185 0 0         if ($@) {
    0          
186 0 0         print DEBUG "\n\n***** Timeout expired *****\n" if ($debug);
187             # Increment the timeout counter
188 0           $to_counter++;
189             # Set the retries to 0
190 0           $retries_remaining = 0;
191             # Return 0
192 0           return 0;
193             }
194             # Else if there was a "Status, All Resources Busy" response
195             elsif ($data =~ /DENY.+SARB/s) {
196             # Decrement the remaining retries counter
197 0           $retries_remaining--;
198             # If the retry limit has not been reached, flag it in the debug file
199             # and, if there is retry delay, sleep for that time period
200 0 0         if ($retries_remaining) {
201 0 0         print DEBUG "\n\n***** SARB Retry - $retries_remaining remaining (waiting $sarb_delay seconds) *****\n" if ($debug);
202 0 0         sleep ($sarb_delay) if ($sarb_delay);
203             }
204             # Otherwise return the data
205             else {
206 0           return $data;
207             }
208             }
209             # Otherwise, set the retries to 0 and return the data
210             else {
211 0           $retries_remaining = 0;
212 0           return $data;
213             }
214             }
215             }
216 0           else { return 0; }
217             }
218              
219             # Function to send a command to, and receive formatted data from, the socket
220             sub tl1_cmdf {
221 0     0 1   my $raw_data = &tl1_cmd(shift);
222 0 0         if ($raw_data) {
223 0 0         if ($raw_data =~ / $currentCTAG DENY.+;/s) {
224 0           return $raw_data;
225             }
226             else {
227 0           my @records = $raw_data =~ /\s+["](.+?[^\\])["]/sg;
228 0           for (my $i = 0; $i < scalar(@records); $i++) {
229             # Remove two or more spaces
230 0           $records[$i] =~ s/\s{2,}//g;
231             }
232 0 0         if (scalar(@records)) { return join ("\n", @records); }
  0            
233 0           else { return "COMPLD"; }
234             }
235             }
236 0           else { return 0; }
237             }
238              
239             # Create a UDP socket (TL1SOCKET) to communicate with the device
240             socket(TL1SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp"))
241             or die "Socket Error: $!";
242            
243 1     1   1096 END { close (TL1SOCKET); }
244              
245             1;
246             __END__