File Coverage

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


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