File Coverage

blib/lib/Control/CLI.pm
Criterion Covered Total %
statement 81 1559 5.2
branch 43 1244 3.4
condition 4 288 1.3
subroutine 17 118 14.4
pod 92 92 100.0
total 237 3301 7.1


line stmt bran cond sub pod time code
1             package Control::CLI;
2              
3 1     1   65017 use strict;
  1         2  
  1         24  
4 1     1   4 use warnings;
  1         2  
  1         21  
5 1     1   4 use Exporter qw( import );
  1         1  
  1         37  
6 1     1   5 use Carp;
  1         1  
  1         41  
7 1     1   423 use Term::ReadKey;
  1         1647  
  1         59  
8 1     1   453 use Time::HiRes qw( time sleep );
  1         1126  
  1         5  
9 1     1   185 use IO::Handle;
  1         2  
  1         41  
10 1     1   399 use IO::Socket::INET;
  1         12084  
  1         6  
11 1     1   372 use Errno qw( EINPROGRESS EWOULDBLOCK );
  1         2  
  1         19067  
12              
13             my $Package = __PACKAGE__;
14             our $VERSION = '2.11';
15             our %EXPORT_TAGS = (
16             use => [qw(useTelnet useSsh useSerial useIPv6)],
17             prompt => [qw(promptClear promptHide promptCredential)],
18             args => [qw(parseMethodArgs suppressMethodArgs)],
19             coderef => [qw(validCodeRef callCodeRef)],
20             _rest => [qw(passphraseRequired parse_errmode stripLastLine poll)],
21             );
22             push @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} foreach keys %EXPORT_TAGS;
23             Exporter::export_ok_tags('all');
24              
25             ########################################### Global Class Variables ###########################################
26              
27             my $PollTimer = 100; # Some connection types require a polling loop; this is the loop sleep timer in ms
28             my $ComPortReadBuffer = 4096; # Size of serial port read buffers
29             my $ComReadInterval = 100; # Timeout between single character reads
30             my $ComBreakDuration = 300; # Number of milliseconds the break signal is held for
31             my $ChangeBaudDelay = 100; # Number of milliseconds to sleep between tearing down and restarting serial port connection
32             my $VT100_QueryDeviceStatus = "\e[5n"; # With report_query_status, if received from host
33             my $VT100_ReportDeviceOk = "\e[0n"; # .. sent to host, with report_query_status
34              
35             my %Default = ( # Hash of default object settings which can be modified on a per object basis
36             timeout => 10, # Default Timeout value in secs
37             connection_timeout => undef, # Default Connection Timeout value in secs
38             connection_timeout_nb => 20, # If above is undefined, still need to set a value for connections in non-blocking mode
39             blocking => 1, # Default blocking mode
40             return_reference => 0, # Whether methods return data (0) or hard referece to it (1)
41             read_attempts => 5, # Empty reads to wait in readwait() before returning
42             readwait_timer => 100, # Polling loop timer for readwait() in millisecs, for further input
43             data_with_error => 0, # Readwait() behaviour in case of read error following some data read
44             prompt_credentials => 0, # Interactively prompt for credentials (1) or not (0)
45             tcp_port => {
46             SSH => 22, # Default TCP port number for SSH
47             TELNET => 23, # Default TCP port number for TELNET
48             },
49             read_block_size => {
50             SSH => 4096, # Default Read Block Size for SSH
51             SERIAL_WIN32 => 1024, # Default Read Block Size for Win32::SerialPort
52             SERIAL_DEVICE => 255, # Default Read Block Size for Device::SerialPort
53             },
54             baudrate => 9600, # Default baud rate used when connecting via Serial port
55             handshake => 'none', # Default handshake used when connecting via Serial port
56             parity => 'none', # Default parity used when connecting via Serial port
57             databits => 8, # Default data bits used when connecting via Serial port
58             stopbits => 1, # Default stop bits used when connecting via Serial port
59             ors => "\n", # Default Output Record Separator used by print() & cmd()
60             errmode => 'croak', # Default error mode; can be: die/croak/return/coderef/arrayref
61             errmsg_format => 'default', # Default error message format; can be: terse/default/verbose
62             poll_obj_complete => 'all', # Default mode for poll() method
63             poll_obj_error => 'ignore', # Default error mode for poll() method
64             report_query_status => 0, # Default setting of report_query_status for class object
65             prompt => '.*[\?\$%#>](?:\e\[00?m)?\s?$', # Default prompt used in login() and cmd() methods
66             username_prompt => '(?i:user(?: ?name)?|login)[: ]+$', # Default username prompt used in login() method
67             password_prompt => '(?i)(?
68             terminal_type => 'vt100', # Default terminal type (for SSH)
69             window_size => [], # Default terminal window size [width, height]
70             debug => 0, # Default debug level; 0 = disabled
71             );
72              
73             our @ConstructorArgs = ( 'use', 'timeout', 'errmode', 'return_reference', 'prompt', 'username_prompt', 'password_prompt',
74             'input_log', 'output_log', 'dump_log', 'blocking', 'debug', 'prompt_credentials', 'read_attempts',
75             'readwait_timer', 'read_block_size', 'output_record_separator', 'connection_timeout', 'data_with_error',
76             'terminal_type', 'window_size', 'errmsg_format', 'report_query_status',
77             );
78              
79             # Debug levels can be set using the debug() method or via debug argument to new() constructor
80             # Debug levels defined:
81             # 0 : No debugging
82             # bit 1 : Debugging activated for for polling methods + readwait() and enables carping on Win32/Device::SerialPort
83             # This level also resets Win32/Device::SerialPort constructor $quiet flag only when supplied in Control::CLI::new()
84             # bit 2 : Debugging is activated on underlying Net::SSH2 and Win32::SerialPort / Device::SerialPort
85             # There is no actual debugging for Net::Telnet
86              
87              
88             my ($UseTelnet, $UseSSH, $UseSerial, $UseSocketIP);
89              
90              
91             ############################################## Required modules ##############################################
92              
93             if (eval {require Net::Telnet}) { # Make Net::Telnet optional
94             import Net::Telnet qw( TELNET_IAC TELNET_SB TELNET_SE TELNET_WILL TELOPT_TTYPE TELOPT_NAWS );
95             $UseTelnet = 1
96             }
97             $UseSSH = 1 if eval {require Net::SSH2}; # Make Net::SSH2 optional
98              
99             if ($^O eq 'MSWin32') {
100             $UseSerial = 1 if eval {require Win32::SerialPort}; # Win32::SerialPort optional on Windows
101             }
102             else {
103             $UseSerial = 1 if eval {require Device::SerialPort}; # Device::SerialPort optional on Unix
104             }
105             croak "$Package: no available module installed to operate on" unless $UseTelnet || $UseSSH || $UseSerial;
106              
107             $UseSocketIP = 1 if eval { require IO::Socket::IP }; # Provides IPv4 and IPv6 support
108              
109              
110             ################################################ Class Methods ###############################################
111              
112             sub useTelnet {
113 3     3 1 1503 return $UseTelnet;
114             }
115              
116             sub useSsh {
117 2     2 1 547 return $UseSSH;
118             }
119              
120             sub useSerial {
121 2     2 1 572 return $UseSerial;
122             }
123              
124             sub useIPv6 {
125 1     1 1 5 return $UseSocketIP;
126             }
127              
128             sub promptClear { # Interactively prompt for a username, in clear text
129 0     0 1 0 my $username = shift;
130 0         0 my $input;
131 0         0 print "Enter $username: ";
132 0         0 ReadMode('normal');
133 0         0 chomp($input = ReadLine(0));
134 0         0 ReadMode('restore');
135 0         0 return $input;
136             }
137              
138             sub promptHide { # Interactively prompt for a password, input is hidden
139 0     0 1 0 my $password = shift;
140 0         0 my $input;
141 0         0 print "Enter $password: ";
142 0         0 ReadMode('noecho');
143 0         0 chomp($input = ReadLine(0));
144 0         0 ReadMode('restore');
145 0         0 print "\n";
146 0         0 return $input;
147             }
148              
149             sub passphraseRequired { # Inspects a private key to see if it requires a passphrase to be used
150 0     0 1 0 my $privateKey = shift;
151 0         0 my $passphraseRequired = 0;
152              
153             # Open the private key to see if passphrase required.. Net::SSH2 does not do this for us..
154 0 0       0 open(my $key, '<', $privateKey) or return;
155 0         0 while (<$key>) {
156 0 0       0 /ENCRYPTED/ && do { # Keys in OpenSSH format and passphrase encrypted
157 0         0 $passphraseRequired = 1;
158 0         0 last;
159             };
160             }
161 0         0 close $key;
162 0         0 return $passphraseRequired;
163             }
164              
165              
166             sub parseMethodArgs { # Parse arguments fed into a method against accepted arguments; also set them to lower case
167 1     1 1 2 my ($pkgsub, $argsRef, $validArgsRef, $noCarp) = @_;
168 1 50       3 return unless @$argsRef;
169 1         2 my ($even_lc, @argsIn, @argsOut, %validArgs);
170 1 100 66     3 @argsIn = map {++$even_lc%2 && defined $_ ? lc : $_} @$argsRef; # Sets to lowercase the hash keys only
  4         30  
171 1         3 foreach my $key (@$validArgsRef) { $validArgs{lc $key} = 1 }
  23         42  
172 1         5 for (my $i = 0; $i < $#argsIn; $i += 2) {
173 2 50       5 return unless defined $argsIn[$i];
174 2 50       5 if ($validArgs{$argsIn[$i]}) {
175 2         5 push @argsOut, $argsIn[$i], $argsIn[$i + 1];
176 2         5 next;
177             }
178 0 0       0 carp "$pkgsub: Invalid argument \"$argsIn[$i]\"" unless $noCarp;
179             }
180 1         6 return @argsOut;
181             }
182              
183              
184             sub suppressMethodArgs { # Parse arguments and remove the ones listed
185 0     0 1 0 my ($argsRef, $suppressArgsRef) = @_;
186 0 0       0 return unless @$argsRef;
187 0         0 my ($even_lc, @argsIn, @argsOut, %suppressArgs);
188 0 0       0 @argsIn = map {++$even_lc%2 ? lc : $_} @$argsRef; # Sets to lowercase the hash keys only
  0         0  
189 0         0 foreach my $key (@$suppressArgsRef) { $suppressArgs{lc $key} = 1 }
  0         0  
190 0         0 for (my $i = 0; $i < $#argsIn; $i += 2) {
191 0 0       0 next if $suppressArgs{$argsIn[$i]};
192 0         0 push @argsOut, $argsIn[$i], $argsIn[$i + 1];
193             }
194 0         0 return @argsOut;
195             }
196              
197              
198             sub parse_errmode { # Parse a new value for the error mode and return it if valid or undef otherwise
199 2     2 1 4 my ($pkgsub, $mode) = @_;
200              
201 2 50       21 if (!defined $mode) {
    50          
    50          
    50          
    0          
202 0         0 carp "$pkgsub: Errmode undefined argument; ignoring";
203 0         0 $mode = undef;
204             }
205 0         0 elsif ($mode =~ /^\s*die\s*$/i) { $mode = 'die' }
206 0         0 elsif ($mode =~ /^\s*croak\s*$/i) { $mode = 'croak' }
207 2         3 elsif ($mode =~ /^\s*return\s*$/i) { $mode = 'return' }
208             elsif ( ref($mode) ) {
209 0 0       0 unless ( validCodeRef($mode) ) {
210 0         0 carp "$pkgsub: Errmode first item of array ref must be a code ref; ignoring";
211 0         0 $mode = undef;
212             }
213             }
214             else {
215 0         0 carp "$pkgsub: Errmode invalid argument '$mode'; ignoring";
216 0         0 $mode = undef;
217             }
218 2         6 return $mode;
219             }
220              
221              
222             sub stripLastLine { # Remove incomplete (not ending with \n) last line, if any from the string ref provided
223 0     0 1 0 my $dataRef = shift;
224 0         0 $$dataRef =~ s/(.*)\z//;
225 0 0       0 return defined $1 ? $1 : '';
226             }
227              
228              
229             sub validCodeRef { # Checks validity of code reference / array ref where 1st element is a code ref
230 0     0 1 0 my $codeRef = shift;
231 0 0       0 return 1 if ref($codeRef) eq 'CODE';
232 0 0 0     0 return 1 if ref($codeRef) eq 'ARRAY' && ref($codeRef->[0]) eq 'CODE';
233 0         0 return;
234             }
235              
236              
237             sub callCodeRef { # Executes a codeRef either as direct codeRef or array ref where 1st element is a code ref
238 0     0 1 0 my $callRef = shift;
239 0 0       0 return &$callRef(@_) if ref($callRef) eq 'CODE';
240             # Else ARRAY ref where 1st element is the codeRef
241 0         0 my @callArgs = @$callRef; # Copy the array before shifting it below, as we need to preserve it
242 0         0 my $codeRef = shift(@callArgs);
243 0         0 return &$codeRef(@callArgs, @_);
244             }
245              
246              
247             sub promptCredential { # Automatically handles credential prompt for code reference or local prompting
248 0     0 1 0 my ($mode, $privacy, $credential) = @_;
249 0 0       0 return callCodeRef($mode, $privacy, $credential) if validCodeRef($mode);
250 0 0       0 return promptClear($credential) if lc($privacy) eq 'clear';
251 0 0       0 return promptHide($credential) if lc($privacy) eq 'hide';
252 0         0 return;
253             }
254              
255              
256             ############################################# Constructors/Destructors #######################################
257              
258             sub new {
259 1     1 1 10 my $pkgsub = "${Package}::new";
260 1         3 my $invocant = shift;
261 1   33     7 my $class = ref($invocant) || $invocant;
262 1         2 my (%args, $errmode, $msgFormat, $connectionType, $parent, $comPort, $debug);
263 1 50       4 if (@_ == 1) { # Method invoked with just the connection type argument
264 0         0 $connectionType = shift;
265             }
266             else {
267 1         5 %args = parseMethodArgs($pkgsub, \@_, \@ConstructorArgs);
268 1         2 $connectionType = $args{use};
269             }
270 1 50       4 $debug = defined $args{debug} ? $args{debug} : $Default{debug};
271 1 50       5 $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : $Default{errmode};
272 1 50       11 $msgFormat = defined $args{errmsg_format} ? $args{errmsg_format} : $Default{errmsg_format};
273 1 50       4 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: Connection type must be specified in constructor", $msgFormat) unless defined $connectionType;
274              
275 1 50       5 if ($connectionType =~ /^TELNET$/i) {
    0          
276 1 50       2 croak "$pkgsub: Module 'Net::Telnet' required for telnet access" unless $UseTelnet;
277 1         52 @CLI::ISA = qw(Net::Telnet);
278 1         8 $parent = Net::Telnet->new();
279             # Set up callbacks for telnet options
280 1         252 $parent->option_callback(\&_telnet_opt_callback);
281 1         19 $parent->suboption_callback(\&_telnet_subopt_callback);
282 1         13 $connectionType = 'TELNET';
283             }
284             elsif ($connectionType =~ /^SSH$/i) {
285 0 0       0 croak "$pkgsub: Module 'Net::SSH2' required for ssh access" unless $UseSSH;
286 0         0 @CLI::ISA = qw(Net::SSH2);
287 0         0 $parent = Net::SSH2->new();
288 0         0 $connectionType = 'SSH';
289             }
290             else {
291 0 0       0 if ($^O eq 'MSWin32') {
292 0 0       0 croak "$pkgsub: Module 'Win32::SerialPort' required for serial access" unless $UseSerial;
293 0         0 @CLI::ISA = qw(Win32::SerialPort);
294 0         0 Win32::SerialPort->set_test_mode_active(!($debug & 1)); # Suppress carping except if debug bit1 set
295 0 0       0 Win32::SerialPort::debug($debug & 2 ? 'ON' : 'OFF');
296 0 0       0 $parent = Win32::SerialPort->new($connectionType, !($debug & 1))
297             or return _error(__FILE__, __LINE__, $errmode, "$pkgsub: Cannot open serial port '$connectionType'", $msgFormat);
298             }
299             else {
300 0 0       0 croak "$pkgsub: Module 'Device::SerialPort' required for serial access" unless $UseSerial;
301 0         0 @CLI::ISA = qw(Device::SerialPort);
302 0         0 Device::SerialPort->set_test_mode_active(!($debug & 1)); # Suppress carping except if debug bit1 set
303 0 0       0 Device::SerialPort::debug($debug & 2 ? 'ON' : 'OFF');
304 0 0       0 $parent = Device::SerialPort->new($connectionType, !($debug & 1))
305             or return _error(__FILE__, __LINE__, $errmode, "$pkgsub: Cannot open serial port '$connectionType'", $msgFormat);
306             }
307 0         0 $comPort = $connectionType;
308 0         0 $connectionType = 'SERIAL';
309             }
310             my $self = {
311             # Lower Case ones can be set by user; Upper case ones are set internaly in the class
312             TYPE => $connectionType,
313             PARENT => $parent,
314             SOCKET => undef,
315             SSHCHANNEL => undef,
316             SSHAUTH => undef,
317             BUFFER => '', # Always defined; greater than 0 length if in use
318             QUERYBUFFER => '', # Always defined; greater than 0 length if in use
319             COMPORT => $comPort,
320             HOST => undef,
321             TCPPORT => undef,
322             HANDSHAKE => undef,
323             BAUDRATE => undef,
324             PARITY => undef,
325             DATABITS => undef,
326             STOPBITS => undef,
327             INPUTLOGFH => undef,
328             OUTPUTLOGFH => undef,
329             DUMPLOGFH => undef,
330             USERNAME => undef,
331             PASSWORD => undef,
332             PASSPHRASE => undef,
333             LOGINSTAGE => '',
334             LASTPROMPT => undef,
335             SERIALEOF => 1,
336             TELNETMODE => 1,
337             POLL => undef, # Storage hash for poll-capable methods
338             POLLING => 0, # Flag to track if in polling-capable method or not
339             POLLREPORTED => 0, # Flag used by poll() to track already reported objects
340             WRITEFLAG => 0, # Flag to keep track of when a write was last performed
341             timeout => $Default{timeout},
342             connection_timeout => $Default{connection_timeout},
343             blocking => $Default{blocking},
344             return_reference => $Default{return_reference},
345             prompt_credentials => $Default{prompt_credentials},
346             read_attempts => $Default{read_attempts},
347             readwait_timer => $Default{readwait_timer},
348             data_with_error => $Default{data_with_error},
349             read_block_size => $Default{read_block_size}{$connectionType},
350             ors => $Default{ors},
351             errmode => $Default{errmode},
352             errmsg => '',
353             errmsg_format => $Default{errmsg_format},
354             prompt => $Default{prompt},
355             prompt_qr => qr/$Default{prompt}/,
356             username_prompt => $Default{username_prompt},
357             username_prompt_qr => qr/$Default{username_prompt}/,
358             password_prompt => $Default{password_prompt},
359             password_prompt_qr => qr/$Default{password_prompt}/,
360             terminal_type => $connectionType eq 'SSH' ? $Default{terminal_type} : undef,
361             window_size => $Default{window_size},
362             report_query_status => $Default{report_query_status},
363             debug => $Default{debug},
364 1 50       122 };
365 1 50       5 if ($connectionType eq 'SERIAL') { # Adjust read_block_size defaults for Win32::SerialPort & Device::SerialPort
366             $self->{read_block_size} = ($^O eq 'MSWin32') ? $Default{read_block_size}{SERIAL_WIN32}
367 0 0       0 : $Default{read_block_size}{SERIAL_DEVICE};
368             }
369 1         3 bless $self, $class;
370 1 50       3 if ($connectionType eq 'TELNET') {
371             # We are going to setup option callbacks to handle telnet options terminal type and window size
372             # However the callbacks only provide the telnet object and there is no option to feed additional arguments
373             # So need to link our object into the telnet one; here we create a key to contain our object
374 1         3 *$parent->{net_telnet}->{$Package} = $self;
375             }
376 1         4 foreach my $arg (keys %args) { # Accepted arguments on constructor
377 2 100       42 if ($arg eq 'errmode') { $self->errmode($args{$arg}) }
  1 50       5  
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
378 0         0 elsif ($arg eq 'errmsg_format') { $self->errmsg_format($args{$arg}) }
379 0         0 elsif ($arg eq 'timeout') { $self->timeout($args{$arg}) }
380 0         0 elsif ($arg eq 'connection_timeout') { $self->connection_timeout($args{$arg}) }
381 0         0 elsif ($arg eq 'read_block_size') { $self->read_block_size($args{$arg}) }
382 0         0 elsif ($arg eq 'blocking') { $self->blocking($args{$arg}) }
383 0         0 elsif ($arg eq 'read_attempts') { $self->read_attempts($args{$arg}) }
384 0         0 elsif ($arg eq 'readwait_timer') { $self->readwait_timer($args{$arg}) }
385 0         0 elsif ($arg eq 'data_with_error') { $self->data_with_error($args{$arg}) }
386 0         0 elsif ($arg eq 'return_reference') { $self->return_reference($args{$arg}) }
387 0         0 elsif ($arg eq 'output_record_separator') { $self->output_record_separator($args{$arg}) }
388 0         0 elsif ($arg eq 'prompt_credentials') { $self->prompt_credentials($args{$arg}) }
389 0         0 elsif ($arg eq 'prompt') { $self->prompt($args{$arg}) }
390 0         0 elsif ($arg eq 'username_prompt') { $self->username_prompt($args{$arg}) }
391 0         0 elsif ($arg eq 'password_prompt') { $self->password_prompt($args{$arg}) }
392 0         0 elsif ($arg eq 'terminal_type') { $self->terminal_type($args{$arg}) }
393 0         0 elsif ($arg eq 'window_size') { $self->window_size(@{$args{$arg}}) }
  0         0  
394 0         0 elsif ($arg eq 'report_query_status') { $self->report_query_status($args{$arg}) }
395 0         0 elsif ($arg eq 'input_log') { $self->input_log($args{$arg}) }
396 0         0 elsif ($arg eq 'output_log') { $self->output_log($args{$arg}) }
397 0         0 elsif ($arg eq 'dump_log') { $self->dump_log($args{$arg}) }
398 0         0 elsif ($arg eq 'debug') { $self->debug($args{$arg}) }
399             }
400 1         5 return $self;
401             }
402              
403             sub DESTROY { # Run disconnect
404 0     0   0 my $self = shift;
405 0         0 return $self->disconnect;
406             }
407              
408              
409             ############################################### Object methods ###############################################
410              
411             sub connect { # Connect to host
412 0     0 1 0 my $pkgsub = "${Package}::connect";
413 0         0 my $self = shift;
414 0         0 my %args;
415 0 0       0 if (@_ == 1) { # Method invoked in the shorthand form
416 0         0 $args{host} = shift;
417 0 0 0     0 if ($args{host} =~ /^(.+?)\s+(\d+)$/ || $args{host} =~ /^([^:\s]+?):(\d+)$/) {
418 0         0 ($args{host}, $args{port}) = ($1, $2);
419             }
420             }
421             else {
422 0         0 my @validArgs = ('host', 'port', 'username', 'password', 'publickey', 'privatekey', 'passphrase',
423             'prompt_credentials', 'baudrate', 'parity', 'databits', 'stopbits', 'handshake',
424             'errmode', 'connection_timeout', 'blocking', 'terminal_type', 'window_size',
425             'callback', 'forcebaud', 'atomic_connect');
426 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
427             }
428              
429             # Initialize the base POLL structure
430             $self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
431             $pkgsub,
432             __PACKAGE__->can('connect_poll'),
433             defined $args{blocking} ? $args{blocking} : $self->{blocking},
434             defined $args{connection_timeout} ? $args{connection_timeout} : $self->{connection_timeout},
435 0 0       0 defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
    0          
    0          
436             0, # no output
437             0, # no output
438             undef, # n/a
439             undef, # n/a
440             );
441             $self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
442             # Set method argument keys
443             host => $args{host},
444             port => $args{port},
445             username => $args{username},
446             password => $args{password},
447             publickey => $args{publickey},
448             privatekey => $args{privatekey},
449             passphrase => $args{passphrase},
450             baudrate => $args{baudrate},
451             parity => $args{parity},
452             databits => $args{databits},
453             stopbits => $args{stopbits},
454             handshake => $args{handshake},
455             prompt_credentials => defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
456             terminal_type => $args{terminal_type},
457             window_size => $args{window_size},
458             callback => $args{callback},
459             forcebaud => $args{forcebaud},
460             atomic_connect => $args{atomic_connect},
461             # Declare method storage keys which will be used
462 0 0       0 stage => 0,
463             authPublicKey => 0,
464             authPassword => 0,
465             };
466 0 0 0     0 if ($self->{TYPE} ne 'SERIAL' && !$UseSocketIP && defined $args{blocking} && !$args{blocking}) {
      0        
      0        
467 0         0 carp "$pkgsub: IO::Socket::IP is required for non-blocking connect";
468             }
469 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
470 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
471 0         0 return __PACKAGE__->can('poll_connect')->($self, $pkgsub); # Do not call a sub-classed version
472             }
473              
474              
475             sub connect_poll { # Poll status of connection (non-blocking mode)
476 0     0 1 0 my $pkgsub = "${Package}::connect_poll";
477 0         0 my $self = shift;
478 0 0       0 carp "$pkgsub: No arguments expected" if @_; # No arguments expected
479              
480 0 0 0     0 unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('connect_poll')) {
481 0         0 return $self->error("$pkgsub: Method connect() needs to be called first with blocking false");
482             }
483 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
484 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
485              
486             # If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
487 0 0 0     0 return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;
488              
489             # We get here only if we are not complete: $self->{POLL}{complete} == 0
490 0         0 return __PACKAGE__->can('poll_connect')->($self, $pkgsub); # Do not call a sub-classed version
491             }
492              
493              
494             sub read { # Read in data from connection
495 0     0 1 0 my $pkgsub = "${Package}::read";
496 0         0 my $self = shift;
497 0         0 my @validArgs = ('blocking', 'timeout', 'errmode', 'return_reference');
498 0         0 my %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
499 0 0       0 my $timeout = defined $args{timeout} ? $args{timeout} : $self->{timeout};
500 0 0       0 my $blocking = defined $args{blocking} ? $args{blocking} : $self->{blocking};
501 0 0       0 my $returnRef = defined $args{return_reference} ? $args{return_reference} : $self->{return_reference};
502 0 0       0 my $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef;
503 0 0       0 local $self->{errmode} = $errmode if defined $errmode;
504              
505 0 0 0     0 return $self->_read_blocking($pkgsub, $timeout, $returnRef) if $blocking && !length $self->{BUFFER};
506 0         0 return $self->_read_nonblocking($pkgsub, $returnRef); # if !$blocking || ($blocking && length $self->{BUFFER})
507             }
508              
509              
510             sub readwait { # Read in data initially in blocking mode, then perform subsequent non-blocking reads for more
511 0     0 1 0 my $pkgsub = "${Package}::readwait";
512 0         0 my $self = shift;
513 0         0 my ($outref, $bufref);
514 0         0 my $ticks = 0;
515 0         0 my @validArgs = ('read_attempts', 'readwait_timer', 'blocking', 'timeout', 'errmode', 'return_reference', 'data_with_error');
516 0         0 my %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
517 0 0       0 my $readAttempts = defined $args{read_attempts} ? $args{read_attempts} : $self->{read_attempts};
518 0 0       0 my $readwaitTimer = defined $args{readwait_timer} ? $args{readwait_timer} : $self->{readwait_timer};
519 0 0       0 my $dataWithError = defined $args{data_with_error} ? $args{data_with_error} : $self->{data_with_error};
520 0 0       0 my $timeout = defined $args{timeout} ? $args{timeout} : $self->{timeout};
521 0 0       0 my $blocking = defined $args{blocking} ? $args{blocking} : $self->{blocking};
522 0 0       0 my $returnRef = defined $args{return_reference} ? $args{return_reference} : $self->{return_reference};
523 0 0       0 my $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef;
524 0 0       0 local $self->{errmode} = $errmode if defined $errmode;
525              
526             # Wait until some data is read in
527 0         0 $bufref = $self->_read_buffer(1);
528 0 0 0     0 if (!length $$bufref && $blocking) {
529 0         0 $bufref = $self->_read_blocking($pkgsub, $timeout, 1);
530 0 0       0 return unless defined $bufref; # Catch errors in 'return' errmode
531             }
532             # Then keep reading until there is nothing more to read..
533 0         0 while ($ticks++ < $readAttempts) {
534 0         0 sleep($readwaitTimer/1000); # Fraction of a sec sleep using Time::HiRes::sleep
535 0         0 $outref = $self->read( blocking => 0, return_reference => 1, errmode => 'return' );
536 0 0       0 unless (defined $outref) { # Here we catch errors since errmode = 'return'
537 0 0 0     0 last if $dataWithError && length $$bufref; # Data_with_error processing
538 0         0 return $self->error("$pkgsub: Read error // ".$self->errmsg);
539             }
540 0 0       0 if (length $$outref) {
541 0         0 $$bufref .= $$outref;
542 0         0 $ticks = 0; # Reset ticks to zero upon successful read
543             }
544 0         0 $self->debugMsg(1,"readwait ticks = $ticks\n");
545             }
546 0 0       0 return $returnRef ? $bufref : $$bufref;
547             }
548              
549              
550             sub waitfor { # Wait to find pattern in the device output stream
551 0     0 1 0 my $pkgsub = "${Package}::waitfor";
552 0         0 my $self = shift;
553 0         0 my ($pollSyntax, $errmode, @matchpat);
554 0         0 my $timeout = $self->{timeout};
555 0         0 my $blocking = $self->{blocking};
556 0         0 my $returnRef = $self->{return_reference};
557              
558 0 0       0 if (@_ == 1) { # Method invoked with single argument form
559 0         0 $matchpat[0] = shift;
560             }
561             else { # Method invoked with multiple arguments form
562 0         0 my @validArgs = ('match', 'match_list', 'timeout', 'errmode', 'return_reference', 'blocking', 'poll_syntax');
563 0         0 my @args = parseMethodArgs($pkgsub, \@_, \@validArgs);
564 0         0 for (my $i = 0; $i < $#args; $i += 2) {
565 0 0       0 push @matchpat, $args[$i + 1] if $args[$i] eq 'match';
566 0 0 0     0 push @matchpat, @{$args[$i + 1]} if $args[$i] eq 'match_list' && ref($args[$i + 1]) eq "ARRAY";
  0         0  
567 0 0       0 $timeout = $args[$i + 1] if $args[$i] eq 'timeout';
568 0 0       0 $blocking = $args[$i + 1] if $args[$i] eq 'blocking';
569 0 0       0 $returnRef = $args[$i + 1] if $args[$i] eq 'return_reference';
570 0 0       0 $errmode = parse_errmode($pkgsub, $args[$i + 1]) if $args[$i] eq 'errmode';
571 0 0       0 $pollSyntax = $args[$i + 1] if $args[$i] eq 'poll_syntax';
572             }
573             }
574 0         0 my @matchArray = grep {defined} @matchpat; # Weed out undefined values, if any
  0         0  
575              
576             # Initialize the base POLL structure
577 0         0 $self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
578             $pkgsub,
579             __PACKAGE__->can('waitfor_poll'),
580             $blocking,
581             $timeout,
582             $errmode,
583             3,
584             undef, # This is set below
585             $returnRef,
586             undef, # n/a
587             );
588 0         0 my $waitfor = $self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
589             # Set method argument keys
590             matchpat => \@matchArray,
591             # Declare method storage keys which will be used
592             stage => 0,
593             matchpat_qr => undef,
594             };
595 0   0     0 $self->{POLL}{output_requested} = !$pollSyntax || wantarray; # Always true in legacy syntax and in poll_syntax if wantarray
596 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
597 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
598              
599 0         0 my ($ok, $prematch, $match) = __PACKAGE__->can('poll_waitfor')->($self, $pkgsub); # Do not call a sub-classed version
600             # We have an old and new syntax
601 0 0       0 if ($pollSyntax) { # New syntax
602 0 0       0 return wantarray ? ($ok, $prematch, $match) : $ok;
603             }
604             else { # Old syntax
605 0 0       0 return wantarray ? ($prematch, $match) : $prematch;
606             }
607             }
608              
609              
610             sub waitfor_poll { # Poll status of waitfor (non-blocking mode)
611 0     0 1 0 my $pkgsub = "${Package}::waitfor_poll";
612 0         0 my $self = shift;
613 0 0       0 carp "$pkgsub: No arguments expected" if @_; # No arguments expected
614              
615 0 0 0     0 unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('waitfor_poll')) {
616 0         0 return $self->error("$pkgsub: Method waitfor() needs to be called first with blocking false");
617             }
618 0         0 $self->{POLL}{output_requested} = wantarray; # This might change at every call
619 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
620 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
621              
622             # If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
623 0 0 0     0 return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;
624              
625             # We get here only if we are not complete: $self->{POLL}{complete} == 0
626 0         0 return __PACKAGE__->can('poll_waitfor')->($self, $pkgsub); # Do not call a sub-classed version
627             }
628              
629              
630             sub put { # Send character strings to host (no \n appended)
631 0     0 1 0 my $pkgsub = "${Package}::put";
632 0         0 my $self = shift;
633 0         0 my %args;
634 0 0       0 if (@_ == 1) { # Method invoked with just the command argument
635 0         0 $args{string} = shift;
636             }
637             else {
638 0         0 my @validArgs = ('string', 'errmode');
639 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
640             }
641 0 0       0 return 1 unless defined $args{string};
642 0 0       0 my $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef;
643 0 0       0 local $self->{errmode} = $errmode if defined $errmode;
644              
645 0         0 return $self->_put($pkgsub, \$args{string});
646             }
647              
648              
649             sub print { # Send CLI commands to host (\n appended)
650 0     0 1 0 my $pkgsub = "${Package}::print";
651 0         0 my $self = shift;
652 0         0 my %args;
653 0 0       0 if (@_ == 1) { # Method invoked with just the command argument
654 0         0 $args{line} = shift;
655             }
656             else {
657 0         0 my @validArgs = ('line', 'errmode');
658 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
659             }
660 0 0       0 my $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef;
661 0 0       0 local $self->{errmode} = $errmode if defined $errmode;
662 0         0 $args{line} .= $self->{ors};
663              
664 0         0 return $self->_put($pkgsub, \$args{line});
665             }
666              
667              
668             sub printlist { # Send multiple lines to host switch (\n appended)
669 0     0 1 0 my $pkgsub = "${Package}::printlist";
670 0         0 my $self = shift;
671 0         0 my $output = join($self->{ors}, @_) . $self->{ors};
672              
673 0         0 return $self->_put($pkgsub, \$output);
674             }
675              
676              
677             sub login { # Handles basic username/password login for Telnet/Serial login and locks onto 1st prompt
678 0     0 1 0 my $pkgsub = "${Package}::login";
679 0         0 my $self =shift;
680 0         0 my @validArgs = ('username', 'password', 'prompt_credentials', 'prompt', 'username_prompt', 'password_prompt',
681             'timeout', 'errmode', 'return_reference', 'blocking');
682 0         0 my %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
683              
684             # Initialize the base POLL structure
685             $self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
686             $pkgsub,
687             __PACKAGE__->can('login_poll'),
688             defined $args{blocking} ? $args{blocking} : $self->{blocking},
689             defined $args{timeout} ? $args{timeout} : $self->{timeout},
690             defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
691             1,
692             wantarray,
693             defined $args{return_reference} ? $args{return_reference} : $self->{return_reference},
694             undef, # n/a
695 0 0       0 );
    0          
    0          
    0          
696             $self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
697             # Set method argument keys
698             username => $args{username},
699             password => $args{password},
700             prompt_credentials => defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
701             prompt => defined $args{prompt} ? $args{prompt} : $self->{prompt_qr},
702             username_prompt => defined $args{username_prompt} ? $args{username_prompt} : $self->{username_prompt_qr},
703             password_prompt => defined $args{password_prompt} ? $args{password_prompt} : $self->{password_prompt_qr},
704             # Declare method storage keys which will be used
705 0 0       0 stage => 0,
    0          
    0          
    0          
706             login_attempted => undef,
707             };
708 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
709 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
710 0         0 return __PACKAGE__->can('poll_login')->($self, $pkgsub); # Do not call a sub-classed version
711             }
712              
713              
714             sub login_poll { # Poll status of login (non-blocking mode)
715 0     0 1 0 my $pkgsub = "${Package}::login_poll";
716 0         0 my $self = shift;
717 0 0       0 carp "$pkgsub: No arguments expected" if @_; # No arguments expected
718              
719 0 0 0     0 unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('login_poll')) {
720 0         0 return $self->error("$pkgsub: Method login() needs to be called first with blocking false");
721             }
722 0         0 $self->{POLL}{output_requested} = wantarray; # This might change at every call
723 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
724 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
725              
726             # If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
727 0 0 0     0 return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;
728              
729             # We get here only if we are not complete: $self->{POLL}{complete} == 0
730 0         0 return __PACKAGE__->can('poll_login')->($self, $pkgsub); # Do not call a sub-classed version
731             }
732              
733              
734             sub cmd { # Sends a CLI command to host and returns output
735 0     0 1 0 my $pkgsub = "${Package}::cmd";
736 0         0 my $self = shift;
737 0         0 my %args;
738 0 0       0 if (@_ == 1) { # Method invoked with just the command argument
739 0         0 $args{command} = shift;
740             }
741             else {
742 0         0 my @validArgs = ('command', 'prompt', 'timeout', 'errmode', 'return_reference', 'blocking', 'poll_syntax');
743 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
744             }
745 0 0       0 $args{command} = '' unless defined $args{command};
746              
747             # Initialize the base POLL structure
748             $self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
749             $pkgsub,
750             __PACKAGE__->can('cmd_poll'),
751             defined $args{blocking} ? $args{blocking} : $self->{blocking},
752             defined $args{timeout} ? $args{timeout} : $self->{timeout},
753             defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
754             1,
755             undef, # This is set below
756             defined $args{return_reference} ? $args{return_reference} : $self->{return_reference},
757             undef, # n/a
758 0 0       0 );
    0          
    0          
    0          
759             my $cmd = $self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
760             # Set method argument keys
761             command => $args{command},
762             prompt => defined $args{prompt} ? $args{prompt} : $self->{prompt_qr},
763             # Declare method storage keys which will be used
764 0 0       0 stage => 0,
765             cmdEchoRemoved => 0,
766             };
767 0   0     0 $self->{POLL}{output_requested} = !$args{poll_syntax} || wantarray; # Always true in legacy syntax and in poll_syntax if wantarray
768 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
769 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
770              
771 0         0 my ($ok, $output) = __PACKAGE__->can('poll_cmd')->($self, $pkgsub); # Do not call a sub-classed version
772             # We have a different syntax for scalar output in blocking and non-blocking modes
773 0 0       0 if ($args{poll_syntax}) { # New syntax
774 0 0       0 return wantarray ? ($ok, $output) : $ok;
775             }
776             else { # Old syntax
777 0 0       0 return wantarray ? ($ok, $output) : $output;
778             }
779             }
780              
781              
782             sub cmd_poll { # Poll status of cmd (non-blocking mode)
783 0     0 1 0 my $pkgsub = "${Package}::cmd_poll";
784 0         0 my $self = shift;
785 0 0       0 carp "$pkgsub: No arguments expected" if @_; # No arguments expected
786              
787 0 0 0     0 unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('cmd_poll')) {
788 0         0 return $self->error("$pkgsub: Method cmd() needs to be called first with blocking false");
789             }
790 0         0 $self->{POLL}{output_requested} = wantarray; # This might change at every call
791 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
792 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
793              
794             # If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
795 0 0 0     0 return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;
796              
797             # We get here only if we are not complete: $self->{POLL}{complete} == 0
798 0         0 return __PACKAGE__->can('poll_cmd')->($self, $pkgsub); # Do not call a sub-classed version
799             }
800              
801              
802             sub change_baudrate { # Change baud rate of active SERIAL connection
803 0     0 1 0 my $pkgsub = "${Package}::change_baudrate";
804 0         0 my $self = shift;
805 0         0 my %args;
806 0 0       0 if (@_ == 1) { # Method invoked with just the command argument
807 0         0 $args{baudrate} = shift;
808             }
809             else {
810 0         0 my @validArgs = ('baudrate', 'parity', 'databits', 'stopbits', 'handshake', 'blocking', 'errmode', 'forcebaud');
811 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
812             }
813              
814             # Initialize the base POLL structure
815             $self->poll_struct( # $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList
816             $pkgsub,
817             __PACKAGE__->can('change_baudrate_poll'),
818             defined $args{blocking} ? $args{blocking} : $self->{blocking},
819             undef,
820 0 0       0 defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : undef,
    0          
821             0, # n/a
822             undef, # n/a
823             undef, # n/a
824             undef, # n/a
825             );
826             $self->{POLL}{$pkgsub} = { # Populate structure with method arguments/storage
827             # Set method argument keys
828             baudrate => defined $args{baudrate} ? $args{baudrate} : $self->{BAUDRATE},
829             parity => defined $args{parity} ? $args{parity} : $self->{PARITY},
830             databits => defined $args{databits} ? $args{databits} : $self->{DATABITS},
831             stopbits => defined $args{stopbits} ? $args{stopbits} : $self->{STOPBITS},
832             handshake => defined $args{handshake} ? $args{handshake} : $self->{HANDSHAKE},
833             forcebaud => $args{forcebaud},
834             # Declare method storage keys which will be used
835 0 0       0 stage => 0,
    0          
    0          
    0          
    0          
836             };
837 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
838 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
839 0         0 return __PACKAGE__->can('poll_change_baudrate')->($self, $pkgsub); # Do not call a sub-classed version
840             }
841              
842              
843             sub change_baudrate_poll { # Poll status of change_baudrate (non-blocking mode)
844 0     0 1 0 my $pkgsub = "${Package}::change_baudrate_poll";
845 0         0 my $self = shift;
846 0 0       0 carp "$pkgsub: No arguments expected" if @_; # No arguments expected
847              
848 0 0 0     0 unless (defined $self->{POLL} && $self->{POLL}{coderef} == __PACKAGE__->can('change_baudrate_poll')) {
849 0         0 return $self->error("$pkgsub: Method change_baudrate() needs to be called first with blocking false");
850             }
851 0         0 local $self->{POLLING} = 1; # True until we come out of this polling-capable method
852 0 0       0 local $self->{errmode} = $self->{POLL}{errmode} if defined $self->{POLL}{errmode};
853              
854             # If already completed (1) or we got an error (undef) from previous call (errmsg is already set) then we go no further
855 0 0 0     0 return $self->poll_return($self->{POLL}{complete}) unless defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0;
856              
857             # We get here only if we are not complete: $self->{POLL}{complete} == 0
858 0         0 return __PACKAGE__->can('poll_change_baudrate')->($self, $pkgsub); # Do not call a sub-classed version
859             }
860              
861              
862             sub input_log { # Log to file all input sent to host
863 0     0 1 0 my $pkgsub = "${Package}::input_log";
864 0         0 my ($self, $fh) = @_;
865              
866 0 0       0 unless (defined $fh) { # No input = return current filehandle
867 0         0 return $self->{INPUTLOGFH};
868             }
869 0 0       0 if ($self->{TYPE} eq 'TELNET') { # For Telnet use methods provided by Net::Telnet
870 0         0 $fh = $self->{PARENT}->input_log($fh);
871 0 0 0     0 if (defined $fh && $self->{PARENT}->errmsg =~ /problem creating $fh: (.*)/) {
872 0         0 return $self->error("$pkgsub: Unable to open input log file: $1");
873             }
874             }
875             else { # SSH & SERIAL We implement logging ourselves
876 0 0 0     0 unless (ref $fh or length $fh) { # Empty input = stop logging
877 0         0 $self->{INPUTLOGFH} = undef;
878 0         0 return;
879             }
880 0 0 0     0 if (!ref($fh) && !defined(fileno $fh)) { # Open a new filehandle if input is a filename
881 0         0 my $logfile = $fh;
882 0         0 $fh = IO::Handle->new;
883 0 0       0 open($fh, '>', "$logfile") or return $self->error("$pkgsub: Unable to open input log file: $!");
884             }
885 0         0 $fh->autoflush();
886             }
887 0         0 $self->{INPUTLOGFH} = $fh;
888 0         0 return $fh;
889             }
890              
891              
892             sub output_log { # Log to file all output received from host
893 0     0 1 0 my $pkgsub = "${Package}::output_log";
894 0         0 my ($self, $fh) = @_;
895              
896 0 0       0 unless (defined $fh) { # No input = return current filehandle
897 0         0 return $self->{OUTPUTLOGFH};
898             }
899 0 0       0 if ($self->{TYPE} eq 'TELNET') { # For Telnet use methods provided by Net::Telnet
900 0         0 $fh = $self->{PARENT}->output_log($fh);
901 0 0 0     0 if (defined $fh && $self->{PARENT}->errmsg =~ /problem creating $fh: (.*)/) {
902 0         0 return $self->error("$pkgsub: Unable to open output log file: $1");
903             }
904             }
905             else { # SSH & SERIAL We implement logging ourselves
906 0 0 0     0 unless (ref $fh or length $fh) { # Empty input = stop logging
907 0         0 $self->{OUTPUTLOGFH} = undef;
908 0         0 return;
909             }
910 0 0 0     0 if (!ref($fh) && !defined(fileno $fh)) { # Open a new filehandle if input is a filename
911 0         0 my $logfile = $fh;
912 0         0 $fh = IO::Handle->new;
913 0 0       0 open($fh, '>', "$logfile") or return $self->error("$pkgsub: Unable to open output log file: $!");
914             }
915 0         0 $fh->autoflush();
916             }
917 0         0 $self->{OUTPUTLOGFH} = $fh;
918 0         0 return $fh;
919             }
920              
921              
922             sub dump_log { # Log hex and ascii for both input & output
923 0     0 1 0 my $pkgsub = "${Package}::dump_log";
924 0         0 my ($self, $fh) = @_;
925              
926 0 0       0 unless (defined $fh) { # No input = return current filehandle
927 0         0 return $self->{DUMPLOGFH};
928             }
929 0 0       0 if ($self->{TYPE} eq 'TELNET') { # For Telnet use methods provided by Net::Telnet
930 0         0 $fh = $self->{PARENT}->dump_log($fh);
931 0 0 0     0 if (defined $fh && $self->{PARENT}->errmsg =~ /problem creating $fh: (.*)/) {
932 0         0 return $self->error("$pkgsub: Unable to open dump log file: $1");
933             }
934             }
935             else { # SSH & SERIAL We implement logging ourselves
936 0 0 0     0 unless (ref $fh or length $fh) { # Empty input = stop logging
937 0         0 $self->{DUMPLOGFH} = undef;
938 0         0 return;
939             }
940 0 0 0     0 if (!ref($fh) && !defined(fileno $fh)) { # Open a new filehandle if input is a filename
941 0         0 my $logfile = $fh;
942 0         0 $fh = IO::Handle->new;
943 0 0       0 open($fh, '>', "$logfile") or return $self->error("$pkgsub: Unable to open dump log file: $!");
944             }
945 0         0 $fh->autoflush();
946             }
947 0         0 $self->{DUMPLOGFH} = $fh;
948 0         0 return $fh;
949             }
950              
951              
952             sub eof { # End-Of-File indicator
953 0     0 1 0 my $pkgsub = "${Package}::eof";
954 0         0 my $self = shift;
955              
956 0 0       0 if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
957             # Re-format Net::Telnet's own method to return 0 or 1
958 0 0       0 return $self->{PARENT}->eof ? 1 : 0;
959             }
960             elsif ($self->{TYPE} eq 'SSH') {
961             # Make SSH behave as Net::Telnet; return 1 if object created but not yet connected
962 0 0 0     0 return 1 if defined $self->{PARENT} && !defined $self->{SSHCHANNEL};
963             # Return Net::SSH2's own method if it is true (but it never is & seems not to work...)
964 0 0       0 return 1 if $self->{SSHCHANNEL}->eof;
965             # So we fudge it by checking Net::SSH2's last error code..
966 0         0 my $sshError = $self->{PARENT}->error; # Minimize calls to Net::SSH2 error method, as it leaks in version 0.58
967 0 0       0 return 1 if $sshError == -1; # LIBSSH2_ERROR_SOCKET_NONE
968 0 0       0 return 1 if $sshError == -43; # LIBSSH2_ERROR_SOCKET_RECV
969 0         0 return 0; # If we get here, return 0
970             }
971             elsif ($self->{TYPE} eq 'SERIAL') {
972 0         0 return $self->{SERIALEOF};
973             }
974             else {
975 0         0 return $self->error("$pkgsub: Invalid connection mode");
976             }
977 0         0 return 1;
978             }
979              
980              
981             sub break { # Send the break signal
982 0     0 1 0 my $pkgsub = "${Package}::break";
983 0         0 my $self = shift;
984 0   0     0 my $comBreakDuration = shift || $ComBreakDuration;
985              
986 0 0       0 return $self->error("$pkgsub: No connection to write to") if $self->eof;
987              
988 0 0       0 if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
989             # Simply use Net::Telnet's implementation
990             $self->{PARENT}->break
991 0 0       0 or return $self->error("$pkgsub: Unable to send telnet break signal");
992             }
993             elsif ($self->{TYPE} eq 'SSH') {
994             # For SSH we just send '~B' and hope that the other end will interpret it as a break
995 0 0       0 $self->put(string => '~B', errmode => 'return')
996             or return $self->error("$pkgsub: Unable to send SSH break signal // ".$self->errmsg);
997             }
998             elsif ($self->{TYPE} eq 'SERIAL') {
999 0         0 $self->{PARENT}->pulse_break_on($comBreakDuration);
1000             }
1001             else {
1002 0         0 return $self->error("$pkgsub: Invalid connection mode");
1003             }
1004 0         0 return 1;
1005             }
1006              
1007              
1008             sub disconnect { # Disconnect from host
1009 0     0 1 0 my $pkgsub = "${Package}::disconnect";
1010 0         0 my $self = shift;
1011 0         0 my %args;
1012 0 0       0 if (@_ == 1) { # Method invoked with just the command argument
1013 0         0 $args{close_logs} = shift;
1014             }
1015             else {
1016 0         0 my @validArgs = ('close_logs');
1017 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
1018             }
1019              
1020 0 0       0 if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
1021 0 0       0 $self->{PARENT}->close if defined $self->{PARENT};
1022 0         0 $self->{HOST} = $self->{TCPPORT} = undef;
1023 0 0       0 close $self->{SOCKET} if defined $self->{SOCKET};
1024 0         0 $self->{SOCKET} = undef;
1025             }
1026             elsif ($self->{TYPE} eq 'SSH') {
1027 0 0       0 $self->{SSHCHANNEL}->close if defined $self->{SSHCHANNEL};
1028 0         0 $self->{SSHCHANNEL} = $self->{SSHAUTH} = undef;
1029 0 0       0 $self->{PARENT}->disconnect() if defined $self->{PARENT};
1030 0         0 $self->{HOST} = $self->{TCPPORT} = undef;
1031 0 0       0 close $self->{SOCKET} if defined $self->{SOCKET};
1032 0         0 $self->{SOCKET} = undef;
1033             }
1034             elsif ($self->{TYPE} eq 'SERIAL') {
1035 0 0 0     0 if (defined $self->{PARENT} && !$self->{SERIALEOF}) {
1036             # Needed to flush writes before closing with Device::SerialPort (do once only)
1037 0 0       0 $self->{PARENT}->write_done(1) if defined $self->{BAUDRATE};
1038 0         0 $self->{PARENT}->close;
1039             }
1040 0         0 $self->{HANDSHAKE} = undef;
1041 0         0 $self->{BAUDRATE} = undef;
1042 0         0 $self->{PARITY} = undef;
1043 0         0 $self->{DATABITS} = undef;
1044 0         0 $self->{STOPBITS} = undef;
1045 0         0 $self->{SERIALEOF} = 1;
1046             }
1047             else {
1048 0         0 return $self->error("$pkgsub: Invalid connection mode");
1049             }
1050 0 0       0 if ($args{close_logs}) {
1051 0 0       0 if (defined $self->input_log) {
1052 0         0 close $self->input_log;
1053 0         0 $self->input_log('');
1054             }
1055 0 0       0 if (defined $self->output_log) {
1056 0         0 close $self->output_log;
1057 0         0 $self->output_log('');
1058             }
1059 0 0       0 if (defined $self->dump_log) {
1060 0         0 close $self->dump_log;
1061 0         0 $self->dump_log('');
1062             }
1063 0 0 0     0 if ($self->{TYPE} eq 'TELNET' && defined $self->parent->option_log) {
1064 0         0 close $self->parent->option_log;
1065 0         0 $self->parent->option_log('');
1066             }
1067             }
1068 0         0 return 1;
1069             }
1070              
1071              
1072             sub close { # Same as disconnect
1073 0     0 1 0 my $self = shift;
1074 0         0 return $self->disconnect(@_);
1075             }
1076              
1077              
1078             sub error { # Handle errors according to the object's error mode
1079 0     0 1 0 my $self = shift;
1080 0   0     0 my $errmsg = shift || '';
1081 0         0 my (undef, $fileName, $lineNumber) = caller; # Needed in case of die
1082              
1083 0         0 $self->errmsg($errmsg);
1084 0         0 return _error($fileName, $lineNumber, $self->{errmode}, $errmsg, $self->{errmsg_format});
1085             }
1086              
1087              
1088             sub poll { # Poll objects for completion
1089 0     0 1 0 my $pkgsub = "${Package}::poll";
1090 0         0 my ($self, %args);
1091 0         0 my ($running, $completed, $failed);
1092 0         0 my (@lastCompleted, @lastFailed);
1093 0         0 my $objComplete = $Default{poll_obj_complete};
1094 0         0 my $objError = $Default{poll_obj_error};
1095 0         0 my $pollTimer = $PollTimer/1000; # Convert to secs
1096 0         0 my ($mainLoopSleep, $mainLoopTime, $pollStartTime, $pollActHost, $objLastPollTime);
1097              
1098 0 0       0 if ($_[0]->isa($Package)) { # Method invoked as object method
    0          
1099 0         0 $self = shift;
1100 0         0 my @validArgs = ('poll_code', 'poll_timer', 'errmode');
1101 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
1102             }
1103             elsif (ref $_[0]) { # Method invoked with single argument array or hash ref
1104 0         0 $args{object_list} = shift;
1105             }
1106             else {
1107 0         0 my @validArgs = ('object_list', 'poll_code', 'object_complete', 'object_error', 'poll_timer', 'errmode', 'errmsg_format');
1108 0         0 %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
1109             }
1110 0 0       0 if (defined $args{object_complete}) {
1111 0 0       0 if ($args{object_complete} =~ /^all|next$/i) {
1112 0         0 $objComplete = lc $args{object_complete};
1113             }
1114             else {
1115 0         0 carp "$pkgsub: Invalid value for 'object_complete' argument; ignoring";
1116             }
1117             }
1118 0 0       0 if (defined $args{object_error}) {
1119 0 0       0 if ($args{object_error} =~ /^return|ignore$/i) {
1120 0         0 $objError = lc $args{object_error};
1121             }
1122             else {
1123 0         0 carp "$pkgsub: Invalid value for 'object_error' argument; ignoring";
1124             }
1125             }
1126 0 0       0 if (defined $args{poll_timer}) {
1127 0 0       0 if ($args{poll_timer} =~ /\d+/) {
1128 0         0 $pollTimer = $args{poll_timer}/1000; # Convert to secs
1129             }
1130             else {
1131 0         0 carp "$pkgsub: Invalid value for 'poll_timer' argument; ignoring";
1132             }
1133             }
1134 0 0       0 if (defined $args{poll_code}) {
1135 0 0       0 unless (validCodeRef($args{poll_code})) {
1136 0         0 $args{poll_code} = undef; # Only keep the argument if valid
1137 0         0 carp "$pkgsub: Argument 'poll_code' is not a valid code ref; ignoring";
1138             }
1139             }
1140 0 0       0 my $errmode = defined $args{errmode} ? parse_errmode($pkgsub, $args{errmode}) : ( defined $self ? $self->{errmode} : $Default{errmode} );
    0          
1141 0 0       0 my $msgFormat = defined $args{errmsg_format} ? $args{errmsg_format} : ( defined $self ? $self->{errmsg_format} : $Default{errmsg_format} );
    0          
1142 0 0 0     0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: No 'object_list' provided", $msgFormat) unless defined $self || defined $args{object_list};
1143              
1144 0         0 $pollStartTime = time;
1145 0         0 while (1) {
1146 0         0 $mainLoopTime = time; # Record time before going over loop below
1147 0         0 ($running, $completed, $failed) = (0,0,0);
1148            
1149 0 0       0 if ( defined $self ) { # Called in object oriented form; single object
    0          
    0          
1150 0 0       0 unless (defined $self->{POLL}) { # No poll structure exists, throw an error
1151 0 0       0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: No polling method was ever called for object", $msgFormat) if defined $args{errmode};
1152 0         0 return $self->error("$pkgsub: No polling method was ever called for object");
1153             }
1154 0 0       0 my $ok = _call_poll_method($self, 0, defined $args{errmode} ? $errmode : undef);
1155             # Return if completed or failed
1156 0 0 0     0 return $ok if $ok || !defined $ok;
1157 0         0 $running = 1; # Ensures we always loop below
1158             }
1159             elsif ( ref $args{object_list} eq 'ARRAY' ) { # Called in non-objectoriented form; list as arg
1160 0         0 for my $i ( 0 .. $#{$args{object_list}} ) {
  0         0  
1161 0         0 my $obj = ${$args{object_list}}[$i];
  0         0  
1162 0 0       0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: Array element $i is not a valid object", $msgFormat) unless $obj->isa($Package);
1163 0 0       0 unless (defined $obj->{POLL}) { # No poll structure exists, throw an error
1164 0 0       0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: No polling method was ever called for object array element $i", $msgFormat) if defined $args{errmode};
1165 0         0 return $obj->error("$pkgsub: No polling method was ever called for object array element $i");
1166             }
1167 0         0 my $objStartTime = time;
1168 0 0       0 my $objTimeCredit = $objStartTime - (defined $objLastPollTime->[$i] ? $objLastPollTime->[$i] : $pollStartTime) - $pollTimer;
1169 0 0       0 my $ok = _call_poll_method($obj, $objTimeCredit, defined $args{errmode} ? $errmode : undef);
1170 0 0       0 if ($ok) {
    0          
1171 0         0 $completed++;
1172 0 0       0 unless ($obj->{POLLREPORTED}) {
1173 0         0 push (@lastCompleted, $i);
1174 0         0 $obj->{POLLREPORTED} = 1;
1175             }
1176             }
1177             elsif (!defined $ok) {
1178 0         0 $failed++;
1179 0 0       0 unless ($obj->{POLLREPORTED}) {
1180 0         0 push (@lastFailed, $i);
1181 0         0 $obj->{POLLREPORTED} = 1;
1182             }
1183             }
1184 0         0 else { $running++ }
1185 0         0 $objLastPollTime->[$i] = time;
1186 0 0 0     0 if ( ($objLastPollTime->[$i] - $objStartTime) > $pollTimer && $args{poll_code}) { # On slow poll methods, call activity between every host
1187 0         0 callCodeRef($args{poll_code}, $running, $completed, $failed, \@lastCompleted, \@lastFailed);
1188 0         0 $pollActHost = 1; # Make sure we don't run activity at end of cycle then
1189             }
1190             else {
1191 0         0 $pollActHost = 0; # Make sure we run activity at end of cycle
1192             }
1193             }
1194             }
1195             elsif ( ref $args{object_list} eq 'HASH' ) { # Called in non-objectoriented form; hash as arg
1196 0         0 foreach my $key ( keys %{$args{object_list}} ) {
  0         0  
1197 0         0 my $obj = ${$args{object_list}}{$key};
  0         0  
1198 0 0       0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: Hash key $key is not a valid object", $msgFormat) unless $obj->isa($Package);
1199 0 0       0 unless (defined $obj->{POLL}) { # No poll structure exists, throw an error
1200 0 0       0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: No polling method was ever called for object hash key $key", $msgFormat) if defined $args{errmode};
1201 0         0 return $obj->error("$pkgsub: No polling method was ever called for object hash key $key");
1202             }
1203 0         0 my $objStartTime = time;
1204 0 0       0 my $objTimeCredit = $objStartTime - (defined $objLastPollTime->{$key} ? $objLastPollTime->{$key} : $pollStartTime) - $pollTimer;
1205 0 0       0 my $ok = _call_poll_method($obj, $objTimeCredit, defined $args{errmode} ? $errmode : undef);
1206 0 0       0 if ($ok) {
    0          
1207 0         0 $completed++;
1208 0 0       0 unless ($obj->{POLLREPORTED}) {
1209 0         0 push (@lastCompleted, $key);
1210 0         0 $obj->{POLLREPORTED} = 1;
1211             }
1212             }
1213             elsif (!defined $ok) {
1214 0         0 $failed++;
1215 0 0       0 unless ($obj->{POLLREPORTED}) {
1216 0         0 push (@lastFailed, $key);
1217 0         0 $obj->{POLLREPORTED} = 1;
1218             }
1219             }
1220 0         0 else { $running++ }
1221 0         0 $objLastPollTime->{$key} = time;
1222 0 0 0     0 if ( ($objLastPollTime->{$key} - $objStartTime) > $pollTimer && $args{poll_code}) { # On slow poll methods, call activity between every host
1223 0         0 callCodeRef($args{poll_code}, $running, $completed, $failed, \@lastCompleted, \@lastFailed);
1224 0         0 $pollActHost = 1; # Make sure we don't run activity at end of cycle then
1225             }
1226             else {
1227 0         0 $pollActHost = 0; # Make sure we run activity at end of cycle
1228             }
1229             }
1230             }
1231             else {
1232 0         0 return _error(__FILE__, __LINE__, $errmode, "$pkgsub: 'object_list' is not a hash or array reference", $msgFormat);
1233             }
1234              
1235             # Check if we are done, before calling pollcode or doing cycle wait
1236 0 0 0     0 last if ($running == 0) || ($objComplete eq 'next' && @lastCompleted) || ($objError eq 'return' && @lastFailed);
      0        
      0        
      0        
1237              
1238 0 0 0     0 if ($args{poll_code} && !$pollActHost) { # If a valid activity coderef was supplied and we did not just perform this on last object..
1239 0         0 callCodeRef($args{poll_code}, $running, $completed, $failed, \@lastCompleted, \@lastFailed);
1240             }
1241 0         0 $pollActHost = 0; # Reset flag
1242 0         0 $mainLoopSleep = $pollTimer - (time - $mainLoopTime); # Timer less time it took to run through loop
1243 0 0       0 sleep($mainLoopSleep) if $mainLoopSleep > 0; # Only if positive
1244             }
1245              
1246 0 0       0 return $running unless wantarray;
1247 0         0 return ($running, $completed, $failed, \@lastCompleted, \@lastFailed);
1248             }
1249              
1250              
1251             #################################### Methods to set/read Object variables ####################################
1252              
1253             sub timeout { # Set/read timeout
1254 0     0 1 0 my ($self, $newSetting) = @_;
1255 0         0 my $currentSetting = $self->{timeout};
1256 0 0       0 if (defined $newSetting) {
1257 0         0 $self->{timeout} = $newSetting;
1258 0 0       0 if ($self->{TYPE} eq 'TELNET') {
1259 0         0 $self->{PARENT}->timeout($newSetting);
1260             }
1261             }
1262 0         0 return $currentSetting;
1263             }
1264              
1265              
1266             sub connection_timeout { # Set/read connection timeout
1267 0     0 1 0 my ($self, $newSetting) = @_;
1268 0         0 my $currentSetting = $self->{connection_timeout};
1269 0         0 $self->{connection_timeout} = $newSetting;
1270 0         0 return $currentSetting;
1271             }
1272              
1273              
1274             sub read_block_size { # Set/read read_block_size for either SSH or SERIAL (not applicable to TELNET)
1275 0     0 1 0 my ($self, $newSetting) = @_;
1276 0         0 my $currentSetting = $self->{read_block_size};
1277 0 0       0 $self->{read_block_size} = $newSetting if defined $newSetting;
1278 0         0 return $currentSetting;
1279             }
1280              
1281              
1282             sub blocking { # Set/read blocking/unblocking mode for reading connection and polling methods
1283 0     0 1 0 my ($self, $newSetting) = @_;
1284 0         0 my $currentSetting = $self->{blocking};
1285 0 0       0 $self->{blocking} = $newSetting if defined $newSetting;
1286 0         0 return $currentSetting;
1287             }
1288              
1289              
1290             sub read_attempts { # Set/read number of read attempts in readwait()
1291 0     0 1 0 my ($self, $newSetting) = @_;
1292 0         0 my $currentSetting = $self->{read_attempts};
1293 0 0       0 $self->{read_attempts} = $newSetting if defined $newSetting;
1294 0         0 return $currentSetting;
1295             }
1296              
1297              
1298             sub readwait_timer { # Set/read poll timer in readwait()
1299 0     0 1 0 my ($self, $newSetting) = @_;
1300 0         0 my $currentSetting = $self->{readwait_timer};
1301 0 0       0 $self->{readwait_timer} = $newSetting if defined $newSetting;
1302 0         0 return $currentSetting;
1303             }
1304              
1305              
1306             sub data_with_error { # Set/read behaviour flag for readwait() when some data read followed by a read error
1307 0     0 1 0 my ($self, $newSetting) = @_;
1308 0         0 my $currentSetting = $self->{data_with_error};
1309 0 0       0 $self->{data_with_error} = $newSetting if defined $newSetting;
1310 0         0 return $currentSetting;
1311             }
1312              
1313              
1314             sub return_reference { # Set/read return_reference mode
1315 0     0 1 0 my ($self, $newSetting) = @_;
1316 0         0 my $currentSetting = $self->{return_reference};
1317 0 0       0 $self->{return_reference} = $newSetting if defined $newSetting;
1318 0         0 return $currentSetting;
1319             }
1320              
1321              
1322             sub output_record_separator { # Set/read the Output Record Separator automaticaly appended by print() and cmd()
1323 0     0 1 0 my ($self, $newSetting) = @_;
1324 0         0 my $currentSetting = $self->{ors};
1325 0 0       0 if (defined $newSetting) {
1326 0         0 $self->{ors} = $newSetting;
1327 0 0       0 $self->{TELNETMODE} = $newSetting eq "\r" ? 0 : 1;
1328             }
1329 0         0 return $currentSetting;
1330             }
1331              
1332              
1333             sub prompt_credentials { # Set/read prompt_credentials mode
1334 0     0 1 0 my $pkgsub = "${Package}::prompt_credentials";
1335 0         0 my ($self, $newSetting) = @_;
1336 0         0 my $currentSetting = $self->{prompt_credentials};
1337 0 0       0 if (defined $newSetting) {
1338 0 0 0     0 if (ref($newSetting) && !validCodeRef($newSetting)) {
1339 0         0 carp "$pkgsub: First item of array ref must be a code ref";
1340             }
1341 0         0 $self->{prompt_credentials} = $newSetting;
1342             }
1343 0         0 return $currentSetting;
1344             }
1345              
1346              
1347             sub flush_credentials { # Clear the stored username, password, passphrases, if any
1348 0     0 1 0 my $self = shift;
1349 0         0 $self->{USERNAME} = $self->{PASSWORD} = $self->{PASSPHRASE} = undef;
1350 0         0 return 1;
1351             }
1352              
1353              
1354             sub prompt { # Read/Set object prompt
1355 0     0 1 0 my ($self, $newSetting) = @_;
1356 0         0 my $currentSetting = $self->{prompt};
1357 0 0       0 if (defined $newSetting) {
1358 0         0 $self->{prompt} = $newSetting;
1359 0         0 $self->{prompt_qr} = qr/$newSetting/;
1360             }
1361 0         0 return $currentSetting;
1362             }
1363              
1364              
1365             sub username_prompt { # Read/Set object username prompt
1366 0     0 1 0 my ($self, $newSetting) = @_;
1367 0         0 my $currentSetting = $self->{username_prompt};
1368 0 0       0 if (defined $newSetting) {
1369 0         0 $self->{username_prompt} = $newSetting;
1370 0         0 $self->{username_prompt_qr} = qr/$newSetting/;
1371             }
1372 0         0 return $currentSetting;
1373             }
1374              
1375              
1376             sub password_prompt { # Read/Set object password prompt
1377 0     0 1 0 my ($self, $newSetting) = @_;
1378 0         0 my $currentSetting = $self->{password_prompt};
1379 0 0       0 if (defined $newSetting) {
1380 0         0 $self->{password_prompt} = $newSetting;
1381 0         0 $self->{password_prompt_qr} = qr/$newSetting/;
1382             }
1383 0         0 return $currentSetting;
1384             }
1385              
1386              
1387             sub terminal_type { # Read/Set object terminal type
1388 0     0 1 0 my ($self, $newSetting) = @_;
1389 0         0 my $currentSetting = $self->{terminal_type};
1390 0 0       0 if (defined $newSetting) {
1391 0 0       0 $self->{terminal_type} = length $newSetting ? $newSetting : undef;
1392             }
1393 0         0 return $currentSetting;
1394             }
1395              
1396              
1397             sub window_size { # Read/Set object terminal window size
1398 0     0 1 0 my $pkgsub = "${Package}::window_size";
1399 0         0 my ($self, $width, $height) = @_;
1400 0         0 my @currentSetting = @{$self->{window_size}};
  0         0  
1401 0 0 0     0 if ((defined $width && !$width) || (defined $height && !$height)) { # Empty value undefines it
    0 0        
      0        
      0        
1402 0         0 $self->{window_size} = [];
1403             }
1404             elsif (defined $width && defined $height) {
1405 0 0 0     0 if ($width =~ /^\d+$/ && $height =~ /^\d+$/) {
1406 0         0 $self->{window_size} = [$width, $height];
1407             }
1408             else {
1409 0         0 carp "$pkgsub: Invalid window size; numeric width & height required";
1410             }
1411             }
1412 0         0 return @currentSetting;
1413             }
1414              
1415              
1416             sub report_query_status { # Enable/Disable ability to Reply Device OK ESC sequence to Query Device Status ESC sequence
1417 0     0 1 0 my ($self, $newSetting) = @_;
1418 0         0 my $currentSetting = $self->{report_query_status};
1419 0 0       0 $self->{report_query_status} = $newSetting if defined $newSetting;
1420 0         0 return $currentSetting;
1421             }
1422              
1423              
1424             sub errmode { # Set/read error mode
1425 1     1 1 2 my $pkgsub = "${Package}::errmode";
1426 1         3 my ($self, $newSetting) = @_;
1427 1         5 my $currentSetting = $self->{errmode};
1428 1 50 33     5 if ((defined $newSetting) && (my $newMode = parse_errmode($pkgsub, $newSetting))) {
1429 1         2 $self->{errmode} = $newMode;
1430             }
1431 1         3 return $currentSetting;
1432             }
1433              
1434              
1435             sub errmsg { # Set/read the last generated error message for the object
1436 0     0 1   my $pkgsub = "${Package}::errmsg";
1437 0           my $self = shift;
1438 0           my %args;
1439 0 0         if (@_ == 1) { # Method invoked with just the command argument
1440 0           $args{set_message} = shift;
1441             }
1442             else {
1443 0           my @validArgs = ('set_message', 'errmsg_format');
1444 0           %args = parseMethodArgs($pkgsub, \@_, \@validArgs);
1445             }
1446 0 0         my $msgFormat = defined $args{errmsg_format} ? $args{errmsg_format} : $self->{errmsg_format};
1447 0           my $errmsg = $self->{errmsg};
1448 0 0         $self->{errmsg} = $args{set_message} if defined $args{set_message};
1449 0           return _error_format($msgFormat, $errmsg);
1450             }
1451              
1452              
1453             sub errmsg_format { # Set/read the error message format
1454 0     0 1   my $pkgsub = "${Package}::errmsg_format";
1455 0           my ($self, $newSetting) = @_;
1456 0           my $currentSetting = $self->{errmsg_format};
1457              
1458 0 0         if (defined $newSetting) {
1459 0 0         if ($newSetting =~ /^\s*terse\s*$/i) { $newSetting = 'terse' }
  0 0          
    0          
1460 0           elsif ($newSetting =~ /^\s*verbose\s*$/i) { $newSetting = 'verbose' }
1461 0           elsif ($newSetting =~ /^\s*default\s*$/i) { $newSetting = 'default' }
1462             else {
1463 0           carp "$pkgsub: invalid format '$newSetting'; ignoring";
1464 0           $newSetting = undef;
1465             }
1466 0 0         $self->{errmsg_format} = $newSetting if defined $newSetting;
1467             }
1468 0           return $currentSetting;
1469             }
1470              
1471              
1472             sub debug { # Set/read debug level
1473 0     0 1   my ($self, $newSetting) = @_;
1474 0           my $currentSetting = $self->{debug};
1475 0 0 0       if (defined $newSetting && $newSetting != $currentSetting) {
1476 0           $self->{debug} = $newSetting;
1477 0 0         if ($self->{TYPE} eq 'SSH') {
    0          
1478 0 0         $self->{PARENT}->debug($newSetting & 2 ? 1 : 0);
1479             }
1480             elsif ($self->{TYPE} eq 'SERIAL') {
1481 0 0         if ($^O eq 'MSWin32') {
1482 0           Win32::SerialPort->set_test_mode_active(!($newSetting & 1));
1483 0 0         Win32::SerialPort::debug($newSetting & 2 ? 'ON' : 'OFF');
1484             }
1485             else {
1486 0           Device::SerialPort->set_test_mode_active(!($newSetting & 1));
1487 0 0         Device::SerialPort::debug($newSetting & 2 ? 'ON' : 'OFF');
1488             }
1489             }
1490             }
1491 0           return $currentSetting;
1492             }
1493              
1494              
1495             ################################# Methods to read read-only Object variables #################################
1496              
1497             sub parent { # Return the parent object
1498 0     0 1   my $self = shift;
1499 0           return $self->{PARENT};
1500             }
1501              
1502              
1503             sub socket { # Return the socket object
1504 0     0 1   my $self = shift;
1505 0           return $self->{SOCKET};
1506             }
1507              
1508              
1509             sub ssh_channel { # Return the SSH channel object
1510 0     0 1   my $self = shift;
1511 0           return $self->{SSHCHANNEL};
1512             }
1513              
1514              
1515             sub ssh_authentication { # Return the SSH authentication type performed
1516 0     0 1   my $self = shift;
1517 0           return $self->{SSHAUTH};
1518             }
1519              
1520              
1521             sub connection_type { # Return the connection type of this object
1522 0     0 1   my $self = shift;
1523 0           return $self->{TYPE};
1524             }
1525              
1526              
1527             sub host { # Return the host we connect to
1528 0     0 1   my $self = shift;
1529 0           return $self->{HOST};
1530             }
1531              
1532              
1533             sub port { # Return the TCP port / COM port for the connection
1534 0     0 1   my $self = shift;
1535 0 0         if ($self->{TYPE} eq 'SERIAL') {
1536 0           return $self->{COMPORT};
1537             }
1538             else {
1539 0           return $self->{TCPPORT};
1540             }
1541             }
1542              
1543              
1544             sub connected { # Returns true if a connection is in place
1545 0     0 1   my $self = shift;
1546 0           return !$self->eof;
1547             }
1548              
1549              
1550             sub last_prompt { # Return the last prompt obtained
1551 0     0 1   my $self = shift;
1552 0           return $self->{LASTPROMPT};
1553             }
1554              
1555              
1556             sub username { # Read the username; this might have been provided or prompted for by a method in this class
1557 0     0 1   my $self = shift;
1558 0           return $self->{USERNAME};
1559             }
1560              
1561              
1562             sub password { # Read the password; this might have been provided or prompted for by a method in this class
1563 0     0 1   my $self = shift;
1564 0           return $self->{PASSWORD};
1565             }
1566              
1567              
1568             sub passphrase { # Read the passphrase; this might have been provided or prompted for by a method in this class
1569 0     0 1   my $self = shift;
1570 0           return $self->{PASSPHRASE};
1571             }
1572              
1573              
1574             sub handshake { # Read the serial handshake used
1575 0     0 1   my $self = shift;
1576 0           return $self->{HANDSHAKE};
1577             }
1578              
1579              
1580             sub baudrate { # Read the serial baudrate used
1581 0     0 1   my $self = shift;
1582 0           return $self->{BAUDRATE};
1583             }
1584              
1585              
1586             sub parity { # Read the serial parity used
1587 0     0 1   my $self = shift;
1588 0           return $self->{PARITY};
1589             }
1590              
1591              
1592             sub databits { # Read the serial databits used
1593 0     0 1   my $self = shift;
1594 0           return $self->{DATABITS};
1595             }
1596              
1597              
1598             sub stopbits { # Read the serial stopbits used
1599 0     0 1   my $self = shift;
1600 0           return $self->{STOPBITS};
1601             }
1602              
1603              
1604             #################################### Methods for modules sub-classing Control::CLI ####################################
1605              
1606             sub poll_struct { # Initialize the poll hash structure for a new method using it
1607 0     0 1   my ($self, $methodName, $codeRef, $blocking, $timeout, $errmode, $outputType, $outputRequested, $returnReference, $returnList) = @_;
1608 0           my $pollsub = "${Package}::poll_struct";
1609              
1610 0 0 0       if (defined $self->{POLL} && defined $self->{POLL}{complete} && $self->{POLL}{complete} == 0 ) { # Sanity check
      0        
1611 0           my (undef, $fileName, $lineNumber) = caller;
1612 0           my $pollOwner = $self->{POLL}{method};
1613 0           carp "$pollsub (called from $fileName line $lineNumber) $methodName is trampling over existing poll structure of $pollOwner";
1614             }
1615              
1616             $self->{POLL} = { # Initialize the base POLL structure
1617 0           method => $methodName,
1618             coderef => $codeRef,
1619             cache => [],
1620             blocking => $blocking,
1621             timeout => $timeout,
1622             endtime => undef,
1623             waittime => undef,
1624             errmode => $errmode,
1625             complete => 0,
1626             return_reference => $returnReference,
1627             return_list => $returnList,
1628             output_requested => $outputRequested,
1629             output_type => $outputType,
1630             output_result => undef,
1631             output_buffer => '',
1632             local_buffer => '',
1633             read_buffer => undef,
1634             already_polled => undef,
1635             socket => undef,
1636             };
1637 0           $self->{POLLREPORTED} = 0;
1638 0           $self->debugMsg(1," --> POLL : $methodName\n");
1639 0           return;
1640             }
1641              
1642              
1643             sub poll_reset { # Clears the existing poll structure, if any
1644 0     0 1   my $self = shift;
1645 0           my $methodName;
1646              
1647 0 0         return unless defined $self->{POLL};
1648 0           $methodName = $self->{POLL}{method};
1649 0 0         $methodName .= '-> ' . join('-> ', @{$self->{POLL}{cache}}) if @{$self->{POLL}{cache}};
  0            
  0            
1650 0           $self->{POLL} = undef;
1651 0           $self->debugMsg(1," --> POLL : undef (was $methodName)\n");
1652 0           return 1;
1653             }
1654              
1655              
1656             sub poll_struct_cache { # Cache selected poll structure keys into a sub polling structure
1657 0     0 1   my ($self, $cacheMethod, $timeout) = @_;
1658 0           my $pollsub = "${Package}::poll_struct_cache";
1659              
1660 0 0         unless ($self->{POLLING}) { # Sanity check
1661 0           my (undef, $fileName, $lineNumber) = caller;
1662 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1663             }
1664              
1665 0           $self->{POLL}{$cacheMethod}{cache}{output_buffer} = $self->{POLL}{output_buffer};
1666 0           $self->{POLL}{output_buffer} = '';
1667              
1668 0           $self->{POLL}{$cacheMethod}{cache}{output_result} = $self->{POLL}{output_result};
1669 0           $self->{POLL}{output_result} = '';
1670              
1671 0           $self->{POLL}{$cacheMethod}{cache}{local_buffer} = $self->{POLL}{local_buffer};
1672 0           $self->{POLL}{local_buffer} = '';
1673              
1674 0 0         if (defined $timeout) {
1675 0           $self->{POLL}{$cacheMethod}{cache}{timeout} = $self->{POLL}{timeout};
1676 0           $self->{POLL}{timeout} = $timeout;
1677             }
1678              
1679 0 0         my $cacheChain = @{$self->{POLL}{cache}} ? '--> ' . join(' --> ', @{$self->{POLL}{cache}}) : '';
  0            
  0            
1680 0           push( @{$self->{POLL}{cache}}, $cacheMethod); # Point cache location
  0            
1681 0           $self->debugMsg(1," --> POLL : $self->{POLL}{method} $cacheChain --> $cacheMethod\n");
1682 0           return;
1683             }
1684              
1685              
1686             sub poll_struct_restore { # Restore original poll structure from cached values and return cache method output
1687 0     0 1   my $self = shift;
1688 0           my $pollsub = "${Package}::poll_struct_restore";
1689              
1690 0 0         unless ($self->{POLLING}) { # Sanity check
1691 0           my (undef, $fileName, $lineNumber) = caller;
1692 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1693             }
1694              
1695 0           my $cacheMethod = pop( @{$self->{POLL}{cache}} );
  0            
1696             # Save the output buffer & result
1697 0           my $output_buffer = $self->{POLL}{output_buffer};
1698 0           my $output_result = $self->{POLL}{output_result};
1699             # Restore the cached keys
1700 0           foreach my $key (keys %{$self->{POLL}{$cacheMethod}{cache}}) {
  0            
1701 0           $self->{POLL}{$key} = $self->{POLL}{$cacheMethod}{cache}{$key};
1702             }
1703             # Undefine the method poll structure
1704 0           $self->{POLL}{$cacheMethod} = undef;
1705 0 0         my $cacheChain = @{$self->{POLL}{cache}} ? '--> ' . join(' --> ', @{$self->{POLL}{cache}}) : '';
  0            
  0            
1706 0           $self->debugMsg(1," --> POLL : $self->{POLL}{method} $cacheChain <-- $cacheMethod\n");
1707             # Return the output as reference
1708 0           return (\$output_buffer, \$output_result);
1709             }
1710              
1711              
1712             sub poll_return { # Method to return from poll methods
1713 0     0 1   my ($self, $ok) = @_;
1714 0           my $pollsub = "${Package}::poll_return";
1715              
1716 0 0         unless ($self->{POLLING}) { # Sanity check
1717 0           my (undef, $fileName, $lineNumber) = caller;
1718 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1719             }
1720 0           $self->{POLL}{already_polled} = undef; # Always reset this flag on exit
1721              
1722 0 0         if (@{$self->{POLL}{cache}}) { # Current polled method was called by another polled method
  0            
1723 0 0 0       return 0 if defined $ok && $ok == 0; # Never return any output on non-blocking not ready
1724             # If error or poll complete then restore cached output to poll structure and recover output, if any
1725 0           my ($output_bufRef, $output_resRef) = $self->poll_struct_restore;
1726 0 0         return unless defined $ok; # Never return any output on error
1727 0 0         return 1 unless wantarray; # No output requested
1728 0           return (1, $output_bufRef, $output_resRef); # Only return output, as reference, on success & wantarray
1729             }
1730              
1731 0           $self->{POLL}{complete} = $ok; # Store status for next poll
1732 0 0 0       return $ok unless $self->{POLL}{output_requested} && $self->{POLL}{output_type};
1733             # If we did not return above, only in this case do we have to provide output
1734 0           my @output_list;
1735 0 0         if ($self->{POLL}{output_type} & 1) { # Provide Output_buffer
1736 0           my $output = $self->{POLL}{output_buffer}; # 1st store the output buffer
1737 0           $self->{POLL}{output_buffer} = ''; # Then clear it in the storage structure
1738 0 0         if ($self->{POLL}{return_reference}) {
1739 0           push(@output_list, \$output);
1740             }
1741             else {
1742 0           push(@output_list, $output);
1743             }
1744             }
1745 0 0         if ($self->{POLL}{output_type} & 2) { # Provide Output_result
1746 0 0         if (ref $self->{POLL}{output_result} eq 'ARRAY') { # If an array
1747 0 0         if ($self->{POLL}{return_list}) {
1748 0           push(@output_list, @{$self->{POLL}{output_result}});
  0            
1749             }
1750             else {
1751 0           push(@output_list, $self->{POLL}{output_result});
1752             }
1753             }
1754             else { # Anything else (scalar or hash ref)
1755 0           push(@output_list, $self->{POLL}{output_result});
1756             }
1757             }
1758 0           return ($ok, @output_list);
1759             }
1760              
1761              
1762             sub poll_sleep { # Method to handle sleep for poll methods (handles both blocking and non-blocking modes)
1763 0     0 1   my ($self, $pkgsub, $secs) = @_;
1764 0           my $pollsub = "${Package}::poll_sleep";
1765              
1766 0 0         unless ($self->{POLLING}) { # Sanity check
1767 0           my (undef, $fileName, $lineNumber) = caller;
1768 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1769             }
1770              
1771 0 0         if ($self->{POLL}{blocking}) { # In blocking mode
1772 0           sleep $secs;
1773             }
1774             else { # In non-blocking mode
1775 0 0         unless(defined $self->{POLL}{endtime}) { # Set endtime for timeout
1776 0           $self->{POLL}{endtime} = time + $secs;
1777             }
1778 0 0         return 0 unless time > $self->{POLL}{endtime}; # Sleep time not expired yet
1779             }
1780 0           return 1;
1781             }
1782              
1783              
1784             sub poll_open_socket { # Internal method to open TCP socket for either Telnet or SSH
1785 0     0 1   my ($self, $pkgsub, $host, $port) = @_;
1786 0           my $pollsub = "${Package}::poll_open_socket";
1787              
1788 0 0         unless ($self->{POLLING}) { # Sanity check
1789 0           my (undef, $fileName, $lineNumber) = caller;
1790 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1791             }
1792              
1793 0 0         if ($UseSocketIP) { # Use IO::Socket::IP if we can (works for both IPv4 & IPv6)
1794              
1795             # In non-blocking mode we will come back here, so open socket only 1st time
1796 0 0         unless (defined $self->{POLL}{socket}) {
1797              
1798             # In non-blocking mode need to set the connection endtime for timeouts
1799 0 0         unless ($self->{POLL}{blocking}) {
1800 0 0         if (defined $self->{POLL}{timeout}) { # If a connection_timeout is defined, use it
1801 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
1802             }
1803             else { # If no connection_timeout is defined, fall back onto module's own default value for non-blocking connections
1804 0           $self->{POLL}{endtime} = time + $Default{connection_timeout_nb};
1805             }
1806             }
1807              
1808 0 0         $self->{POLL}{socket} = IO::Socket::IP->new(
1809             PeerHost => $host,
1810             PeerPort => $port,
1811             Blocking => 0, # Use non-blocking mode to enforce connection timeout
1812             # even if blocking connect()
1813             ) or return $self->error("$pkgsub: cannot construct socket - $@");
1814             }
1815              
1816 0   0       while ( !$self->{POLL}{socket}->connect && ( $! == EINPROGRESS || $! == EWOULDBLOCK ) ) {
      0        
1817 0           my $wvec = '';
1818 0           vec( $wvec, fileno $self->{POLL}{socket}, 1 ) = 1;
1819 0           my $evec = '';
1820 0           vec( $evec, fileno $self->{POLL}{socket}, 1 ) = 1;
1821              
1822 0 0         if ($self->{POLL}{blocking}) { # In blocking mode perform connection timeout
1823             select( undef, $wvec, $evec, $self->{POLL}{timeout} )
1824 0 0         or return $self->error("$pkgsub: connection timeout expired");
1825             }
1826             else { # In non-blocking mode don't wait; just come out if not ready and timeout not expired
1827 0 0         select( undef, $wvec, $evec, 0 ) or do {
1828 0 0         return (0, undef) unless time > $self->{POLL}{endtime}; # Timeout not expired
1829 0           return $self->error("$pkgsub: connection timeout expired"); # Timeout expired
1830             };
1831             }
1832             }
1833 0 0         return $self->error("$pkgsub: unable to connect - $!") if $!;
1834             }
1835             else { # Use IO::Socket::INET (only IPv4 support)
1836             $self->{POLL}{socket} = IO::Socket::INET->new(
1837             PeerHost => $host,
1838             PeerPort => $port,
1839             Timeout => $self->{POLL}{timeout},
1840 0 0         ) or return $self->error("$pkgsub: unable to establish socket - $@");
1841             }
1842 0           return (1, $self->{POLL}{socket});
1843             }
1844              
1845              
1846             sub poll_read { # Method to handle reads for poll methods (handles both blocking and non-blocking modes)
1847 0     0 1   my ($self, $pkgsub, $errmsg) = @_;
1848 0           my $pollsub = "${Package}::poll_read";
1849              
1850 0 0         unless ($self->{POLLING}) { # Sanity check
1851 0           my (undef, $fileName, $lineNumber) = caller;
1852 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1853             }
1854              
1855 0 0         if ($self->{POLL}{blocking}) { # In blocking mode
1856             $self->{POLL}{read_buffer} = $self->read(
1857             blocking => 1,
1858             timeout => $self->{POLL}{timeout},
1859 0           return_reference => 0,
1860             errmode => 'return',
1861             );
1862 0 0         unless (defined $self->{POLL}{read_buffer}) { # Here we catch errors since errmode = 'return'
1863 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1864 0           return; # Otherwise
1865             }
1866 0           return 1; # In blocking mode we come out here indicating we have read data
1867             }
1868             else { # In non-blocking mode
1869 0 0         if ($self->{POLL}{already_polled}) { # In non-blocking mode and if we already went round the calling loop once
1870 0           $self->{POLL}{already_polled} = undef; # Undefine it for next time
1871 0           $self->{POLL}{read_buffer} = undef; # Undefine it for next time
1872 0           return 0;
1873             }
1874              
1875 0 0         unless(defined $self->{POLL}{endtime}) { # Set endtime for timeout
1876 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
1877             }
1878              
1879 0           $self->{POLL}{read_buffer} = $self->read(
1880             blocking => 0,
1881             return_reference => 0,
1882             errmode => 'return',
1883             );
1884 0 0         unless (defined $self->{POLL}{read_buffer}) { # Here we catch errors since errmode = 'return'
1885 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1886 0           return; # Otherwise
1887             }
1888 0 0         if (length $self->{POLL}{read_buffer}) { # We read something
1889 0           $self->{POLL}{already_polled} = 1; # Set it for next cycle
1890 0           $self->{POLL}{endtime} = undef; # Clear timeout endtime
1891 0           return 1; # This is effectively when we are done and $self->{POLL}{read_buffer} can be read by calling loop
1892             }
1893              
1894             # We read nothing from device
1895 0 0         if (time > $self->{POLL}{endtime}) { # Timeout has expired
1896 0           $self->{POLL}{endtime} = undef; # Clear timeout endtime
1897 0           $self->errmsg("$pollsub: Poll Read Timeout");
1898 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1899 0           return; # Otherwise
1900             }
1901             else { # Still within timeout
1902 0           return 0;
1903             }
1904             }
1905             }
1906              
1907              
1908             sub poll_readwait { # Method to handle readwait for poll methods (handles both blocking and non-blocking modes)
1909 0     0 1   my ($self, $pkgsub, $firstReadRequired, $readAttempts, $readwaitTimer, $errmsg, $dataWithError) = @_;
1910 0 0         $readAttempts = $self->{read_attempts} unless defined $readAttempts;
1911 0 0         $readwaitTimer = $self->{readwait_timer} unless defined $readwaitTimer;
1912 0 0         $dataWithError = $self->{data_with_error} unless defined $dataWithError;
1913 0           my $pollsub = "${Package}::poll_readwait";
1914              
1915 0 0         unless ($self->{POLLING}) { # Sanity check
1916 0           my (undef, $fileName, $lineNumber) = caller;
1917 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
1918             }
1919              
1920             # Different read section for blocking and non-blocking modes
1921 0 0         if ($self->{POLL}{blocking}) { # In blocking mode use regular readwait() method
1922             $self->{POLL}{read_buffer} = $self->readwait(
1923             read_attempts => $readAttempts,
1924             readwait_timer => $readwaitTimer,
1925             data_with_error => $dataWithError,
1926             blocking => $firstReadRequired,
1927             timeout => $self->{POLL}{timeout},
1928 0           return_reference => 0,
1929             errmode => 'return',
1930             );
1931 0 0         unless (defined $self->{POLL}{read_buffer}) { # Here we catch errors since errmode = 'return'
1932 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1933 0           return; # Otherwise
1934             }
1935 0           return 1; # In non-blocking mode we come out here
1936             }
1937             else { # In non-blocking mode
1938 0 0         if ($self->{POLL}{already_polled}) { # In non-blocking mode and if we already went round the calling loop once
1939 0           $self->{POLL}{already_polled} = undef; # Undefine it for next time
1940 0           $self->{POLL}{read_buffer} = undef; # Undefine it for next time
1941 0           return 0;
1942             }
1943              
1944 0 0 0       if ($firstReadRequired && !defined $self->{POLL}{endtime}) { # First time we need to setup endtime timer
    0 0        
1945 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
1946             }
1947             elsif (!$firstReadRequired && !defined $self->{POLL}{waittime}) { # First time, no timeout, but we need to setup wait timer directly
1948 0           $self->{POLL}{waittime} = time + $readwaitTimer/1000 * $readAttempts;
1949 0           $self->{POLL}{read_buffer} = ''; # Make sure read buffer is defined and empty
1950             }
1951              
1952 0           my $outref = $self->read(
1953             blocking => 0,
1954             return_reference => 1,
1955             errmode => 'return',
1956             );
1957 0 0         unless (defined $outref) { # Here we catch errors since errmode = 'return'
1958 0 0 0       if ($dataWithError && length $self->{POLL}{read_buffer}) { # Data_with_error processing
1959 0           $self->{POLL}{already_polled} = 1; # Set it for next cycle
1960 0           $self->{POLL}{endtime} = undef; # Clear timeout endtime
1961 0           $self->{POLL}{waittime} = undef; # Clear waittime
1962 0           return 1; # We are done, available data in $self->{POLL}{read_buffer} can be read by calling loop, in spite of error
1963             }
1964 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1965 0           return; # Otherwise
1966             }
1967 0 0         if (length $$outref) { # We read something, reset wait timer
1968 0           $self->{POLL}{read_buffer} .= $$outref;
1969 0           $self->{POLL}{waittime} = time + $readwaitTimer/1000 * $readAttempts;
1970 0           return 0;
1971             }
1972              
1973             # We read nothing from device
1974 0 0         if (defined $self->{POLL}{waittime}) { # Some data already read; now just doing waittimer for more
1975 0 0         if (time > $self->{POLL}{waittime}) { # Wait timer has expired
1976 0           $self->{POLL}{already_polled} = 1; # Set it for next cycle
1977 0           $self->{POLL}{endtime} = undef; # Clear timeout endtime
1978 0           $self->{POLL}{waittime} = undef; # Clear waittime
1979 0           return 1; # This is effectively when we are done and $self->{POLL}{read_buffer} can be read by calling loop
1980             }
1981             else { # Wait timer has not expired yet
1982 0           return 0;
1983             }
1984             }
1985             else { # No data read yet, regular timeout checking
1986 0 0         if (time > $self->{POLL}{endtime}) { # Timeout has expired
1987 0           $self->{POLL}{endtime} = undef; # Clear timeout endtime
1988 0           $self->errmsg("$pollsub: Poll Read Timeout");
1989 0 0         return $self->error("$pkgsub: $errmsg // ".$self->errmsg) if defined $errmsg;
1990 0           return; # Otherwise
1991             }
1992             else { # Still within timeout
1993 0           return 0;
1994             }
1995             }
1996             }
1997             }
1998              
1999              
2000             sub poll_connect { # Internal method to connect to host (used for both blocking & non-blocking modes)
2001 0     0 1   my $self = shift;
2002 0           my $pkgsub = shift;
2003 0           my $pollsub = "${Package}::connect";
2004              
2005 0 0         unless ($self->{POLLING}) { # Sanity check
2006 0           my (undef, $fileName, $lineNumber) = caller;
2007 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
2008             }
2009              
2010 0 0         unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
2011 0           my @validArgs = ('host', 'port', 'username', 'password', 'publickey', 'privatekey', 'passphrase',
2012             'prompt_credentials', 'baudrate', 'parity', 'databits', 'stopbits', 'handshake',
2013             'errmode', 'connection_timeout', 'terminal_type', 'window_size', 'callback',
2014             'forcebaud', 'atomic_connect');
2015 0           my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
2016 0 0 0       if (@_ && !%args) { # Legacy syntax
2017             ($args{host}, $args{port}, $args{username}, $args{password}, $args{publickey}, $args{privatekey}, $args{passphrase}, $args{baudrate},
2018 0           $args{parity}, $args{databits}, $args{stopbits}, $args{handshake}, $args{prompt_credentials}, $args{timeout}, $args{errmode}) = @_;
2019             }
2020             # In which case we need to setup the poll structure here (the main poll structure remains unchanged)
2021             $self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
2022             # Set method argument keys
2023             host => $args{host},
2024             port => $args{port},
2025             username => defined $args{username} ? $args{username} : $self->{USERNAME},
2026             password => defined $args{password} ? $args{password} : $self->{PASSWORD},
2027             publickey => $args{publickey},
2028             privatekey => $args{privatekey},
2029             passphrase => defined $args{passphrase} ? $args{passphrase} : $self->{PASSPHRASE},
2030             baudrate => $args{baudrate},
2031             parity => $args{parity},
2032             databits => $args{databits},
2033             stopbits => $args{stopbits},
2034             handshake => $args{handshake},
2035             prompt_credentials => defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
2036             terminal_type => $args{terminal_type},
2037             window_size => $args{window_size},
2038             callback => $args{callback},
2039             forcebaud => $args{forcebaud},
2040             atomic_connect => $args{atomic_connect},
2041             # Declare method storage keys which will be used
2042             stage => 0,
2043             authPublicKey => 0,
2044             authPassword => 0,
2045             # Declare keys to be set if method called from another polled method
2046             errmode => $args{errmode},
2047 0 0         };
    0          
    0          
    0          
2048             # Cache poll structure keys which this method will use
2049 0           $self->poll_struct_cache($pollsub, $args{connection_timeout});
2050             }
2051 0           my $connect = $self->{POLL}{$pollsub};
2052 0 0         local $self->{errmode} = $connect->{errmode} if defined $connect->{errmode};
2053              
2054 0           my $ok;
2055              
2056 0 0         if ($connect->{stage} < 1) { # Initial setup - do only once
2057 0           $self->{BUFFER} = '';
2058 0           $self->{LOGINSTAGE} = '';
2059              
2060             # For these arguments, go change the object setting, as it will need accessing via Net:Telnet callbacks
2061 0 0         $self->terminal_type($connect->{terminal_type}) if defined $connect->{terminal_type};
2062 0 0         $self->window_size(@{$connect->{window_size}}) if defined $connect->{window_size};
  0            
2063             }
2064              
2065 0 0         if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
2066 0 0         if ($connect->{stage} < 1) { # Initial setup - do only once
2067 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2068 0 0         return $self->poll_return($self->error("$pkgsub: No Telnet host provided")) unless defined $connect->{host};
2069 0           $self->{PARENT}->errmode('return');
2070 0           $self->{PARENT}->timeout($self->{timeout});
2071 0 0         $connect->{port} = $Default{tcp_port}{TELNET} unless defined $connect->{port};
2072 0           $self->{HOST} = $connect->{host};
2073 0           $self->{TCPPORT} = $connect->{port};
2074 0 0 0       if (!$self->{POLL}{blocking} && $connect->{atomic_connect}) {
2075 0           $self->{POLL}{blocking} = 1; # Switch into blocking mode during connect phase
2076 0           return $self->poll_return(0); # Next poll will be the atomic connect
2077             }
2078             else {
2079 0           $connect->{atomic_connect} = undef; # In blocking mode undefine it
2080             }
2081             }
2082             # TCP Socket setup and handoff to Net::Telnet object
2083             # Open Socket ourselves
2084 0           ($ok, $self->{SOCKET}) = $self->poll_open_socket($pkgsub, $connect->{host}, $connect->{port});
2085 0 0         return $self->poll_return($ok) unless $ok; # Covers 2 cases:
2086             # - errmode is 'return' and $ok = undef ; so we come out due to error
2087             # - $ok = 0 ; non-blocking mode; connection not ready yet
2088              
2089             # Give Socket to Net::Telnet
2090 0 0         $self->{PARENT}->fhopen($self->{SOCKET}) or return $self->poll_return($self->error("$pkgsub: unable to open Telnet over socket"));
2091 0 0         if ($^O eq 'MSWin32') {
2092             # We need this hack to workaround a bug introduced in Net::Telnet 3.04
2093             # see Net::Telnet bug report 94913: https://rt.cpan.org/Ticket/Display.html?id=94913
2094 0           my $telobj = *{$self->{PARENT}}->{net_telnet};
  0            
2095 0 0 0       if (exists $telobj->{select_supported} && !$telobj->{select_supported}) {
2096             # select_supported key is new in Net::Telnet 3.04 (does not exist in 3.03)
2097             # If we get here, it is because it did not get set correctly by our fhopen above, which means
2098             # we are using Net::Telnet 3.04 or a later version of it which still has not fixed the issue
2099 0           $telobj->{select_supported} = 1; # Workaround, we set it
2100             }
2101             }
2102              
2103             # Handle Telnet options
2104 0           $self->_handle_telnet_options;
2105 0 0         $self->{POLL}{blocking} = 0 if $connect->{atomic_connect}; # Restore non-blocking mode once connect complete
2106             }
2107             elsif ($self->{TYPE} eq 'SSH') {
2108 0 0         if ($connect->{stage} < 1) { # Initial setup - do only once
2109 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2110 0 0         return $self->poll_return($self->error("$pkgsub: No SSH host provided")) unless defined $connect->{host};
2111 0 0         $connect->{port} = $Default{tcp_port}{SSH} unless defined $connect->{port};
2112 0           $self->{HOST} = $connect->{host};
2113 0           $self->{TCPPORT} = $connect->{port};
2114 0 0 0       if (!$self->{POLL}{blocking} && $connect->{atomic_connect}) {
2115 0           $self->{POLL}{blocking} = 1; # Switch into blocking mode during connect phase
2116 0           return $self->poll_return(0); # Next poll will be the atomic connect
2117             }
2118             else {
2119 0           $connect->{atomic_connect} = undef; # In blocking mode undefine it
2120             }
2121             }
2122 0 0         if ($connect->{stage} < 2) { # TCP Socket setup and handoff to Net::SSH2 object
2123             # Open Socket ourselves
2124 0           ($ok, $self->{SOCKET}) = $self->poll_open_socket($pkgsub, $connect->{host}, $connect->{port});
2125 0 0         return $self->poll_return($ok) unless $ok; # Covers 2 cases:
2126             # - errmode is 'return' and $ok = undef ; so we come out due to error
2127             # - $ok = 0 ; non-blocking mode; connection not ready yet
2128 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2129              
2130             # Set the SO_LINGER option as Net::SSH2 would do
2131 0           $self->{SOCKET}->sockopt(&Socket::SO_LINGER, pack('SS', 0, 0));
2132            
2133             # Give Socket to Net::SSH2
2134 0           eval { # Older versions of Net::SSH2 need to be trapped so that we get desired error mode
2135 0           $ok = $self->{PARENT}->connect($self->{SOCKET});
2136             };
2137 0 0         return $self->poll_return($self->error("$pkgsub: " . $@)) if $@;
2138 0 0         return $self->poll_return($self->error("$pkgsub: SSH unable to connect")) unless $ok;
2139 0 0         return $self->poll_return(0) unless $self->{POLL}{blocking};
2140             }
2141 0 0         if ($connect->{stage} < 3) { # Check for callback (if user wants to verify device hostkey against known hosts)
2142 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2143 0 0         if ($connect->{callback}) {
2144 0 0         if ( validCodeRef($connect->{callback}) ) {
2145 0           ($ok, my $errmsg) = callCodeRef($connect->{callback}, $self);
2146 0 0         return $self->poll_return($self->error("$pkgsub: " . (defined $errmsg ? $errmsg : "SSH callback refused connection"))) unless $ok;
    0          
2147 0 0         return $self->poll_return(0) unless $self->{POLL}{blocking};
2148             }
2149             else {
2150 0           carp "$pkgsub: Callback is not a valid code ref; ignoring";
2151             }
2152             }
2153             }
2154 0 0         if ($connect->{stage} < 4) { # Find out available SSH authentication options
2155 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2156 0 0         unless ( defined $connect->{username} ) {
2157 0 0         return $self->poll_return($self->error("$pkgsub: Username required for SSH authentication")) unless $connect->{prompt_credentials};
2158 0           $connect->{username} = promptCredential($connect->{prompt_credentials}, 'Clear', 'Username');
2159             # Reset timeout endtime
2160 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
2161             }
2162 0 0 0       if ( !$self->{POLL}{blocking} && time > $self->{POLL}{endtime} ) { # Check if over time in non-blocking mode
2163 0           return $self->poll_return($self->error("$pkgsub: connection timeout expired (before auth_list)"));
2164             }
2165 0           my @authList = $self->{PARENT}->auth_list($connect->{username});
2166 0           foreach my $auth (@authList) {
2167 0 0         $connect->{authPublicKey} = 1 if $auth eq 'publickey';
2168 0 0         $connect->{authPassword} |= 1 if $auth eq 'password'; # bit1 = password
2169 0 0         $connect->{authPassword} |= 2 if $auth eq 'keyboard-interactive'; # bit2 = KI
2170             }
2171 0           $self->debugMsg(1,"SSH authentications accepted: ", \join(', ', @authList), "\n");
2172 0           $self->debugMsg(1,"authPublicKey flag = $connect->{authPublicKey} ; authPassword flag = $connect->{authPassword}\n");
2173 0           $self->{USERNAME} = $connect->{username}; # If we got here, we have a connection so store the username used
2174 0 0         return $self->poll_return(0) unless $self->{POLL}{blocking};
2175             }
2176 0 0         if ($connect->{stage} < 5) { # Try publickey authentication
2177 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2178 0 0         if ($connect->{authPublicKey}) { # Try Public Key authentication...
2179 0 0 0       if (defined $connect->{publickey} && defined $connect->{privatekey}) { # ... if we have keys
    0          
2180             return $self->poll_return($self->error("$pkgsub: Public Key '$connect->{publickey}' not found"))
2181 0 0         unless -e $connect->{publickey};
2182             return $self->poll_return($self->error("$pkgsub: Private Key '$connect->{privatekey}' not found"))
2183 0 0         unless -e $connect->{privatekey};
2184 0 0         unless ($connect->{passphrase}) { # Passphrase not provided
2185 0           my $passphReq = passphraseRequired($connect->{privatekey});
2186 0 0         return $self->poll_return($self->error("$pkgsub: Unable to read Private key")) unless defined $passphReq;
2187 0 0         if ($passphReq) { # Passphrase is required
2188 0 0         return $self->poll_return($self->error("$pkgsub: Passphrase required for Private Key")) unless $connect->{prompt_credentials};
2189             # We are allowed to prompt for it
2190 0           $connect->{passphrase} = promptCredential($connect->{prompt_credentials}, 'Hide', 'Passphrase for Private Key');
2191             # Reset timeout endtime
2192 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
2193             }
2194             }
2195 0 0 0       if ( !$self->{POLL}{blocking} && time > $self->{POLL}{endtime} ) { # Check if over time in non-blocking mode
2196 0           return $self->poll_return($self->error("$pkgsub: connection timeout expired (before auth_publickey"));
2197             }
2198             $ok = $self->{PARENT}->auth_publickey(
2199             $connect->{username},
2200             $connect->{publickey},
2201             $connect->{privatekey},
2202             $connect->{passphrase},
2203 0           );
2204 0 0 0       if ($ok) { # Store the passphrase used if publickey authentication succeded
    0          
2205 0 0         $self->{PASSPHRASE} = $connect->{passphrase} if $connect->{passphrase};
2206 0           $self->{SSHAUTH} = 'publickey';
2207             }
2208             elsif ( !($connect->{authPassword} && (defined $connect->{password} || $connect->{prompt_credentials})) ) {
2209             # Unless we can try password authentication next, throw an error now
2210 0           return $self->poll_return($self->error("$pkgsub: SSH unable to publickey authenticate"));
2211             }
2212 0 0         return $self->poll_return(0) unless $self->{POLL}{blocking};
2213             }
2214             elsif (!$connect->{authPassword}) { # If we don't have the keys and publickey authentication was the only one possible
2215 0           return $self->poll_return($self->error("$pkgsub: Only publickey SSH authenticatication possible and no keys provided"));
2216             }
2217             }
2218             }
2219 0 0         if ($connect->{stage} < 6) { # Try password authentication
2220 0           $connect->{stage}++; # Ensure we don't come back here in non-blocking mode
2221 0 0 0       if ($connect->{authPassword} && !$self->{PARENT}->auth_ok) { # Try password authentication if not already publickey authenticated
2222 0 0         unless ( defined $connect->{password} ) {
2223 0 0         return $self->poll_return($self->error("$pkgsub: Password required for password authentication")) unless $connect->{prompt_credentials};
2224 0           $connect->{password} = promptCredential($connect->{prompt_credentials}, 'Hide', 'Password');
2225             # Reset timeout endtime
2226 0           $self->{POLL}{endtime} = time + $self->{POLL}{timeout};
2227             }
2228 0 0 0       if ( !$self->{POLL}{blocking} && time > $self->{POLL}{endtime} ) { # Check if over time in non-blocking mode
2229 0           return $self->poll_return($self->error("$pkgsub: connection timeout expired (before auth_password)"));
2230             }
2231 0 0         if ($connect->{authPassword} & 1) { # Use password authentication
    0          
2232             $self->{PARENT}->auth_password($connect->{username}, $connect->{password})
2233 0 0         or return $self->poll_return($self->error("$pkgsub: SSH unable to password authenticate"));
2234 0           $self->{SSHAUTH} = 'password';
2235             }
2236             elsif ($connect->{authPassword} & 2) { # Use keyboard-interactive authentication
2237             $self->{PARENT}->auth_keyboard($connect->{username}, $connect->{password})
2238 0 0         or return $self->poll_return($self->error("$pkgsub: SSH unable to password authenticate (using keyboard-interactive)"));
2239 0           $self->{SSHAUTH} = 'keyboard-interactive';
2240             }
2241             else {
2242 0           return $self->poll_return($self->error("$pkgsub: Error in processing password authentication options"));
2243             }
2244             # Store password used
2245 0           $self->{PASSWORD} = $connect->{password};
2246 0 0         return $self->poll_return(0) unless $self->{POLL}{blocking};
2247             }
2248             }
2249             # Make sure we are authenticated, in case neither publicKey nor password auth was accepted
2250 0 0         return $self->poll_return($self->error("$pkgsub: SSH unable to authenticate")) unless $self->{PARENT}->auth_ok;
2251              
2252             # Setup SSH channel
2253 0 0 0       if ( !$self->{POLL}{blocking} && time > $self->{POLL}{endtime} ) { # Check if over time in non-blocking mode
2254 0           return $self->poll_return($self->error("$pkgsub: connection timeout expired (before SSH channel setup)"));
2255             }
2256 0           $self->{SSHCHANNEL} = $self->{PARENT}->channel(); # Open an SSH channel
2257 0           $self->{PARENT}->blocking(0); # Make the session non blocking for reads
2258 0           $self->{SSHCHANNEL}->ext_data('merge'); # Merge stderr onto regular channel
2259 0           $self->{SSHCHANNEL}->pty($self->{terminal_type}, undef, @{$self->{window_size}}); # Start interactive terminal; also set term type & window size
  0            
2260 0           $self->{SSHCHANNEL}->shell(); # Start shell on channel
2261 0 0         $self->{POLL}{blocking} = 0 if $connect->{atomic_connect}; # Restore non-blocking mode once connect complete
2262             }
2263             elsif ($self->{TYPE} eq 'SERIAL') {
2264 0 0         $connect->{handshake} = $Default{handshake} unless defined $connect->{handshake};
2265 0 0         $connect->{baudrate} = $Default{baudrate} unless defined $connect->{baudrate};
2266 0 0         $connect->{parity} = $Default{parity} unless defined $connect->{parity};
2267 0 0         $connect->{databits} = $Default{databits} unless defined $connect->{databits};
2268 0 0         $connect->{stopbits} = $Default{stopbits} unless defined $connect->{stopbits};
2269 0 0         $self->{PARENT}->handshake($connect->{handshake}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Handshake"));
2270 0 0         $self->{PARENT}->baudrate($connect->{baudrate}) or do {
2271             # If error, could be Win32::SerialPort bug https://rt.cpan.org/Ticket/Display.html?id=120068
2272 0 0 0       if ($^O eq 'MSWin32' && $connect->{forcebaud}) { # With forcebaud we can force-set the desired baudrate
2273 0           $self->{PARENT}->{"_N_BAUD"} = $connect->{baudrate};
2274             }
2275             else { # Else we come out with error
2276 0           return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Baudrate"));
2277             }
2278             };
2279 0 0         $self->{PARENT}->parity($connect->{parity}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Parity"));
2280 0 0         unless ($connect->{parity} eq 'none') { # According to Win32::SerialPort, parity_enable needs to be set when parity is not 'none'...
2281 0 0         $self->{PARENT}->parity_enable(1) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Parity_Enable"));
2282             }
2283 0 0         $self->{PARENT}->databits($connect->{databits}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort DataBits"));
2284 0 0         $self->{PARENT}->stopbits($connect->{stopbits}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort StopBits"));
2285 0 0         $self->{PARENT}->write_settings or return $self->poll_return($self->error("$pkgsub: Can't change Device_Control_Block: $^E"));
2286             #Set Read & Write buffers
2287 0 0         $self->{PARENT}->buffers($ComPortReadBuffer, 0) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Buffers"));
2288 0 0         if ($^O eq 'MSWin32') {
2289 0 0         $self->{PARENT}->read_interval($ComReadInterval) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Read_Interval"));
2290             }
2291             # Don't wait for each character
2292 0 0         defined $self->{PARENT}->read_char_time(0) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Read_Char_Time"));
2293 0           $self->{HANDSHAKE} = $connect->{handshake};
2294 0           $self->{BAUDRATE} = $connect->{baudrate};
2295 0           $self->{PARITY} = $connect->{parity};
2296 0           $self->{DATABITS} = $connect->{databits};
2297 0           $self->{STOPBITS} = $connect->{stopbits};
2298 0           $self->{SERIALEOF} = 0;
2299             }
2300             else {
2301 0           return $self->poll_return($self->error("$pkgsub: Invalid connection mode"));
2302             }
2303 0           return $self->poll_return(1);
2304             }
2305              
2306              
2307             sub poll_login { # Method to handle login for poll methods (used for both blocking & non-blocking modes)
2308 0     0 1   my $self = shift;
2309 0           my $pkgsub = shift;
2310 0           my $pollsub = "${Package}::login";
2311              
2312 0 0         unless ($self->{POLLING}) { # Sanity check
2313 0           my (undef, $fileName, $lineNumber) = caller;
2314 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
2315             }
2316              
2317 0 0         unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
2318 0           my @validArgs = ('username', 'password', 'prompt_credentials', 'prompt', 'username_prompt', 'password_prompt', 'timeout', 'errmode');
2319 0           my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
2320 0 0 0       if (@_ && !%args) { # Legacy syntax
2321             ($args{username}, $args{password}, $args{prompt}, $args{username_prompt}, $args{password_prompt},
2322 0           $args{prompt_credentials}, $args{timeout}, $args{errmode}) = @_;
2323             }
2324             # In which case we need to setup the poll structure here (the main poll structure remains unchanged)
2325             $self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
2326             # Set method argument keys
2327             username => defined $args{username} ? $args{username} : $self->{USERNAME},
2328             password => defined $args{password} ? $args{password} : $self->{PASSWORD},
2329             prompt => defined $args{prompt} ? $args{prompt} : $self->{prompt_qr},
2330             username_prompt => defined $args{username_prompt} ? $args{username_prompt} : $self->{username_prompt_qr},
2331             password_prompt => defined $args{password_prompt} ? $args{password_prompt} : $self->{password_prompt_qr},
2332             prompt_credentials => defined $args{prompt_credentials} ? $args{prompt_credentials} : $self->{prompt_credentials},
2333             # Declare method storage keys which will be used
2334             stage => 0,
2335             login_attempted => undef,
2336             # Declare keys to be set if method called from another polled method
2337             errmode => $args{errmode},
2338 0 0         };
    0          
    0          
    0          
    0          
    0          
2339             # Cache poll structure keys which this method will use
2340 0           $self->poll_struct_cache($pollsub, $args{timeout});
2341             }
2342 0           my $login = $self->{POLL}{$pollsub};
2343 0 0         local $self->{errmode} = $login->{errmode} if defined $login->{errmode};
2344 0 0         return $self->poll_return($self->error("$pkgsub: No connection to login to")) if $self->eof;
2345              
2346 0 0         if ($login->{stage} < 1) { # Initial loginstage checking - do only once
2347 0           $login->{stage}++; # Ensure we don't come back here in non-blocking mode
2348 0 0         if ($self->{LOGINSTAGE} eq 'username') { # Resume login from where it was left
    0          
2349 0 0         return $self->error("$pkgsub: Username required") unless $login->{username};
2350 0 0         $self->print(line => $login->{username}, errmode => 'return')
2351             or return $self->poll_return($self->error("$pkgsub: Unable to send username // ".$self->errmsg));
2352 0           $self->{LOGINSTAGE} = '';
2353 0           $login->{login_attempted} =1;
2354             }
2355             elsif ($self->{LOGINSTAGE} eq 'password') { # Resume login from where it was left
2356 0 0         return $self->error("$pkgsub: Password required") unless $login->{password};
2357 0 0         $self->print(line => $login->{password}, errmode => 'return')
2358             or return $self->poll_return($self->error("$pkgsub: Unable to send password // ".$self->errmsg));
2359 0           $self->{LOGINSTAGE} = '';
2360             }
2361             }
2362             # Enter login loop..
2363             do {{
2364 0           my $ok = $self->poll_read($pkgsub, 'Failed reading login prompt');
  0            
2365 0 0         return $self->poll_return($ok) unless $ok;
2366              
2367 0           $self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer}; # Login buffer can get flushed along the way
2368 0           $self->{POLL}{output_buffer} .= $self->{POLL}{read_buffer}; # This buffer preserves all the output, in case it is requested
2369              
2370 0 0         if ($self->{POLL}{local_buffer} =~ /$login->{username_prompt}/) { # Handle username prompt
2371 0 0         if ($login->{login_attempted}) {
2372 0           return $self->poll_return($self->error("$pkgsub: Incorrect Username or Password"));
2373             }
2374 0 0         unless ($login->{username}) {
2375 0 0         if ($self->{TYPE} eq 'SSH') { # If an SSH connection, we already have the username
2376 0           $login->{username} = $self->{USERNAME};
2377             }
2378             else {
2379 0 0         unless ($login->{prompt_credentials}) {
2380 0           $self->{LOGINSTAGE} = 'username';
2381 0           return $self->poll_return($self->error("$pkgsub: Username required"));
2382             }
2383 0           $login->{username} = promptCredential($login->{prompt_credentials}, 'Clear', 'Username');
2384             }
2385             }
2386 0 0         $self->print(line => $login->{username}, errmode => 'return')
2387             or return $self->poll_return($self->error("$pkgsub: Unable to send username // ".$self->errmsg));
2388 0           $self->{LOGINSTAGE} = '';
2389 0           $login->{login_attempted} =1;
2390 0           $self->{POLL}{local_buffer} = '';
2391 0           next;
2392             }
2393 0 0         if ($self->{POLL}{local_buffer} =~ /$login->{password_prompt}/) { # Handle password prompt
2394 0 0         unless (defined $login->{password}) {
2395 0 0         unless (defined $login->{prompt_credentials}) {
2396 0           $self->{LOGINSTAGE} = 'password';
2397 0           return $self->poll_return($self->error("$pkgsub: Password required"));
2398             }
2399 0           $login->{password} = promptCredential($login->{prompt_credentials}, 'Hide', 'Password');
2400             }
2401 0 0         $self->print(line => $login->{password}, errmode => 'return')
2402             or return $self->poll_return($self->error("$pkgsub: Unable to send password // ".$self->errmsg));
2403 0           $self->{LOGINSTAGE} = '';
2404 0           $self->{POLL}{local_buffer} = '';
2405 0           next;
2406             }
2407 0           }} until ($self->{POLL}{local_buffer} =~ /($login->{prompt})/);
2408 0           $self->{LASTPROMPT} = $1;
2409 0           $self->{WRITEFLAG} = 0;
2410 0 0         ($self->{USERNAME}, $self->{PASSWORD}) = ($login->{username}, $login->{password}) if $login->{login_attempted};
2411 0           return $self->poll_return(1);
2412             }
2413              
2414              
2415             sub poll_waitfor { # Method to handle waitfor for poll methods (used for both blocking & non-blocking modes)
2416 0     0 1   my $self = shift;
2417 0           my $pkgsub = shift;
2418 0           my $pollsub = "${Package}::waitfor";
2419              
2420 0 0         unless ($self->{POLLING}) { # Sanity check
2421 0           my (undef, $fileName, $lineNumber) = caller;
2422 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
2423             }
2424              
2425 0 0         unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
2426 0           my @validArgs = ('match_list', 'timeout', 'errmode');
2427 0           my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
2428 0 0 0       if (@_ && !%args) { # Legacy syntax
2429 0           ($args{match_list}, $args{timeout}, $args{errmode}) = @_;
2430             }
2431 0 0         $args{match_list} = [$args{match_list}] unless ref($args{match_list}) eq "ARRAY"; # We want it as an array reference
2432 0           my @matchArray = grep {defined} @{$args{match_list}}; # Weed out undefined values, if any
  0            
  0            
2433             # In which case we need to setup the poll structure here (the main poll structure remains unchanged)
2434             $self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
2435             # Set method argument keys
2436             matchpat => \@matchArray,
2437             # Declare method storage keys which will be used
2438             stage => 0,
2439             matchpat_qr => undef,
2440             # Declare keys to be set if method called from another polled method
2441             errmode => $args{errmode},
2442 0           };
2443             # Cache poll structure keys which this method will use
2444 0           $self->poll_struct_cache($pollsub, $args{timeout});
2445             }
2446 0           my $waitfor = $self->{POLL}{$pollsub};
2447 0 0         local $self->{errmode} = $waitfor->{errmode} if defined $waitfor->{errmode};
2448 0 0         return $self->poll_return($self->error("$pkgsub: Received eof from connection")) if $self->eof;
2449              
2450 0 0         if ($waitfor->{stage} < 1) { # 1st stage
2451 0           $waitfor->{stage}++; # Ensure we don't come back here in non-blocking mode
2452 0 0         return $self->poll_return($self->error("$pkgsub: Match pattern provided is undefined")) unless @{$waitfor->{matchpat}};
  0            
2453 0           eval { # Eval the patterns as they may be invalid
2454 0           @{$waitfor->{matchpat_qr}} = map {qr/^((?:.*\n?)*?)($_)/} @{$waitfor->{matchpat}}; # Convert match patterns into regex
  0            
  0            
  0            
2455             # This syntax did not work: qr/^([\n.]*?)($_)/
2456             };
2457 0 0         if ($@) { # If we trap an error..
2458 0           $@ =~ s/ at \S+ line .+$//s; # ..remove this module's line number
2459 0           return $self->poll_return($self->error("$pkgsub: $@"));
2460             }
2461             }
2462              
2463 0           READ: while (1) {
2464 0           my $ok = $self->poll_read($pkgsub, 'Failed waiting for output');
2465 0 0         return $self->poll_return($ok) unless $ok;
2466 0           $self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer};
2467              
2468 0           foreach my $pattern (@{$waitfor->{matchpat_qr}}) {
  0            
2469 0 0         if ($self->{POLL}{local_buffer} =~ s/$pattern//) {
2470 0           ($self->{POLL}{output_buffer}, $self->{POLL}{output_result}) = ($1, $2);
2471 0           last READ;
2472             }
2473             }
2474             }
2475 0 0         $self->{BUFFER} = $self->{POLL}{local_buffer} if length $self->{POLL}{local_buffer};
2476 0           return $self->poll_return(1);
2477             }
2478              
2479              
2480             sub poll_cmd { # Method to handle cmd for poll methods (used for both blocking & non-blocking modes)
2481 0     0 1   my $self = shift;
2482 0           my $pkgsub = shift;
2483 0           my $pollsub = "${Package}::cmd";
2484              
2485 0 0         unless ($self->{POLLING}) { # Sanity check
2486 0           my (undef, $fileName, $lineNumber) = caller;
2487 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
2488             }
2489              
2490 0 0         unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
2491 0           my @validArgs = ('command', 'prompt', 'timeout', 'errmode');
2492 0           my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
2493 0 0 0       if (@_ && !%args) { # Legacy syntax
2494 0           ($args{command}, $args{prompt}, $args{timeout}, $args{errmode}) = @_;
2495             }
2496             # In which case we need to setup the poll structure here (the main poll structure remains unchanged)
2497             $self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
2498             # Set method argument keys
2499             command => $args{command},
2500             prompt => defined $args{prompt} ? $args{prompt} : $self->{prompt_qr},
2501             # Declare method storage keys which will be used
2502             stage => 0,
2503             cmdEchoRemoved => 0,
2504             # Declare keys to be set if method called from another polled method
2505             errmode => $args{errmode},
2506 0 0         };
2507             # Cache poll structure keys which this method will use
2508 0           $self->poll_struct_cache($pollsub, $args{timeout});
2509             }
2510 0           my $cmd = $self->{POLL}{$pollsub};
2511 0 0         local $self->{errmode} = $cmd->{errmode} if defined $cmd->{errmode};
2512 0 0         return $self->poll_return($self->error("$pkgsub: No connection to send cmd to")) if $self->eof;
2513              
2514 0 0         if ($cmd->{stage} < 1) { # Send command - do only once
2515 0           $cmd->{stage}++; # Ensure we don't come back here in non-blocking mode
2516              
2517             # Flush any unread data which might be pending
2518 0           $self->read(blocking => 0);
2519              
2520             # Send the command
2521 0 0         $self->print(line => $cmd->{command}, errmode => 'return')
2522             or return $self->poll_return($self->error("$pkgsub: Unable to send CLI command: $cmd->{command} // ".$self->errmsg));
2523             }
2524              
2525             # Wait for next prompt
2526             do {
2527 0           my $ok = $self->poll_read($pkgsub, 'Failed after sending command');
2528 0 0         return $self->poll_return($ok) unless $ok;
2529              
2530 0 0         if ($cmd->{cmdEchoRemoved}) { # Initial echoed command was already removed from output
2531 0           $self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer}; # Add new output
2532 0           my $lastLine = stripLastLine(\$self->{POLL}{local_buffer}); # Remove incomplete last line if any
2533 0           $self->{POLL}{output_buffer} .= $self->{POLL}{local_buffer}; # This buffer preserves all the output
2534 0           $self->{POLL}{local_buffer} = $lastLine; # Keep incomplete lines in this buffer
2535             }
2536             else { # We have not yet received a complete line
2537 0           $self->{POLL}{local_buffer} .= $self->{POLL}{read_buffer}; # Use this buffer until we can strip the echoed command
2538 0 0         if ($self->{POLL}{local_buffer} =~ s/^.*\n//) { # We can remove initial echoed command from output
2539 0           my $lastLine = stripLastLine(\$self->{POLL}{local_buffer}); # Remove incomplete last line if any
2540 0           $self->{POLL}{output_buffer} = $self->{POLL}{local_buffer}; # Copy it across; it can now be retrieved
2541 0           $self->{POLL}{local_buffer} = $lastLine; # Keep incomplete lines in this buffer
2542 0           $cmd->{cmdEchoRemoved} = 1;
2543             }
2544             }
2545 0           } until $self->{POLL}{local_buffer} =~ s/($cmd->{prompt})//;
2546 0           $self->{LASTPROMPT} = $1;
2547 0           $self->{WRITEFLAG} = 0;
2548 0           return $self->poll_return(1);
2549             }
2550              
2551              
2552             sub poll_change_baudrate { # Method to handle change_baudrate for poll methods (used for both blocking & non-blocking modes)
2553 0     0 1   my $self = shift;
2554 0           my $pkgsub = shift;
2555 0           my $pollsub = "${Package}::change_baudrate";
2556              
2557 0 0         unless ($self->{POLLING}) { # Sanity check
2558 0           my (undef, $fileName, $lineNumber) = caller;
2559 0           croak "$pollsub (called from $fileName line $lineNumber) can only be used within polled methods";
2560             }
2561              
2562 0 0         unless (defined $self->{POLL}{$pollsub}) { # Only applicable if called from another method already in polling mode
2563 0           my @validArgs = ('baudrate', 'parity', 'databits', 'stopbits', 'handshake', 'errmode', 'forcebaud');
2564 0           my %args = parseMethodArgs($pkgsub, \@_, \@validArgs, 1);
2565 0 0 0       if (@_ && !%args) { # Legacy syntax
2566 0           ($args{baudrate}, $args{parity}, $args{databits}, $args{stopbits}, $args{handshake}, $args{errmode}) = @_;
2567             }
2568             # In which case we need to setup the poll structure here (the main poll structure remains unchanged)
2569             $self->{POLL}{$pollsub} = { # Populate structure with method arguments/storage
2570             # Set method argument keys
2571             baudrate => defined $args{baudrate} ? $args{baudrate} : $self->{BAUDRATE},
2572             parity => defined $args{parity} ? $args{parity} : $self->{PARITY},
2573             databits => defined $args{databits} ? $args{databits} : $self->{DATABITS},
2574             stopbits => defined $args{stopbits} ? $args{stopbits} : $self->{STOPBITS},
2575             handshake => defined $args{handshake} ? $args{handshake} : $self->{HANDSHAKE},
2576             forcebaud => $args{forcebaud},
2577             # Declare method storage keys which will be used
2578             stage => 0,
2579             # Declare keys to be set if method called from another polled method
2580             errmode => $args{errmode},
2581 0 0         };
    0          
    0          
    0          
    0          
2582             # Cache poll structure keys which this method will use
2583 0           $self->poll_struct_cache($pollsub);
2584             }
2585 0           my $changeBaud = $self->{POLL}{$pollsub};
2586 0 0         local $self->{errmode} = $changeBaud->{errmode} if defined $changeBaud->{errmode};
2587              
2588 0 0         return $self->poll_return($self->error("$pkgsub: Cannot change baudrate on Telnet/SSH")) unless $self->{TYPE} eq 'SERIAL';
2589 0 0         return $self->poll_return($self->error("$pkgsub: No serial connection established yet")) if $self->{SERIALEOF};
2590              
2591 0 0         if ($changeBaud->{stage} < 1) { # 1st stage
2592 0           $self->{PARENT}->write_done(1); # Needed to flush writes before closing with Device::SerialPort
2593 0           $changeBaud->{stage}++; # Move to 2nd stage
2594             }
2595 0 0         if ($changeBaud->{stage} < 2) { # 2nd stage - delay
2596 0           my $ok = $self->poll_sleep($pkgsub, $ChangeBaudDelay/1000);
2597 0 0         return $self->poll_return($ok) unless $ok;
2598 0           $changeBaud->{stage}++; # Move to next stage
2599             }
2600 0           $self->{PARENT}->close;
2601 0           $self->{SERIALEOF} = 1; # If all goes well we'll set this back to 0 on exit
2602 0 0         if ($^O eq 'MSWin32') {
2603 0 0         $self->{PARENT} = Win32::SerialPort->new($self->{COMPORT}, !($self->{debug} & 1))
2604             or return $self->poll_return($self->error("$pkgsub: Cannot re-open serial port '$self->{COMPORT}'"));
2605             }
2606             else {
2607 0 0         $self->{PARENT} = Device::SerialPort->new($self->{COMPORT}, !($self->{debug} & 1))
2608             or return $self->poll_return($self->error("$pkgsub: Cannot re-open serial port '$self->{COMPORT}'"));
2609             }
2610 0 0         $self->{PARENT}->handshake($changeBaud->{handshake}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Handshake"));
2611 0 0         $self->{PARENT}->baudrate($changeBaud->{baudrate}) or do {
2612             # If error, could be Win32::SerialPort bug https://rt.cpan.org/Ticket/Display.html?id=120068
2613 0 0 0       if ($^O eq 'MSWin32' && $changeBaud->{forcebaud}) { # With forcebaud we can force-set the desired baudrate
2614 0           $self->{PARENT}->{"_N_BAUD"} = $changeBaud->{baudrate};
2615             }
2616             else { # Else we come out with error
2617 0           return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Baudrate"));
2618             }
2619             };
2620 0 0         $self->{PARENT}->parity($changeBaud->{parity}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Parity"));
2621 0 0         unless ($changeBaud->{parity} eq 'none') { # According to Win32::SerialPort, parity_enable needs to be set when parity is not 'none'...
2622 0 0         $self->{PARENT}->parity_enable(1) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Parity_Enable"));
2623             }
2624 0 0         $self->{PARENT}->databits($changeBaud->{databits}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort DataBits"));
2625 0 0         $self->{PARENT}->stopbits($changeBaud->{stopbits}) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort StopBits"));
2626 0 0         $self->{PARENT}->write_settings or return $self->poll_return($self->error("$pkgsub: Can't change Device_Control_Block: $^E"));
2627             #Set Read & Write buffers
2628 0 0         $self->{PARENT}->buffers($ComPortReadBuffer, 0) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Buffers"));
2629 0 0         if ($^O eq 'MSWin32') {
2630 0 0         $self->{PARENT}->read_interval($ComReadInterval) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Read_Interval"));
2631             }
2632             # Don't wait for each character
2633 0 0         defined $self->{PARENT}->read_char_time(0) or return $self->poll_return($self->error("$pkgsub: Can't set SerialPort Read_Char_Time"));
2634 0           $self->{BAUDRATE} = $changeBaud->{baudrate};
2635 0           $self->{PARITY} = $changeBaud->{parity};
2636 0           $self->{DATABITS} = $changeBaud->{databits};
2637 0           $self->{STOPBITS} = $changeBaud->{stopbits};
2638 0           $self->{HANDSHAKE} = $changeBaud->{handshake};
2639 0           $self->{SERIALEOF} = 0;
2640 0           return $self->poll_return(1);
2641             }
2642              
2643              
2644             sub debugMsg { # Print a debug message
2645 0     0 1   my $self = shift;
2646 0 0         if (shift() & $self->{debug}) {
2647 0           my $string1 = shift();
2648 0   0       my $stringRef = shift() || \"";#" Ultraedit hack!
2649 0   0       my $string2 = shift() || "";
2650 0           print $string1, $$stringRef, $string2;
2651             }
2652 0           return;
2653             }
2654              
2655              
2656             ########################################## Internal Private Methods ##########################################
2657              
2658             sub _check_query { # Internal method to process Query Device Status escape sequences
2659 0     0     my ($self, $pkgsub, $bufRef) = @_;
2660 0 0         if (length $self->{QUERYBUFFER}) { # If an escape sequence fragment was cashed
2661 0           $$bufRef = join('', $self->{QUERYBUFFER}, $$bufRef); # prepend it to new output
2662 0           $self->{QUERYBUFFER} = '';
2663             }
2664 0 0         if ($$bufRef =~ /(\e(?:\[.?)?)$/){ # If output stream ends with \e, or \e[ or \e[.
2665             # We could be looking at an escape sequence fragment; we check if it partially matches $VT100_QueryDeviceStatus
2666 0           my $escFrag = $1;
2667 0 0         if ($VT100_QueryDeviceStatus =~ /^\Q$escFrag\E/){ # If it does,
2668 0           $$bufRef =~ s/\Q$escFrag\E$//; # we strip it
2669 0           $self->{QUERYBUFFER} .= $escFrag; # and cache it
2670             }
2671             }
2672 0 0         return unless $$bufRef =~ s/\Q$VT100_QueryDeviceStatus\E//go;
2673             # A Query Device Status escape sequence was found and removed from output buffer
2674 0           $self->_put($pkgsub, \$VT100_ReportDeviceOk); # Send a Report Device OK escape sequence
2675 0           return;
2676             }
2677              
2678              
2679             sub _read_buffer { # Internal method to read (and clear) any data cached in object buffer
2680 0     0     my ($self, $returnRef) = @_;
2681 0           my $buffer = $self->{BUFFER};
2682 0           $self->{BUFFER} = '';
2683             # $buffer will always be defined; worst case an empty string
2684 0 0         return $returnRef ? \$buffer : $buffer;
2685             }
2686              
2687              
2688             sub _read_blocking { # Internal read method; data must be read or we timeout
2689 0     0     my ($self, $pkgsub, $timeout, $returnRef) = @_;
2690 0           my ($buffer, $startTime);
2691              
2692 0           until (length $buffer) {
2693 0           $startTime = time; # Record start time
2694 0 0         if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
2695 0           $buffer = $self->{PARENT}->get(Timeout => $timeout);
2696 0 0         return $self->error("$pkgsub: Received eof from connection") if $self->eof;
2697 0 0         return $self->error("$pkgsub: Telnet ".$self->{PARENT}->errmsg) unless defined $buffer;
2698             }
2699             elsif ($self->{TYPE} eq 'SSH') {
2700 0 0         return $self->error("$pkgsub: No SSH channel to read from") unless defined $self->{SSHCHANNEL};
2701 0           $self->{SSHCHANNEL}->read($buffer, $self->{read_block_size});
2702 0 0 0       unless (defined $buffer && length $buffer) {
2703 0 0         return $self->error("$pkgsub: Received eof from connection") if $self->eof;
2704 0           my @poll = { handle => $self->{SSHCHANNEL}, events => ['in'] };
2705 0 0 0       unless ($self->{PARENT}->poll($timeout*1000, \@poll) && $poll[0]->{revents}->{in}) {
2706 0           return $self->error("$pkgsub: SSH read timeout");
2707             }
2708 0           my $inBytes = $self->{SSHCHANNEL}->read($buffer, $self->{read_block_size});
2709 0 0         return $self->error("$pkgsub: SSH channel read error") unless defined $inBytes;
2710             }
2711 0 0         _log_print($self->{INPUTLOGFH}, \$buffer) if defined $self->{INPUTLOGFH};
2712 0 0         _log_dump('<', $self->{DUMPLOGFH}, \$buffer) if defined $self->{DUMPLOGFH};
2713             }
2714             elsif ($self->{TYPE} eq 'SERIAL') {
2715 0 0         return $self->error("$pkgsub: Received eof from connection") if $self->{SERIALEOF};
2716 0 0         if ($^O eq 'MSWin32') { # Win32::SerialPort
2717 0           my $inBytes;
2718             # Set timeout in millisecs
2719 0     0     local $SIG{__WARN__} = sub {}; # Disable carp from Win32::SerialPort
2720 0 0         $self->{PARENT}->read_const_time($timeout == 0 ? 1 : $timeout * 1000) or do {
    0          
2721 0           $self->{PARENT}->close;
2722 0           $self->{SERIALEOF} = 1;
2723 0           return $self->error("$pkgsub: Unable to read serial port");
2724             };
2725 0           ($inBytes, $buffer) = $self->{PARENT}->read($self->{read_block_size});
2726 0 0         return $self->error("$pkgsub: Serial Port read timeout") unless $inBytes;
2727             }
2728             else { # Device::SerialPort; we handle polling ourselves
2729             # Wait defined millisecs during every read
2730 0 0         $self->{PARENT}->read_const_time($PollTimer) or do {
2731 0           $self->{PARENT}->close;
2732 0           $self->{SERIALEOF} = 1;
2733 0           return $self->error("$pkgsub: Unable to read serial port");
2734             };
2735 0           my $inBytes;
2736 0           my $ticks = 0;
2737 0           my $ticksTimeout = $timeout*$PollTimer/10;
2738 0           do {
2739 0 0         if ($ticks++ > $ticksTimeout) {
2740 0           return $self->error("$pkgsub: Serial port read timeout");
2741             }
2742 0           ($inBytes, $buffer) = $self->{PARENT}->read($self->{read_block_size});
2743             } until $inBytes > 0;
2744             }
2745 0 0         _log_print($self->{INPUTLOGFH}, \$buffer) if defined $self->{INPUTLOGFH};
2746 0 0         _log_dump('<', $self->{DUMPLOGFH}, \$buffer) if defined $self->{DUMPLOGFH};
2747             }
2748             else {
2749 0           return $self->error("$pkgsub: Invalid connection mode");
2750             }
2751             # Check for Query Device Status escape sequences and process a reply if necessary
2752 0 0         if ($self->{report_query_status}){
2753 0           $self->_check_query($pkgsub, \$buffer);
2754 0 0         unless (length $buffer) { # If buffer was just a Query Device Status escape sequence we now have an empty buffer
2755 0           $timeout -= (time - $startTime); # Re-calculate a reduced timeout value, to perform next read cycle
2756 0 0         return $self->error("$pkgsub: Read timeout with report_query_status active") if $timeout <= 0;
2757             }
2758             }
2759             }
2760             # $buffer should always be a defined, non-empty string
2761 0 0         return $returnRef ? \$buffer : $buffer;
2762             }
2763              
2764              
2765             sub _read_nonblocking { # Internal read method; if no data available return immediately
2766 0     0     my ($self, $pkgsub, $returnRef) = @_;
2767 0           my $buffer;
2768              
2769 0 0         if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
2770 0           $buffer = $self->{PARENT}->get(Timeout => 0);
2771 0 0         return $self->error("$pkgsub: Received eof from connection") if $self->eof;
2772 0 0         $buffer = '' unless defined $buffer;
2773             }
2774             elsif ($self->{TYPE} eq 'SSH') {
2775 0 0         return $self->error("$pkgsub: No SSH channel to read from") unless defined $self->{SSHCHANNEL};
2776 0           $self->{SSHCHANNEL}->read($buffer, $self->{read_block_size});
2777             # With Net::SSH2 0.58 & libssh2 1.5.0 line below was not necessary, as an emty read would leave $buffer defined and empty
2778             # But with Net::SSH2 0.63 & libssh2 1.7.0 this is no longer the case; now an empty read returns undef as both method return value and $buffer
2779 0 0         $buffer = '' unless defined $buffer;
2780 0 0         if (length $buffer) {
2781 0 0         _log_print($self->{INPUTLOGFH}, \$buffer) if defined $self->{INPUTLOGFH};
2782 0 0         _log_dump('<', $self->{DUMPLOGFH}, \$buffer) if defined $self->{DUMPLOGFH};
2783             }
2784             }
2785             elsif ($self->{TYPE} eq 'SERIAL') {
2786 0 0         return $self->error("$pkgsub: Received eof from connection") if $self->{SERIALEOF};
2787 0           my $inBytes;
2788 0     0     local $SIG{__WARN__} = sub {}; # Disable carp from Win32::SerialPort
2789             # Set timeout to nothing (1ms; Win32::SerialPort does not like 0)
2790 0 0         $self->{PARENT}->read_const_time(1) or do {
2791 0           $self->{PARENT}->close;
2792 0           $self->{SERIALEOF} = 1;
2793 0           return $self->error("$pkgsub: Unable to read serial port");
2794             };
2795 0           ($inBytes, $buffer) = $self->{PARENT}->read($self->{read_block_size});
2796 0 0         return $self->error("$pkgsub: Serial port read error") unless defined $buffer;
2797 0 0         if (length $buffer) {
2798 0 0         _log_print($self->{INPUTLOGFH}, \$buffer) if defined $self->{INPUTLOGFH};
2799 0 0         _log_dump('<', $self->{DUMPLOGFH}, \$buffer) if defined $self->{DUMPLOGFH};
2800             }
2801             }
2802             else {
2803 0           return $self->error("$pkgsub: Invalid connection mode");
2804             }
2805             # Check for Query Device Status escape sequences and process a reply if necessary
2806 0 0 0       $self->_check_query($pkgsub, \$buffer) if length $buffer && $self->{report_query_status};
2807              
2808             # Pre-pend local buffer if not empty
2809 0 0         $buffer = join('', $self->_read_buffer(0), $buffer) if length $self->{BUFFER};
2810              
2811             # If nothing was read, $buffer should be a defined, empty string
2812 0 0         return $returnRef ? \$buffer : $buffer;
2813             }
2814              
2815              
2816             sub _put { # Internal write method
2817 0     0     my ($self, $pkgsub, $outref) = @_;
2818              
2819 0 0         return $self->error("$pkgsub: No connection to write to") if $self->eof;
2820              
2821 0 0         if ($self->{TYPE} eq 'TELNET') {
    0          
    0          
2822             $self->{PARENT}->put(
2823             String => $$outref,
2824             Telnetmode => $self->{TELNETMODE},
2825 0 0         ) or return $self->error("$pkgsub: Telnet ".$self->{PARENT}->errmsg);
2826             }
2827             elsif ($self->{TYPE} eq 'SSH') {
2828 0 0         return $self->error("$pkgsub: No SSH channel to write to") unless defined $self->{SSHCHANNEL};
2829 0           print {$self->{SSHCHANNEL}} $$outref;
  0            
2830 0 0         _log_print($self->{OUTPUTLOGFH}, $outref) if defined $self->{OUTPUTLOGFH};
2831 0 0         _log_dump('>', $self->{DUMPLOGFH}, $outref) if defined $self->{DUMPLOGFH};
2832             }
2833             elsif ($self->{TYPE} eq 'SERIAL') {
2834 0           my $countOut = $self->{PARENT}->write($$outref);
2835 0 0         return $self->error("$pkgsub: Serial port write failed") unless $countOut;
2836 0 0         return $self->error("$pkgsub: Serial port write incomplete") if $countOut != length($$outref);
2837 0 0         _log_print($self->{OUTPUTLOGFH}, $outref) if defined $self->{OUTPUTLOGFH};
2838 0 0         _log_dump('>', $self->{DUMPLOGFH}, $outref) if defined $self->{DUMPLOGFH};
2839             }
2840             else {
2841 0           return $self->error("$pkgsub: Invalid connection mode");
2842             }
2843 0           $self->{WRITEFLAG} = 1;
2844 0           return 1;
2845             }
2846              
2847              
2848             sub _log_print { # Print output to log file (input, output or dump); taken from Net::Telnet
2849 0     0     my ($fh, $dataRef) = @_;
2850              
2851 0           local $\ = '';
2852 0 0 0       if (ref($fh) and ref($fh) ne "GLOB") { # fh is blessed ref
2853 0           $fh->print($$dataRef);
2854             }
2855             else { # fh isn't blessed ref
2856 0           print $fh $$dataRef;
2857             }
2858 0           return 1;
2859             }
2860              
2861              
2862             sub _log_dump { # Dump log procedure; copied and modified directly from Net::Telnet for use with SSH/Serial access
2863 0     0     my ($direction, $fh, $dataRef) = @_;
2864 0           my ($hexvals, $line);
2865 0           my ($addr, $offset) = (0, 0);
2866 0           my $len = length($$dataRef);
2867              
2868             # Print data in dump format.
2869 0           while ($len > 0) { # Convert up to the next 16 chars to hex, padding w/ spaces.
2870 0 0         if ($len >= 16) {
2871 0           $line = substr($$dataRef, $offset, 16);
2872             }
2873             else {
2874 0           $line = substr($$dataRef, $offset, $len);
2875             }
2876 0           $hexvals = unpack("H*", $line);
2877 0           $hexvals .= ' ' x (32 - length $hexvals);
2878              
2879             # Place in 16 columns, each containing two hex digits.
2880 0           $hexvals = sprintf("%s %s %s %s " x 4, unpack("a2" x 16, $hexvals));
2881              
2882             # For the ASCII column, change unprintable chars to a period.
2883 0           $line =~ s/[\000-\037,\177-\237]/./g;
2884              
2885             # Print the line in dump format.
2886 0           _log_print($fh, \sprintf("%s 0x%5.5lx: %s%s\n", $direction, $addr, $hexvals, $line));
2887              
2888 0           $addr += 16;
2889 0           $offset += 16;
2890 0           $len -= 16;
2891             }
2892 0 0         _log_print($fh, \"\n") if $$dataRef;#" Ultraedit hack!
2893 0           return 1;
2894             }
2895              
2896              
2897             sub _error_format { # Format the error message
2898 0     0     my ($msgFormat, $errmsg) = @_;
2899              
2900 0 0         return ucfirst $errmsg if $msgFormat =~ /^\s*verbose\s*$/i;
2901 0           $errmsg =~ s/\s+\/\/\s+.*$//;
2902 0 0 0       return ucfirst $errmsg if $msgFormat =~ /^\s*default\s*$/i || $msgFormat !~ /^\s*terse\s*$/i;
2903 0           $errmsg =~ s/^(?:[^:]+::)+[^:]+:\s+//;
2904 0           return ucfirst $errmsg; # terse
2905             }
2906              
2907              
2908             sub _error { # Internal method to perfom error mode action
2909 0     0     my ($fileName, $lineNumber, $mode, $errmsg, $msgFormat) = @_;
2910              
2911 0           $errmsg = _error_format($msgFormat, $errmsg);
2912              
2913 0 0         if (defined $mode) {
2914 0 0         if (ref($mode)) {
2915 0           callCodeRef($mode, $errmsg);
2916 0           return;
2917             }
2918 0 0         return if $mode eq 'return';
2919 0 0         croak "\n$errmsg" if $mode eq 'croak';
2920 0 0         die "\n$errmsg at $fileName line $lineNumber\n" if $mode eq 'die';
2921             }
2922             # Else (should never happen..)
2923 0           croak "\nInvalid errmode! Defaulting to croak\n$errmsg";
2924             }
2925              
2926              
2927             sub _call_poll_method { # Call object's poll method and optionally alter and then restore its error mode in doing so
2928 0     0     my ($self, $timeCredit, $errmode) = @_;
2929 0           my $errmodecache;
2930              
2931 0 0         unless ($self->{POLLREPORTED}) {
2932 0 0         if (defined $errmode) { # Store object's poll errormode and replace it with new error mode
2933 0           $errmodecache = $self->{POLL}{errmode};
2934 0           $self->{POLL}{errmode} = $errmode;
2935             }
2936 0 0 0       if ($timeCredit > 0 && defined $self->{POLL}{endtime}) { # We are going to increase the object's timeout by a credit amount
2937 0           $self->{POLL}{endtime} = $self->{POLL}{endtime} + $timeCredit;
2938 0           $self->debugMsg(1," - Timeout Credit of : ", \$timeCredit, " seconds\n");
2939             }
2940 0 0         $self->debugMsg(1," - Timeout Remaining : ", \($self->{POLL}{endtime} - time), " seconds\n") if defined $self->{POLL}{endtime};
2941             }
2942              
2943             # Call object's poll method
2944 0           my $ok = $self->{POLL}{coderef}->($self);
2945              
2946 0 0         unless ($self->{POLLREPORTED}) {
2947 0 0         $self->debugMsg(1," - Error: ", \$self->errmsg, "\n") unless defined $ok;
2948             # Restore original object poll error mode if necessary
2949 0 0         $self->{POLL}{errmode} = $errmodecache if defined $errmode;
2950             }
2951 0           return $ok;
2952             }
2953              
2954              
2955             sub _setup_telnet_option { # Sets up specified telnet option
2956 0     0     my ($self, $telobj, $option) = @_;
2957              
2958 0           $self->{PARENT}->option_accept(Do => $option);
2959 0           my $telcmd = "\377\373" . pack("C", $option); # will command
2960 0           $telobj->{unsent_opts} .= $telcmd;
2961 0 0 0       Net::Telnet::_log_option($telobj->{opt_log}, "SENT", "Will", $option) if defined &Net::Telnet::_log_option && $telobj->{opt_log};
2962 0           $self->debugMsg(1,"Telnet Option ", \$Net::Telnet::Telopts[$option], " Accept-Do + Send-Will\n");
2963 0           return;
2964             }
2965              
2966              
2967             sub _handle_telnet_options { # Sets up telnet options if we need them
2968 0     0     my $self = shift;
2969 0           my $telobj = *{$self->{PARENT}}->{net_telnet};
  0            
2970              
2971 0 0         _setup_telnet_option($self, $telobj, &TELOPT_TTYPE) if defined $self->{terminal_type}; # Only if a terminal type set for object
2972 0 0         _setup_telnet_option($self, $telobj, &TELOPT_NAWS) if @{$self->{window_size}}; # Only if a window size set for object
  0            
2973              
2974             # Send WILL for options now
2975 0 0 0       Net::Telnet::_flush_opts($self->{PARENT}) if defined &Net::Telnet::_flush_opts && length $telobj->{unsent_opts};
2976 0           return;
2977             }
2978              
2979             sub _telnet_opt_callback { # This is the callback setup for dealing with Telnet option negotiation
2980 0     0     my ($telslf, $option, $is_remote, $is_enabled, $was_enabled, $opt_bufpos) = @_;
2981 0           my $telobj = *$telslf->{net_telnet};
2982 0           my $self = $telobj->{$Package}; # Retrieve our object that we planted within the Net::Telnet one
2983              
2984 0 0 0       if ($option == &TELOPT_NAWS && @{$self->{window_size}}) {
  0            
2985 0           my $telcmd = pack("C9", &TELNET_IAC, &TELNET_SB, &TELOPT_NAWS, 0, $self->{window_size}->[0], 0, $self->{window_size}->[1], &TELNET_IAC, &TELNET_SE);
2986             # We activated option_accept for TELOPT_NAWS, so Net::Telnet queues a WILL response; but we already sent a Will in _setup_telnet_option
2987 0           my $telrmv = pack("C3", &TELNET_IAC, &TELNET_WILL, &TELOPT_NAWS);
2988 0           $telobj->{unsent_opts} =~ s/$telrmv/$telcmd/; # So replace WILL response queued by Net::Telnet with our SB response
2989 0 0 0       if (defined &Net::Telnet::_log_option && $telobj->{opt_log}) { # Net::Telnet already added a SENT WILL in the option log, so rectify
2990 0           Net::Telnet::_log_option($telobj->{opt_log}, "Not-SENT", "WILL", $option) ;
2991 0           Net::Telnet::_log_option($telobj->{opt_log}, "Instead-SENT(".join(' x ', @{$self->{window_size}}).")", "SB", $option);
  0            
2992             }
2993 0           $self->debugMsg(1,"Telnet Option Callback TELOPT_NAWS; sending sub-option negotiation ", \join(' x ', @{$self->{window_size}}), "\n");
  0            
2994             }
2995 0           return 1;
2996             }
2997              
2998              
2999             sub _telnet_subopt_callback { # This is the callback setup for dealing with Telnet sub-option negotiation
3000 0     0     my ($telslf, $option, $parameters) = @_;
3001 0           my $telobj = *$telslf->{net_telnet};
3002 0           my $self = $telobj->{$Package}; # Retrieve our object that we planted within the Net::Telnet one
3003              
3004             # Integrate with Net::Telnet's option_log
3005 0 0 0       Net::Telnet::_log_option($telobj->{opt_log}, "RCVD", "SB", $option) if defined &Net::Telnet::_log_option && $telobj->{opt_log};
3006              
3007             # Terminal type
3008 0 0 0       if ($option == &TELOPT_TTYPE && defined $self->{terminal_type}) {
3009 0           my $telcmd = pack("C4 A* C2", &TELNET_IAC, &TELNET_SB, &TELOPT_TTYPE, 0, $self->{terminal_type}, &TELNET_IAC, &TELNET_SE);
3010 0           $telobj->{unsent_opts} .= $telcmd;
3011 0 0 0       Net::Telnet::_log_option($telobj->{opt_log}, "SENT($self->{terminal_type})", "SB", $option) if defined &Net::Telnet::_log_option && $telobj->{opt_log};
3012 0           $self->debugMsg(1,"Telnet SubOption Callback TELOPT_TTYPE; sending ", \$self->{terminal_type}, "\n");
3013             }
3014             # Window Size
3015 0 0 0       if ($option == &TELOPT_NAWS && @{$self->{window_size}}) {
  0            
3016 0           my $telcmd = pack("C9", &TELNET_IAC, &TELNET_SB, &TELOPT_NAWS, 0, $self->{window_size}->[0], 0, $self->{window_size}->[1], &TELNET_IAC, &TELNET_SE);
3017 0           $telobj->{unsent_opts} .= $telcmd;
3018 0 0 0       Net::Telnet::_log_option($telobj->{opt_log}, "SENT(".join(' x ', @{$self->{window_size}}).")", "SB", $option) if defined &Net::Telnet::_log_option && $telobj->{opt_log};
  0            
3019 0           $self->debugMsg(1,"Telnet SubOption Callback TELOPT_NAWS; sending ", \join(' x ', @{$self->{window_size}}), "\n");
  0            
3020             }
3021 0           return 1;
3022             }
3023              
3024              
3025             1;
3026             __END__;