File Coverage

blib/lib/Net/Telnet.pm
Criterion Covered Total %
statement 55 1522 3.6
branch 0 930 0.0
condition 0 168 0.0
subroutine 17 123 13.8
pod 50 53 94.3
total 122 2796 4.3


line stmt bran cond sub pod time code
1             package Net::Telnet;
2              
3             ## Copyright 1997, 2000, 2002, 2013 Jay Rogers. All rights reserved.
4             ## This program is free software; you can redistribute it and/or
5             ## modify it under the same terms as Perl itself.
6              
7             ## See user documentation at the end of this file. Search for =head
8              
9 1     1   75033 use strict;
  1         3  
  1         37  
10             require 5.002;
11              
12             ## Module export.
13 1     1   6 use vars qw(@EXPORT_OK);
  1         2  
  1         105  
14             @EXPORT_OK = qw(TELNET_IAC TELNET_DONT TELNET_DO TELNET_WONT TELNET_WILL
15             TELNET_SB TELNET_GA TELNET_EL TELNET_EC TELNET_AYT TELNET_AO
16             TELNET_IP TELNET_BREAK TELNET_DM TELNET_NOP TELNET_SE
17             TELNET_EOR TELNET_ABORT TELNET_SUSP TELNET_EOF TELNET_SYNCH
18             TELOPT_BINARY TELOPT_ECHO TELOPT_RCP TELOPT_SGA TELOPT_NAMS
19             TELOPT_STATUS TELOPT_TM TELOPT_RCTE TELOPT_NAOL TELOPT_NAOP
20             TELOPT_NAOCRD TELOPT_NAOHTS TELOPT_NAOHTD TELOPT_NAOFFD
21             TELOPT_NAOVTS TELOPT_NAOVTD TELOPT_NAOLFD TELOPT_XASCII
22             TELOPT_LOGOUT TELOPT_BM TELOPT_DET TELOPT_SUPDUP
23             TELOPT_SUPDUPOUTPUT TELOPT_SNDLOC TELOPT_TTYPE TELOPT_EOR
24             TELOPT_TUID TELOPT_OUTMRK TELOPT_TTYLOC TELOPT_3270REGIME
25             TELOPT_X3PAD TELOPT_NAWS TELOPT_TSPEED TELOPT_LFLOW
26             TELOPT_LINEMODE TELOPT_XDISPLOC TELOPT_OLD_ENVIRON
27             TELOPT_AUTHENTICATION TELOPT_ENCRYPT TELOPT_NEW_ENVIRON
28             TELOPT_TN3270E TELOPT_CHARSET TELOPT_COMPORT TELOPT_KERMIT
29             TELOPT_EXOPL);
30              
31             ## Module import.
32 1     1   513 use IO::Socket::INET;
  1         22114  
  1         10  
33 1     1   447 use IO::Handle;
  1         4  
  1         31  
34 1     1   5 use Exporter ();
  1         2  
  1         32  
35 1     1   6 use Socket qw(AF_INET SOCK_STREAM inet_aton sockaddr_in);
  1         1  
  1         187  
36 1     1   7 use Symbol qw(qualify);
  1         2  
  1         66  
37              
38             ## Base classes.
39 1     1   448 use parent qw/ Exporter IO::Socket::INET /;
  1         293  
  1         5  
40              
41             my $AF_INET6 = &_import_af_inet6();
42             my $AF_UNSPEC = &_import_af_unspec() || 0;
43             my $AI_ADDRCONFIG = &_import_ai_addrconfig() || 0;
44             my $EAI_BADFLAGS = &_import_eai_badflags() || -1;
45             my $EINTR = &_import_eintr();
46              
47             ## Global variables.
48 1     1   130 use vars qw($VERSION @Telopts);
  1         2  
  1         2436  
49             $VERSION = "3.04_01";
50             @Telopts = ("BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAMS", "STATUS",
51             "TIMING MARK", "RCTE", "NAOL", "NAOP", "NAOCRD", "NAOHTS",
52             "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD", "NAOLFD", "EXTEND ASCII",
53             "LOGOUT", "BYTE MACRO", "DATA ENTRY TERMINAL", "SUPDUP",
54             "SUPDUP OUTPUT", "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD",
55             "TACACS UID", "OUTPUT MARKING", "TTYLOC", "3270 REGIME", "X.3 PAD",
56             "NAWS", "TSPEED", "LFLOW", "LINEMODE", "XDISPLOC", "OLD-ENVIRON",
57             "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON", "TN3270E", "XAUTH",
58             "CHARSET", "RSP", "COMPORT", "SUPPRESS LOCAL ECHO", "START TLS",
59             "KERMIT");
60              
61              
62             ########################### Public Methods ###########################
63              
64              
65             sub new {
66 0     0 1 0 my ($class) = @_;
67             my (
68 0         0 $dump_log,
69             $errmode,
70             $family,
71             $fh_open,
72             $host,
73             $input_log,
74             $localfamily,
75             $option_log,
76             $output_log,
77             $port,
78             $prompt,
79             $self,
80             %args,
81             );
82 0         0 local $_;
83              
84             ## Create a new object with defaults.
85 0         0 $self = $class->SUPER::new;
86             *$self->{net_telnet} = {
87 0         0 bin_mode => 0,
88             blksize => &_optimal_blksize(),
89             buf => "",
90             cmd_prompt => '/[\$%#>] $/',
91             cmd_rm_mode => "auto",
92             dumplog => '',
93             eofile => 1,
94             errormode => "die",
95             errormsg => "",
96             fdmask => '',
97             host => "localhost",
98             inputlog => '',
99             last_line => "",
100             last_prompt => "",
101             local_family => "ipv4",
102             local_host => "",
103             maxbufsize => 1_048_576,
104             num_wrote => 0,
105             ofs => "",
106             opened => '',
107             opt_cback => '',
108             opt_log => '',
109             opts => {},
110             ors => "\n",
111             outputlog => '',
112             peer_family => "ipv4",
113             pending_errormsg => "",
114             port => 23,
115             pushback_buf => "",
116             rs => "\n",
117             select_supported => 1,
118             sock_family => 0,
119             subopt_cback => '',
120             telnet_mode => 1,
121             time_out => 10,
122             timedout => '',
123             unsent_opts => "",
124             };
125              
126             ## Indicate that we'll accept an offer from remote side for it to echo
127             ## and suppress go aheads.
128 0         0 &_opt_accept($self,
129             { option => &TELOPT_ECHO,
130             is_remote => 1,
131             is_enable => 1 },
132             { option => &TELOPT_SGA,
133             is_remote => 1,
134             is_enable => 1 },
135             );
136              
137             ## Parse the args.
138 0 0       0 if (@_ == 2) { # one positional arg given
    0          
139 0         0 $host = $_[1];
140             }
141             elsif (@_ > 2) { # named args given
142             ## Get the named args.
143 0         0 (undef, %args) = @_;
144              
145             ## Parse all other named args.
146 0         0 foreach (keys %args) {
147 0 0 0     0 if (/^-?binmode$/i) {
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
148 0         0 $self->binmode($args{$_});
149             }
150             elsif (/^-?cmd_remove_mode$/i) {
151 0         0 $self->cmd_remove_mode($args{$_});
152             }
153             elsif (/^-?dump_log$/i) {
154 0         0 $dump_log = $args{$_};
155             }
156             elsif (/^-?errmode$/i) {
157 0         0 $errmode = $args{$_};
158             }
159             elsif (/^-?family$/i) {
160 0         0 $family = $args{$_};
161             }
162             elsif (/^-?fhopen$/i) {
163 0         0 $fh_open = $args{$_};
164             }
165             elsif (/^-?host$/i) {
166 0         0 $host = $args{$_};
167             }
168             elsif (/^-?input_log$/i) {
169 0         0 $input_log = $args{$_};
170             }
171             elsif (/^-?input_record_separator$/i or /^-?rs$/i) {
172 0         0 $self->input_record_separator($args{$_});
173             }
174             elsif (/^-?localfamily$/i) {
175 0         0 $localfamily = $args{$_};
176             }
177             elsif (/^-?localhost$/i) {
178 0         0 $self->localhost($args{$_});
179             }
180             elsif (/^-?max_buffer_length$/i) {
181 0         0 $self->max_buffer_length($args{$_});
182             }
183             elsif (/^-?option_log$/i) {
184 0         0 $option_log = $args{$_};
185             }
186             elsif (/^-?output_field_separator$/i or /^-?ofs$/i) {
187 0         0 $self->output_field_separator($args{$_});
188             }
189             elsif (/^-?output_log$/i) {
190 0         0 $output_log = $args{$_};
191             }
192             elsif (/^-?output_record_separator$/i or /^-?ors$/i) {
193 0         0 $self->output_record_separator($args{$_});
194             }
195             elsif (/^-?port$/i) {
196 0         0 $port = $args{$_};
197             }
198             elsif (/^-?prompt$/i) {
199 0         0 $prompt = $args{$_};
200             }
201             elsif (/^-?telnetmode$/i) {
202 0         0 $self->telnetmode($args{$_});
203             }
204             elsif (/^-?timeout$/i) {
205 0         0 $self->timeout($args{$_});
206             }
207             else {
208 0         0 &_croak($self, "bad named parameter \"$_\" given " .
209             "to " . ref($self) . "::new()");
210             }
211             }
212             }
213              
214 0 0       0 if (defined $errmode) { # user wants to set errmode
215 0         0 $self->errmode($errmode);
216             }
217              
218 0 0       0 if (defined $host) { # user wants to set host
219 0         0 $self->host($host);
220             }
221              
222 0 0       0 if (defined $port) { # user wants to set port
223 0 0       0 $self->port($port)
224             or return;
225             }
226              
227 0 0       0 if (defined $family) { # user wants to set family
228 0 0       0 $self->family($family)
229             or return;
230             }
231              
232 0 0       0 if (defined $localfamily) { # user wants to set localfamily
233 0 0       0 $self->localfamily($localfamily)
234             or return;
235             }
236              
237 0 0       0 if (defined $prompt) { # user wants to set prompt
238 0 0       0 $self->prompt($prompt)
239             or return;
240             }
241              
242 0 0       0 if (defined $dump_log) { # user wants to set dump_log
243 0 0       0 $self->dump_log($dump_log)
244             or return;
245             }
246              
247 0 0       0 if (defined $input_log) { # user wants to set input_log
248 0 0       0 $self->input_log($input_log)
249             or return;
250             }
251              
252 0 0       0 if (defined $option_log) { # user wants to set option_log
253 0 0       0 $self->option_log($option_log)
254             or return;
255             }
256              
257 0 0       0 if (defined $output_log) { # user wants to set output_log
258 0 0       0 $self->output_log($output_log)
259             or return;
260             }
261              
262 0 0       0 if (defined $fh_open) { # user wants us to attach to existing filehandle
    0          
263 0 0       0 $self->fhopen($fh_open)
264             or return;
265             }
266             elsif (defined $host) { # user wants us to open a connection to host
267 0 0       0 $self->open
268             or return;
269             }
270              
271 0         0 $self;
272             } # end sub new
273              
274              
275       0     sub DESTROY {
276             } # end sub DESTROY
277              
278              
279             sub binmode {
280 0     0 1 0 my ($self, $mode) = @_;
281             my (
282 0         0 $prev,
283             $s,
284             );
285              
286 0         0 $s = *$self->{net_telnet};
287 0         0 $prev = $s->{bin_mode};
288              
289 0 0       0 if (@_ >= 2) {
290 0 0       0 unless (defined $mode) {
291 0         0 $mode = 0;
292             }
293              
294 0         0 $s->{bin_mode} = $mode;
295             }
296              
297 0         0 $prev;
298             } # end sub binmode
299              
300              
301             sub break {
302 0     0 1 0 my ($self) = @_;
303 0         0 my $s = *$self->{net_telnet};
304 0         0 my $break_cmd = "\xff\xf3";
305              
306 0         0 $s->{timedout} = '';
307              
308 0         0 &_put($self, \$break_cmd, "break");
309             } # end sub break
310              
311              
312             sub buffer {
313 0     0 1 0 my ($self) = @_;
314 0         0 my $s = *$self->{net_telnet};
315              
316 0         0 \$s->{buf};
317             } # end sub buffer
318              
319              
320             sub buffer_empty {
321 0     0 1 0 my ($self) = @_;
322             my (
323 0         0 $buffer,
324             );
325              
326 0         0 $buffer = $self->buffer;
327 0         0 $$buffer = "";
328             } # end sub buffer_empty
329              
330              
331             sub close {
332 0     0 1 0 my ($self) = @_;
333 0         0 my $s = *$self->{net_telnet};
334              
335 0         0 $s->{eofile} = 1;
336 0         0 $s->{opened} = '';
337 0         0 $s->{sock_family} = 0;
338 0 0       0 close $self
339             if defined fileno($self);
340              
341 0         0 1;
342             } # end sub close
343              
344              
345             sub cmd {
346 0     0 1 0 my ($self, @args) = @_;
347             my (
348 0         0 $arg_errmode,
349             $cmd_remove_mode,
350             $firstpos,
351             $last_prompt,
352             $lastpos,
353             $lines,
354             $ors,
355             $output,
356             $output_ref,
357             $prompt,
358             $remove_echo,
359             $rs,
360             $rs_len,
361             $s,
362             $telopt_echo,
363             $timeout,
364             %args,
365             );
366 0         0 my $cmd = "";
367 0         0 local $_;
368              
369             ## Init.
370 0         0 $self->timed_out('');
371 0         0 $self->last_prompt("");
372 0         0 $s = *$self->{net_telnet};
373 0         0 $output = [];
374 0         0 $cmd_remove_mode = $self->cmd_remove_mode;
375 0         0 $ors = $self->output_record_separator;
376 0         0 $prompt = $self->prompt;
377 0         0 $rs = $self->input_record_separator;
378 0         0 $timeout = $self->timeout;
379              
380             ## Override errmode first, if specified.
381 0         0 $arg_errmode = &_extract_arg_errmode($self, \@args);
382 0 0       0 local $s->{errormode} = $arg_errmode
383             if $arg_errmode;
384              
385             ## Parse args.
386 0 0       0 if (@args == 1) { # one positional arg given
    0          
387 0         0 $cmd = $args[0];
388             }
389             elsif (@args >= 2) { # named args given
390             ## Get the named args.
391 0         0 %args = @args;
392              
393             ## Parse the named args.
394 0         0 foreach (keys %args) {
395 0 0 0     0 if (/^-?cmd_remove/i) {
    0 0        
    0          
    0          
    0          
    0          
    0          
396 0         0 $cmd_remove_mode = &_parse_cmd_remove_mode($self, $args{$_});
397             }
398             elsif (/^-?input_record_separator$/i or /^-?rs$/i) {
399 0         0 $rs = &_parse_input_record_separator($self, $args{$_});
400             }
401             elsif (/^-?output$/i) {
402 0         0 $output_ref = $args{$_};
403 0 0 0     0 if (defined($output_ref) and ref($output_ref) eq "ARRAY") {
404 0         0 $output = $output_ref;
405             }
406             }
407             elsif (/^-?output_record_separator$/i or /^-?ors$/i) {
408 0         0 $ors = $args{$_};
409             }
410             elsif (/^-?prompt$/i) {
411 0 0       0 $prompt = &_parse_prompt($self, $args{$_})
412             or return;
413             }
414             elsif (/^-?string$/i) {
415 0         0 $cmd = $args{$_};
416             }
417             elsif (/^-?timeout$/i) {
418 0         0 $timeout = &_parse_timeout($self, $args{$_});
419             }
420             else {
421 0         0 &_croak($self, "bad named parameter \"$_\" given " .
422             "to " . ref($self) . "::cmd()");
423             }
424             }
425             }
426              
427             ## Override some user settings.
428 0         0 local $s->{time_out} = &_endtime($timeout);
429 0         0 $self->errmsg("");
430              
431             ## Send command and wait for the prompt.
432             {
433 0         0 local $s->{errormode} = "return";
  0         0  
434              
435 0 0       0 $self->put($cmd . $ors)
436             and ($lines, $last_prompt) = $self->waitfor($prompt);
437             }
438              
439             ## Check for failure.
440 0 0       0 return $self->error("command timed-out") if $self->timed_out;
441 0 0       0 return $self->error($self->errmsg) if $self->errmsg ne "";
442              
443             ## Save the most recently matched prompt.
444 0         0 $self->last_prompt($last_prompt);
445              
446             ## Split lines into an array, keeping record separator at end of line.
447 0         0 $firstpos = 0;
448 0         0 $rs_len = length $rs;
449 0         0 while (($lastpos = index($lines, $rs, $firstpos)) > -1) {
450 0         0 push(@$output,
451             substr($lines, $firstpos, $lastpos - $firstpos + $rs_len));
452 0         0 $firstpos = $lastpos + $rs_len;
453             }
454              
455 0 0       0 if ($firstpos < length $lines) {
456 0         0 push @$output, substr($lines, $firstpos);
457             }
458              
459             ## Determine if we should remove the first line of output based
460             ## on the assumption that it's an echoed back command.
461 0 0       0 if ($cmd_remove_mode eq "auto") {
462             ## See if remote side told us they'd echo.
463 0         0 $telopt_echo = $self->option_state(&TELOPT_ECHO);
464 0         0 $remove_echo = $telopt_echo->{remote_enabled};
465             }
466             else { # user explicitly told us how many lines to remove.
467 0         0 $remove_echo = $cmd_remove_mode;
468             }
469              
470             ## Get rid of possible echo back command.
471 0         0 while ($remove_echo--) {
472 0         0 shift @$output;
473             }
474              
475             ## Ensure at least a null string when there's no command output - so
476             ## "true" is returned in a list context.
477 0 0       0 unless (@$output) {
478 0         0 @$output = ("");
479             }
480              
481             ## Return command output via named arg, if requested.
482 0 0       0 if (defined $output_ref) {
483 0 0       0 if (ref($output_ref) eq "SCALAR") {
    0          
484 0         0 $$output_ref = join "", @$output;
485             }
486             elsif (ref($output_ref) eq "HASH") {
487 0         0 %$output_ref = @$output;
488             }
489             }
490              
491 0 0       0 wantarray ? @$output : 1;
492             } # end sub cmd
493              
494              
495             sub cmd_remove_mode {
496 0     0 1 0 my ($self, $mode) = @_;
497             my (
498 0         0 $prev,
499             $s,
500             );
501              
502 0         0 $s = *$self->{net_telnet};
503 0         0 $prev = $s->{cmd_rm_mode};
504              
505 0 0       0 if (@_ >= 2) {
506 0         0 $s->{cmd_rm_mode} = &_parse_cmd_remove_mode($self, $mode);
507             }
508              
509 0         0 $prev;
510             } # end sub cmd_remove_mode
511              
512              
513             sub dump_log {
514 0     0 1 0 my ($self, $name) = @_;
515             my (
516 0         0 $fh,
517             $s,
518             );
519              
520 0         0 $s = *$self->{net_telnet};
521 0         0 $fh = $s->{dumplog};
522              
523 0 0       0 if (@_ >= 2) {
524 0 0 0     0 if (!defined($name) or $name eq "") { # input arg is ""
    0          
    0          
525             ## Turn off logging.
526 0         0 $fh = "";
527             }
528             elsif (&_is_open_fh($name)) { # input arg is an open fh
529             ## Use the open fh for logging.
530 0         0 $fh = $name;
531 1     1   1356 select((select($fh), $|=1)[$[]); # don't buffer writes
  1         1704  
  1         11207  
  0         0  
532             }
533             elsif (!ref $name) { # input arg is filename
534             ## Open the file for logging.
535 0 0       0 $fh = &_fname_to_handle($self, $name)
536             or return;
537 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
538             }
539             else {
540 0         0 return $self->error("bad Dump_log argument ",
541             "\"$name\": not filename or open fh");
542             }
543              
544 0         0 $s->{dumplog} = $fh;
545             }
546              
547 0         0 $fh;
548             } # end sub dump_log
549              
550              
551             sub eof {
552 0     0 1 0 my ($self) = @_;
553              
554 0         0 *$self->{net_telnet}{eofile};
555             } # end sub eof
556              
557              
558             sub errmode {
559 0     0 1 0 my ($self, $mode) = @_;
560             my (
561 0         0 $prev,
562             $s,
563             );
564              
565 0         0 $s = *$self->{net_telnet};
566 0         0 $prev = $s->{errormode};
567              
568 0 0       0 if (@_ >= 2) {
569 0         0 $s->{errormode} = &_parse_errmode($self, $mode);
570             }
571              
572 0         0 $prev;
573             } # end sub errmode
574              
575              
576             sub errmsg {
577 0     0 1 0 my ($self, @errmsgs) = @_;
578             my (
579 0         0 $prev,
580             $s,
581             );
582              
583 0         0 $s = *$self->{net_telnet};
584 0         0 $prev = $s->{errormsg};
585              
586 0 0       0 if (@_ >= 2) {
587 0         0 $s->{errormsg} = join "", @errmsgs;
588             }
589              
590 0         0 $prev;
591             } # end sub errmsg
592              
593              
594             sub error {
595 0     0 1 0 my ($self, @errmsg) = @_;
596             my (
597 0         0 $errmsg,
598             $func,
599             $mode,
600             $s,
601             @args,
602             );
603 0         0 local $_;
604              
605 0         0 $s = *$self->{net_telnet};
606              
607 0 0       0 if (@_ >= 2) {
608             ## Put error message in the object.
609 0         0 $errmsg = join "", @errmsg;
610 0         0 $s->{errormsg} = $errmsg;
611              
612             ## Do the error action as described by error mode.
613 0         0 $mode = $s->{errormode};
614 0 0       0 if (ref($mode) eq "CODE") {
    0          
    0          
615 0         0 &$mode($errmsg);
616 0         0 return;
617             }
618             elsif (ref($mode) eq "ARRAY") {
619 0         0 ($func, @args) = @$mode;
620 0         0 &$func(@args);
621 0         0 return;
622             }
623             elsif ($mode =~ /^return$/i) {
624 0         0 return;
625             }
626             else { # die
627 0 0       0 if ($errmsg =~ /\n$/) {
628 0         0 die $errmsg;
629             }
630             else {
631             ## Die and append caller's line number to message.
632 0         0 &_croak($self, $errmsg);
633             }
634             }
635             }
636             else {
637 0         0 return $s->{errormsg} ne "";
638             }
639             } # end sub error
640              
641              
642             sub family {
643 0     0 1 0 my ($self, $family) = @_;
644             my (
645 0         0 $prev,
646             $s,
647             );
648              
649 0         0 $s = *$self->{net_telnet};
650 0         0 $prev = $s->{peer_family};
651              
652 0 0       0 if (@_ >= 2) {
653 0 0       0 $family = &_parse_family($self, $family)
654             or return;
655              
656 0         0 $s->{peer_family} = $family;
657             }
658              
659 0         0 $prev;
660             } # end sub family
661              
662              
663             sub fhopen {
664 0     0 1 0 my ($self, $fh) = @_;
665             my (
666 0         0 $globref,
667             $s,
668             );
669              
670             ## Convert given filehandle to a typeglob reference, if necessary.
671 0         0 $globref = &_qualify_fh($self, $fh);
672              
673             ## Ensure filehandle is already open.
674 0 0 0     0 return $self->error("fhopen filehandle isn't already open")
675             unless defined($globref) and defined(fileno $globref);
676              
677             ## Ensure we're closed.
678 0         0 $self->close;
679              
680             ## Save our private data.
681 0         0 $s = *$self->{net_telnet};
682              
683             ## Switch ourself with the given filehandle.
684 0         0 *$self = *$globref;
685              
686             ## Restore our private data.
687 0         0 *$self->{net_telnet} = $s;
688              
689             ## Re-initialize ourself.
690 0         0 select((select($self), $|=1)[$[]); # don't buffer writes
691 0         0 $s = *$self->{net_telnet};
692 0         0 $s->{blksize} = &_optimal_blksize((stat $self)[11]);
693 0         0 $s->{buf} = "";
694 0         0 $s->{eofile} = '';
695 0         0 $s->{errormsg} = "";
696 0         0 vec($s->{fdmask}='', fileno($self), 1) = 1;
697 0         0 $s->{host} = "";
698 0         0 $s->{last_line} = "";
699 0         0 $s->{last_prompt} = "";
700 0         0 $s->{num_wrote} = 0;
701 0         0 $s->{opened} = 1;
702 0         0 $s->{pending_errormsg} = "";
703 0         0 $s->{port} = '';
704 0         0 $s->{pushback_buf} = "";
705 0   0     0 $s->{select_supported} = $^O ne "MSWin32" || -S $self;
706 0         0 $s->{timedout} = '';
707 0         0 $s->{unsent_opts} = "";
708 0         0 &_reset_options($s->{opts});
709              
710 0         0 1;
711             } # end sub fhopen
712              
713              
714             sub get {
715 0     0 1 0 my ($self, %args) = @_;
716             my (
717 0         0 $binmode,
718             $endtime,
719             $errmode,
720             $line,
721             $s,
722             $telnetmode,
723             $timeout,
724             );
725 0         0 local $_;
726              
727             ## Init.
728 0         0 $s = *$self->{net_telnet};
729 0         0 $timeout = $s->{time_out};
730 0         0 $s->{timedout} = '';
731 0 0       0 return if $s->{eofile};
732              
733             ## Parse the named args.
734 0         0 foreach (keys %args) {
735 0 0       0 if (/^-?binmode$/i) {
    0          
    0          
    0          
736 0         0 $binmode = $args{$_};
737 0 0       0 unless (defined $binmode) {
738 0         0 $binmode = 0;
739             }
740             }
741             elsif (/^-?errmode$/i) {
742 0         0 $errmode = &_parse_errmode($self, $args{$_});
743             }
744             elsif (/^-?telnetmode$/i) {
745 0         0 $telnetmode = $args{$_};
746 0 0       0 unless (defined $telnetmode) {
747 0         0 $telnetmode = 0;
748             }
749             }
750             elsif (/^-?timeout$/i) {
751 0         0 $timeout = &_parse_timeout($self, $args{$_});
752             }
753             else {
754 0         0 &_croak($self, "bad named parameter \"$_\" given " .
755             "to " . ref($self) . "::get()");
756             }
757             }
758              
759             ## If any args given, override corresponding instance data.
760 0 0       0 local $s->{errormode} = $errmode
761             if defined $errmode;
762 0 0       0 local $s->{bin_mode} = $binmode
763             if defined $binmode;
764 0 0       0 local $s->{telnet_mode} = $telnetmode
765             if defined $telnetmode;
766              
767             ## Set wall time when we time out.
768 0         0 $endtime = &_endtime($timeout);
769              
770             ## Try to send any waiting option negotiation.
771 0 0       0 if (length $s->{unsent_opts}) {
772 0         0 &_flush_opts($self);
773             }
774              
775             ## Try to read just the waiting data using return error mode.
776             {
777 0         0 local $s->{errormode} = "return";
  0         0  
778 0         0 $s->{errormsg} = "";
779 0         0 &_fillbuf($self, $s, 0);
780             }
781              
782             ## We're done if we timed-out and timeout value is set to "poll".
783             return $self->error($s->{errormsg})
784             if ($s->{timedout} and defined($timeout) and $timeout == 0
785 0 0 0     0 and !length $s->{buf});
      0        
      0        
786              
787             ## We're done if we hit an error other than timing out.
788 0 0 0     0 if ($s->{errormsg} and !$s->{timedout}) {
789 0 0       0 if (!length $s->{buf}) {
790 0         0 return $self->error($s->{errormsg});
791             }
792             else { # error encountered but there's some data in buffer
793 0         0 $s->{pending_errormsg} = $s->{errormsg};
794             }
795             }
796              
797             ## Clear time-out error from first read.
798 0         0 $s->{timedout} = '';
799 0         0 $s->{errormsg} = "";
800              
801             ## If buffer is still empty, try to read according to user's timeout.
802 0 0       0 if (!length $s->{buf}) {
803             &_fillbuf($self, $s, $endtime)
804 0 0       0 or do {
805 0 0       0 return if $s->{timedout};
806              
807             ## We've reached end-of-file.
808 0         0 $self->close;
809 0         0 return;
810             };
811             }
812              
813             ## Extract chars from buffer.
814 0         0 $line = $s->{buf};
815 0         0 $s->{buf} = "";
816              
817 0         0 $line;
818             } # end sub get
819              
820              
821             sub getline {
822 0     0 1 0 my ($self, %args) = @_;
823             my (
824 0         0 $binmode,
825             $endtime,
826             $errmode,
827             $len,
828             $line,
829             $offset,
830             $pos,
831             $rs,
832             $s,
833             $telnetmode,
834             $timeout,
835             );
836 0         0 local $_;
837              
838             ## Init.
839 0         0 $s = *$self->{net_telnet};
840 0         0 $s->{timedout} = '';
841 0 0       0 return if $s->{eofile};
842 0         0 $rs = $s->{"rs"};
843 0         0 $timeout = $s->{time_out};
844              
845             ## Parse the named args.
846 0         0 foreach (keys %args) {
847 0 0 0     0 if (/^-?binmode$/i) {
    0          
    0          
    0          
    0          
848 0         0 $binmode = $args{$_};
849 0 0       0 unless (defined $binmode) {
850 0         0 $binmode = 0;
851             }
852             }
853             elsif (/^-?errmode$/i) {
854 0         0 $errmode = &_parse_errmode($self, $args{$_});
855             }
856             elsif (/^-?input_record_separator$/i or /^-?rs$/i) {
857 0         0 $rs = &_parse_input_record_separator($self, $args{$_});
858             }
859             elsif (/^-?telnetmode$/i) {
860 0         0 $telnetmode = $args{$_};
861 0 0       0 unless (defined $telnetmode) {
862 0         0 $telnetmode = 0;
863             }
864             }
865             elsif (/^-?timeout$/i) {
866 0         0 $timeout = &_parse_timeout($self, $args{$_});
867             }
868             else {
869 0         0 &_croak($self, "bad named parameter \"$_\" given " .
870             "to " . ref($self) . "::getline()");
871             }
872             }
873              
874             ## If any args given, override corresponding instance data.
875 0 0       0 local $s->{bin_mode} = $binmode
876             if defined $binmode;
877 0 0       0 local $s->{errormode} = $errmode
878             if defined $errmode;
879 0 0       0 local $s->{telnet_mode} = $telnetmode
880             if defined $telnetmode;
881              
882             ## Set wall time when we time out.
883 0         0 $endtime = &_endtime($timeout);
884              
885             ## Try to send any waiting option negotiation.
886 0 0       0 if (length $s->{unsent_opts}) {
887 0         0 &_flush_opts($self);
888             }
889              
890             ## Keep reading into buffer until end-of-line is read.
891 0         0 $offset = 0;
892 0         0 while (($pos = index($s->{buf}, $rs, $offset)) == -1) {
893 0         0 $offset = length $s->{buf};
894             &_fillbuf($self, $s, $endtime)
895 0 0       0 or do {
896 0 0       0 return if $s->{timedout};
897              
898             ## We've reached end-of-file.
899 0         0 $self->close;
900 0 0       0 if (length $s->{buf}) {
901 0         0 return $s->{buf};
902             }
903             else {
904 0         0 return;
905             }
906             };
907             }
908              
909             ## Extract line from buffer.
910 0         0 $len = $pos + length $rs;
911 0         0 $line = substr($s->{buf}, 0, $len);
912 0         0 substr($s->{buf}, 0, $len) = "";
913              
914 0         0 $line;
915             } # end sub getline
916              
917              
918             sub getlines {
919 0     0 1 0 my ($self, %args) = @_;
920             my (
921 0         0 $binmode,
922             $errmode,
923             $line,
924             $rs,
925             $s,
926             $telnetmode,
927             $timeout,
928             );
929 0         0 my $all = 1;
930 0         0 my @lines = ();
931 0         0 local $_;
932              
933             ## Init.
934 0         0 $s = *$self->{net_telnet};
935 0         0 $s->{timedout} = '';
936 0 0       0 return if $s->{eofile};
937 0         0 $timeout = $s->{time_out};
938              
939             ## Parse the named args.
940 0         0 foreach (keys %args) {
941 0 0 0     0 if (/^-?all$/i) {
    0          
    0          
    0          
    0          
    0          
942 0         0 $all = $args{$_};
943 0 0       0 unless (defined $all) {
944 0         0 $all = '';
945             }
946             }
947             elsif (/^-?binmode$/i) {
948 0         0 $binmode = $args{$_};
949 0 0       0 unless (defined $binmode) {
950 0         0 $binmode = 0;
951             }
952             }
953             elsif (/^-?errmode$/i) {
954 0         0 $errmode = &_parse_errmode($self, $args{$_});
955             }
956             elsif (/^-?input_record_separator$/i or /^-?rs$/i) {
957 0         0 $rs = &_parse_input_record_separator($self, $args{$_});
958             }
959             elsif (/^-?telnetmode$/i) {
960 0         0 $telnetmode = $args{$_};
961 0 0       0 unless (defined $telnetmode) {
962 0         0 $telnetmode = 0;
963             }
964             }
965             elsif (/^-?timeout$/i) {
966 0         0 $timeout = &_parse_timeout($self, $args{$_});
967             }
968             else {
969 0         0 &_croak($self, "bad named parameter \"$_\" given " .
970             "to " . ref($self) . "::getlines()");
971             }
972             }
973              
974             ## If any args given, override corresponding instance data.
975 0 0       0 local $s->{bin_mode} = $binmode
976             if defined $binmode;
977 0 0       0 local $s->{errormode} = $errmode
978             if defined $errmode;
979 0 0       0 local $s->{"rs"} = $rs
980             if defined $rs;
981 0 0       0 local $s->{telnet_mode} = $telnetmode
982             if defined $telnetmode;
983 0         0 local $s->{time_out} = &_endtime($timeout);
984              
985             ## User requested only the currently available lines.
986 0 0       0 if (! $all) {
987 0         0 return &_next_getlines($self, $s);
988             }
989              
990             ## Read lines until eof or error.
991 0         0 while (1) {
992 0 0       0 $line = $self->getline
993             or last;
994 0         0 push @lines, $line;
995             }
996              
997             ## Check for error.
998 0 0       0 return if ! $self->eof;
999              
1000 0         0 @lines;
1001             } # end sub getlines
1002              
1003              
1004             sub host {
1005 0     0 1 0 my ($self, $host) = @_;
1006             my (
1007 0         0 $prev,
1008             $s,
1009             );
1010              
1011 0         0 $s = *$self->{net_telnet};
1012 0         0 $prev = $s->{host};
1013              
1014 0 0       0 if (@_ >= 2) {
1015 0 0       0 unless (defined $host) {
1016 0         0 $host = "";
1017             }
1018              
1019 0         0 $s->{host} = $host;
1020             }
1021              
1022 0         0 $prev;
1023             } # end sub host
1024              
1025              
1026             sub input_log {
1027 0     0 1 0 my ($self, $name) = @_;
1028             my (
1029 0         0 $fh,
1030             $s,
1031             );
1032              
1033 0         0 $s = *$self->{net_telnet};
1034 0         0 $fh = $s->{inputlog};
1035              
1036 0 0       0 if (@_ >= 2) {
1037 0 0 0     0 if (!defined($name) or $name eq "") { # input arg is ""
    0          
    0          
1038             ## Turn off logging.
1039 0         0 $fh = "";
1040             }
1041             elsif (&_is_open_fh($name)) { # input arg is an open fh
1042             ## Use the open fh for logging.
1043 0         0 $fh = $name;
1044 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1045             }
1046             elsif (!ref $name) { # input arg is filename
1047             ## Open the file for logging.
1048 0 0       0 $fh = &_fname_to_handle($self, $name)
1049             or return;
1050 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1051             }
1052             else {
1053 0         0 return $self->error("bad Input_log argument ",
1054             "\"$name\": not filename or open fh");
1055             }
1056              
1057 0         0 $s->{inputlog} = $fh;
1058             }
1059              
1060 0         0 $fh;
1061             } # end sub input_log
1062              
1063              
1064             sub input_record_separator {
1065 0     0 1 0 my ($self, $rs) = @_;
1066             my (
1067 0         0 $prev,
1068             $s,
1069             );
1070              
1071 0         0 $s = *$self->{net_telnet};
1072 0         0 $prev = $s->{"rs"};
1073              
1074 0 0       0 if (@_ >= 2) {
1075 0         0 $s->{"rs"} = &_parse_input_record_separator($self, $rs);
1076             }
1077              
1078 0         0 $prev;
1079             } # end sub input_record_separator
1080              
1081              
1082             sub last_prompt {
1083 0     0 1 0 my ($self, $string) = @_;
1084             my (
1085 0         0 $prev,
1086             $s,
1087             );
1088              
1089 0         0 $s = *$self->{net_telnet};
1090 0         0 $prev = $s->{last_prompt};
1091              
1092 0 0       0 if (@_ >= 2) {
1093 0 0       0 unless (defined $string) {
1094 0         0 $string = "";
1095             }
1096              
1097 0         0 $s->{last_prompt} = $string;
1098             }
1099              
1100 0         0 $prev;
1101             } # end sub last_prompt
1102              
1103              
1104             sub lastline {
1105 0     0 1 0 my ($self, $line) = @_;
1106             my (
1107 0         0 $prev,
1108             $s,
1109             );
1110              
1111 0         0 $s = *$self->{net_telnet};
1112 0         0 $prev = $s->{last_line};
1113              
1114 0 0       0 if (@_ >= 2) {
1115 0 0       0 unless (defined $line) {
1116 0         0 $line = "";
1117             }
1118              
1119 0         0 $s->{last_line} = $line;
1120             }
1121              
1122 0         0 $prev;
1123             } # end sub lastline
1124              
1125              
1126             sub localfamily {
1127 0     0 1 0 my ($self, $family) = @_;
1128             my (
1129 0         0 $prev,
1130             $s,
1131             );
1132              
1133 0         0 $s = *$self->{net_telnet};
1134 0         0 $prev = $s->{local_family};
1135              
1136 0 0       0 if (@_ >= 2) {
1137 0 0       0 unless (defined $family) {
1138 0         0 $family = "";
1139             }
1140              
1141 0 0       0 if ($family =~ /^\s*ipv4\s*$/i) { # family arg is "ipv4"
    0          
    0          
1142 0         0 $s->{local_family} = "ipv4";
1143             }
1144             elsif ($family =~ /^\s*any\s*$/i) { # family arg is "any"
1145 0 0 0     0 if ($Socket::VERSION >= 1.94 and defined $AF_INET6) { # has IPv6
1146 0         0 $s->{local_family} = "any";
1147             }
1148             else { # IPv6 not supported on this machine
1149 0         0 $s->{local_family} = "ipv4";
1150             }
1151             }
1152             elsif ($family =~ /^\s*ipv6\s*$/i) { # family arg is "ipv6"
1153 0 0       0 return $self->error("Localfamily arg ipv6 not supported when " .
1154             "Socket.pm version < 1.94")
1155             unless $Socket::VERSION >= 1.94;
1156 0 0       0 return $self->error("Localfamily arg ipv6 not supported by " .
1157             "this OS: AF_INET6 not in Socket.pm")
1158             unless defined $AF_INET6;
1159              
1160 0         0 $s->{local_family} = "ipv6";
1161             }
1162             else {
1163 0         0 return $self->error("bad Localfamily argument \"$family\": " .
1164             "must be \"ipv4\", \"ipv6\", or \"any\"");
1165             }
1166             }
1167              
1168 0         0 $prev;
1169             } # end sub localfamily
1170              
1171              
1172             sub localhost {
1173 0     0 1 0 my ($self, $localhost) = @_;
1174             my (
1175 0         0 $prev,
1176             $s,
1177             );
1178              
1179 0         0 $s = *$self->{net_telnet};
1180 0         0 $prev = $s->{local_host};
1181              
1182 0 0       0 if (@_ >= 2) {
1183 0 0       0 unless (defined $localhost) {
1184 0         0 $localhost = "";
1185             }
1186              
1187 0         0 $s->{local_host} = $localhost;
1188             }
1189              
1190 0         0 $prev;
1191             } # end sub localhost
1192              
1193              
1194             sub login {
1195 0     0 1 0 my ($self, @args) = @_;
1196             my (
1197 0         0 $arg_errmode,
1198             $error,
1199             $is_passwd_arg,
1200             $is_username_arg,
1201             $lastline,
1202             $match,
1203             $ors,
1204             $passwd,
1205             $prematch,
1206             $prompt,
1207             $s,
1208             $timeout,
1209             $username,
1210             %args,
1211             );
1212 0         0 local $_;
1213              
1214             ## Init.
1215 0         0 $self->timed_out('');
1216 0         0 $self->last_prompt("");
1217 0         0 $s = *$self->{net_telnet};
1218 0         0 $timeout = $self->timeout;
1219 0         0 $ors = $self->output_record_separator;
1220 0         0 $prompt = $self->prompt;
1221              
1222             ## Parse positional args.
1223 0 0       0 if (@args == 2) { # just username and passwd given
1224 0         0 $username = $args[0];
1225 0         0 $passwd = $args[1];
1226              
1227 0         0 $is_username_arg = 1;
1228 0         0 $is_passwd_arg = 1;
1229             }
1230              
1231             ## Override errmode first, if specified.
1232 0         0 $arg_errmode = &_extract_arg_errmode($self, \@args);
1233 0 0       0 local $s->{errormode} = $arg_errmode
1234             if $arg_errmode;
1235              
1236             ## Parse named args.
1237 0 0       0 if (@args > 2) {
1238             ## Get the named args.
1239 0         0 %args = @args;
1240              
1241             ## Parse the named args.
1242 0         0 foreach (keys %args) {
1243 0 0       0 if (/^-?name$/i) {
    0          
    0          
    0          
1244 0         0 $username = $args{$_};
1245 0 0       0 unless (defined $username) {
1246 0         0 $username = "";
1247             }
1248              
1249 0         0 $is_username_arg = 1;
1250             }
1251             elsif (/^-?pass/i) {
1252 0         0 $passwd = $args{$_};
1253 0 0       0 unless (defined $passwd) {
1254 0         0 $passwd = "";
1255             }
1256              
1257 0         0 $is_passwd_arg = 1;
1258             }
1259             elsif (/^-?prompt$/i) {
1260 0 0       0 $prompt = &_parse_prompt($self, $args{$_})
1261             or return;
1262             }
1263             elsif (/^-?timeout$/i) {
1264 0         0 $timeout = &_parse_timeout($self, $args{$_});
1265             }
1266             else {
1267 0         0 &_croak($self, "bad named parameter \"$_\" given ",
1268             "to " . ref($self) . "::login()");
1269             }
1270             }
1271             }
1272              
1273             ## Ensure both username and password argument given.
1274 0 0       0 &_croak($self,"Name argument not given to " . ref($self) . "::login()")
1275             unless $is_username_arg;
1276 0 0       0 &_croak($self,"Password argument not given to " . ref($self) . "::login()")
1277             unless $is_passwd_arg;
1278              
1279             ## Set timeout for this invocation.
1280 0         0 local $s->{time_out} = &_endtime($timeout);
1281              
1282             ## Create a subroutine to generate an error.
1283             $error
1284             = sub {
1285 0     0   0 my ($errmsg) = @_;
1286              
1287 0 0       0 if ($self->timed_out) {
    0          
1288 0         0 return $self->error($errmsg);
1289             }
1290             elsif ($self->eof) {
1291 0         0 ($lastline = $self->lastline) =~ s/\n+//;
1292 0         0 return $self->error($errmsg, ": ", $lastline);
1293             }
1294             else {
1295 0         0 return $self->error($self->errmsg);
1296             }
1297 0         0 };
1298              
1299              
1300 0 0       0 return $self->error("login failed: filehandle isn't open")
1301             if $self->eof;
1302              
1303             ## Wait for login prompt.
1304             $self->waitfor(Match => '/login[: ]*$/i',
1305             Match => '/username[: ]*$/i',
1306             Errmode => "return")
1307 0 0       0 or do {
1308 0 0       0 return &$error("eof read waiting for login prompt")
1309             if $self->eof;
1310 0         0 return &$error("timed-out waiting for login prompt");
1311             };
1312              
1313             ## Delay sending response because of bug in Linux login program.
1314 0         0 &_sleep(0.01);
1315              
1316             ## Send login name.
1317 0 0       0 $self->put(String => $username . $ors,
1318             Errmode => "return")
1319             or return &$error("login disconnected");
1320              
1321             ## Wait for password prompt.
1322             $self->waitfor(Match => '/password[: ]*$/i',
1323             Errmode => "return")
1324 0 0       0 or do {
1325 0 0       0 return &$error("eof read waiting for password prompt")
1326             if $self->eof;
1327 0         0 return &$error("timed-out waiting for password prompt");
1328             };
1329              
1330             ## Delay sending response because of bug in Linux login program.
1331 0         0 &_sleep(0.01);
1332              
1333             ## Send password.
1334 0 0       0 $self->put(String => $passwd . $ors,
1335             Errmode => "return")
1336             or return &$error("login disconnected");
1337              
1338             ## Wait for command prompt or another login prompt.
1339             ($prematch, $match) = $self->waitfor(Match => '/login[: ]*$/i',
1340             Match => '/username[: ]*$/i',
1341             Match => $prompt,
1342             Errmode => "return")
1343 0 0       0 or do {
1344 0 0       0 return &$error("eof read waiting for command prompt")
1345             if $self->eof;
1346 0         0 return &$error("timed-out waiting for command prompt");
1347             };
1348              
1349             ## It's a bad login if we got another login prompt.
1350 0 0 0     0 return $self->error("login failed: bad name or password")
1351             if $match =~ /login[: ]*$/i or $match =~ /username[: ]*$/i;
1352              
1353             ## Save the most recently matched command prompt.
1354 0         0 $self->last_prompt($match);
1355              
1356 0         0 1;
1357             } # end sub login
1358              
1359              
1360             sub max_buffer_length {
1361 0     0 1 0 my ($self, $maxbufsize) = @_;
1362             my (
1363 0         0 $prev,
1364             $s,
1365             );
1366 0         0 my $minbufsize = 512;
1367              
1368 0         0 $s = *$self->{net_telnet};
1369 0         0 $prev = $s->{maxbufsize};
1370              
1371 0 0       0 if (@_ >= 2) {
1372             ## Ensure a positive integer value.
1373 0 0 0     0 unless (defined $maxbufsize
      0        
1374             and $maxbufsize =~ /^\d+$/
1375             and $maxbufsize)
1376             {
1377 0         0 &_carp($self, "ignoring bad Max_buffer_length " .
1378             "argument \"$maxbufsize\": it's not a positive integer");
1379 0         0 $maxbufsize = $prev;
1380             }
1381              
1382             ## Adjust up values that are too small.
1383 0 0       0 if ($maxbufsize < $minbufsize) {
1384 0         0 $maxbufsize = $minbufsize;
1385             }
1386              
1387 0         0 $s->{maxbufsize} = $maxbufsize;
1388             }
1389              
1390 0         0 $prev;
1391             } # end sub max_buffer_length
1392              
1393              
1394             ## Make ofs() synonymous with output_field_separator().
1395 0     0 1 0 sub ofs { &output_field_separator; }
1396              
1397              
1398             sub open {
1399 0     0 1 0 my ($self, @args) = @_;
1400             my (
1401 0         0 $af,
1402             $arg_errmode,
1403             $err,
1404             $errno,
1405             $family,
1406             $flags_hint,
1407             $host,
1408             $ip_addr,
1409             $lfamily,
1410             $localhost,
1411             $port,
1412             $s,
1413             $timeout,
1414             %args,
1415             @ai,
1416             );
1417 0         0 local $@;
1418 0         0 local $_;
1419 0         0 my $local_addr = '';
1420 0         0 my $remote_addr = '';
1421 0 0       0 my %af = (
1422             ipv4 => AF_INET,
1423             ipv6 => defined($AF_INET6) ? $AF_INET6 : undef,
1424             any => $AF_UNSPEC,
1425             );
1426              
1427             ## Init.
1428 0         0 $s = *$self->{net_telnet};
1429 0         0 $s->{timedout} = '';
1430 0         0 $s->{sock_family} = 0;
1431 0         0 $port = $self->port;
1432 0         0 $family = $self->family;
1433 0         0 $localhost = $self->localhost;
1434 0         0 $lfamily = $self->localfamily;
1435 0         0 $timeout = $self->timeout;
1436              
1437             ## Override errmode first, if specified.
1438 0         0 $arg_errmode = &_extract_arg_errmode($self, \@args);
1439 0 0       0 local $s->{errormode} = $arg_errmode
1440             if $arg_errmode;
1441              
1442 0 0       0 if (@args == 1) { # one positional arg given
    0          
1443 0         0 $self->host($args[0]);
1444             }
1445             elsif (@args >= 2) { # named args given
1446             ## Get the named args.
1447 0         0 %args = @args;
1448              
1449             ## Parse the named args.
1450 0         0 foreach (keys %args) {
1451 0 0       0 if (/^-?family$/i) {
    0          
    0          
    0          
    0          
    0          
1452 0         0 $family = &_parse_family($self, $args{$_});
1453             }
1454             elsif (/^-?host$/i) {
1455 0         0 $self->host($args{$_});
1456             }
1457             elsif (/^-?localfamily$/i) {
1458 0         0 $lfamily = &_parse_localfamily($self, $args{$_});
1459             }
1460             elsif (/^-?localhost$/i) {
1461 0 0       0 $args{$_} = "" unless defined $args{$_};
1462 0         0 $localhost = $args{$_};
1463             }
1464             elsif (/^-?port$/i) {
1465 0         0 $port = &_parse_port($self, $args{$_});
1466             }
1467             elsif (/^-?timeout$/i) {
1468 0         0 $timeout = &_parse_timeout($self, $args{$_});
1469             }
1470             else {
1471 0         0 &_croak($self, "bad named parameter \"$_\" given ",
1472             "to " . ref($self) . "::open()");
1473             }
1474             }
1475             }
1476              
1477             ## Get hostname/ip address.
1478 0         0 $host = $self->host;
1479              
1480             ## Ensure we're already closed.
1481 0         0 $self->close;
1482              
1483             ## Connect with or without a timeout.
1484 0 0 0     0 if (defined($timeout) and &_have_alarm) { # use a timeout
1485             ## Convert possible absolute timeout to relative timeout.
1486 0 0       0 if ($timeout >= $^T) { # it's an absolute time
1487 0         0 $timeout = $timeout - time;
1488             }
1489              
1490             ## Ensure a valid timeout value for alarm.
1491 0 0       0 if ($timeout < 1) {
1492 0         0 $timeout = 1;
1493             }
1494 0         0 $timeout = int($timeout + 0.5);
1495              
1496             ## Connect to server, timing out if it takes too long.
1497 0         0 eval {
1498             ## Turn on timer.
1499 0         0 local $SIG{"__DIE__"} = "DEFAULT";
1500 0     0   0 local $SIG{ALRM} = sub { die "timed-out\n" };
  0         0  
1501 0         0 alarm $timeout;
1502              
1503 0 0       0 if ($family eq "ipv4") {
1504             ## Lookup server's IP address.
1505 0 0       0 $ip_addr = inet_aton $host
1506             or die "unknown remote host: $host\n";
1507 0         0 $af = AF_INET;
1508 0         0 $remote_addr = sockaddr_in($port, $ip_addr);
1509             }
1510             else { # family is "ipv6" or "any"
1511             ## Lookup server's IP address.
1512 0 0       0 $flags_hint = $family eq "any" ? $AI_ADDRCONFIG : 0;
1513             ($err, @ai) = Socket::getaddrinfo($host, $port,
1514             { socktype => SOCK_STREAM,
1515 0         0 "family" => $af{$family},
1516             "flags" => $flags_hint });
1517 0 0       0 if ($err == $EAI_BADFLAGS) {
1518             ## Try again with no flags.
1519             ($err, @ai) = Socket::getaddrinfo($host, $port,
1520             {socktype => SOCK_STREAM,
1521 0         0 "family"=> $af{$family},
1522             "flags" => 0 });
1523             }
1524 0 0 0     0 die "unknown remote host: $host: $err\n"
1525             if $err or !@ai;
1526 0         0 $af = $ai[0]{"family"};
1527 0         0 $remote_addr = $ai[0]{addr};
1528             }
1529              
1530             ## Create a socket and attach the filehandle to it.
1531 0 0       0 socket $self, $af, SOCK_STREAM, 0
1532             or die "problem creating socket: $!\n";
1533              
1534             ## Bind to a local network interface.
1535 0 0       0 if (length $localhost) {
1536 0 0       0 if ($lfamily eq "ipv4") {
1537             ## Lookup server's IP address.
1538 0 0       0 $ip_addr = inet_aton $localhost
1539             or die "unknown local host: $localhost\n";
1540 0         0 $local_addr = sockaddr_in(0, $ip_addr);
1541             }
1542             else { # local family is "ipv6" or "any"
1543             ## Lookup local IP address.
1544             ($err, @ai) = Socket::getaddrinfo($localhost, 0,
1545             {socktype => SOCK_STREAM,
1546 0         0 "family"=>$af{$lfamily},
1547             "flags" => 0 });
1548 0 0 0     0 die "unknown local host: $localhost: $err\n"
1549             if $err or !@ai;
1550 0         0 $local_addr = $ai[0]{addr};
1551             }
1552              
1553 0 0       0 bind $self, $local_addr
1554             or die "problem binding to \"$localhost\": $!\n";
1555             }
1556              
1557             ## Open connection to server.
1558 0 0       0 connect $self, $remote_addr
1559             or die "problem connecting to \"$host\", port $port: $!\n";
1560             };
1561 0         0 alarm 0;
1562              
1563             ## Check for error.
1564 0 0       0 if ($@ =~ /^timed-out$/) { # time out failure
    0          
1565 0         0 $s->{timedout} = 1;
1566 0         0 $self->close;
1567 0 0 0     0 if (!$remote_addr) {
    0          
1568 0         0 return $self->error("unknown remote host: $host: ",
1569             "name lookup timed-out");
1570             }
1571             elsif (length($localhost) and !$local_addr) {
1572 0         0 return $self->error("unknown local host: $localhost: ",
1573             "name lookup timed-out");
1574             }
1575             else {
1576 0         0 return $self->error("problem connecting to \"$host\", ",
1577             "port $port: connect timed-out");
1578             }
1579             }
1580             elsif ($@) { # hostname lookup or connect failure
1581 0         0 $self->close;
1582 0         0 chomp $@;
1583 0         0 return $self->error($@);
1584             }
1585             }
1586             else { # don't use a timeout
1587 0         0 $timeout = undef;
1588              
1589 0 0       0 if ($family eq "ipv4") {
1590             ## Lookup server's IP address.
1591 0 0       0 $ip_addr = inet_aton $host
1592             or return $self->error("unknown remote host: $host");
1593 0         0 $af = AF_INET;
1594 0         0 $remote_addr = sockaddr_in($port, $ip_addr);
1595             }
1596             else { # family is "ipv6" or "any"
1597             ## Lookup server's IP address.
1598 0 0       0 $flags_hint = $family eq "any" ? $AI_ADDRCONFIG : 0;
1599             ($err, @ai) = Socket::getaddrinfo($host, $port,
1600             { socktype => SOCK_STREAM,
1601 0         0 "family" => $af{$family},
1602             "flags" => $flags_hint });
1603 0 0       0 if ($err == $EAI_BADFLAGS) {
1604             ## Try again with no flags.
1605             ($err, @ai) = Socket::getaddrinfo($host, $port,
1606             { socktype => SOCK_STREAM,
1607 0         0 "family"=> $af{$family},
1608             "flags" => 0 });
1609             }
1610 0 0 0     0 return $self->error("unknown remote host: $host")
1611             if $err or !@ai;
1612 0         0 $af = $ai[0]{"family"};
1613 0         0 $remote_addr = $ai[0]{addr};
1614             }
1615              
1616             ## Create a socket and attach the filehandle to it.
1617 0 0       0 socket $self, $af, SOCK_STREAM, 0
1618             or return $self->error("problem creating socket: $!");
1619              
1620             ## Bind to a local network interface.
1621 0 0       0 if (length $localhost) {
1622 0 0       0 if ($lfamily eq "ipv4") {
1623             ## Lookup server's IP address.
1624 0 0       0 $ip_addr = inet_aton $localhost
1625             or return $self->error("unknown local host: $localhost");
1626 0         0 $local_addr = sockaddr_in(0, $ip_addr);
1627             }
1628             else { # local family is "ipv6" or "any"
1629             ## Lookup local IP address.
1630             ($err, @ai) = Socket::getaddrinfo($localhost, 0,
1631             { socktype => SOCK_STREAM,
1632 0         0 "family"=>$af{$lfamily},
1633             "flags" => 0 });
1634 0 0 0     0 return $self->error("unknown local host: $localhost: $err")
1635             if $err or !@ai;
1636 0         0 $local_addr = $ai[0]{addr};
1637             }
1638              
1639 0 0       0 bind $self, $local_addr
1640             or return $self->error("problem binding ",
1641             "to \"$localhost\": $!");
1642             }
1643              
1644             ## Open connection to server.
1645             connect $self, $remote_addr
1646 0 0       0 or do {
1647 0         0 $errno = "$!";
1648 0         0 $self->close;
1649 0         0 return $self->error("problem connecting to \"$host\", ",
1650             "port $port: $errno");
1651             };
1652             }
1653              
1654 0         0 select((select($self), $|=1)[$[]); # don't buffer writes
1655 0         0 $s->{blksize} = &_optimal_blksize((stat $self)[11]);
1656 0         0 $s->{buf} = "";
1657 0         0 $s->{eofile} = '';
1658 0         0 $s->{errormsg} = "";
1659 0         0 vec($s->{fdmask}='', fileno($self), 1) = 1;
1660 0         0 $s->{last_line} = "";
1661 0         0 $s->{sock_family} = $af;
1662 0         0 $s->{num_wrote} = 0;
1663 0         0 $s->{opened} = 1;
1664 0         0 $s->{pending_errormsg} = "";
1665 0         0 $s->{pushback_buf} = "";
1666 0         0 $s->{select_supported} = 1;
1667 0         0 $s->{timedout} = '';
1668 0         0 $s->{unsent_opts} = "";
1669 0         0 &_reset_options($s->{opts});
1670              
1671 0         0 1;
1672             } # end sub open
1673              
1674              
1675             sub option_accept {
1676 0     0 0 0 my ($self, @args) = @_;
1677             my (
1678 0         0 $arg,
1679             $option,
1680             $s,
1681             @opt_args,
1682             );
1683 0         0 local $_;
1684              
1685             ## Init.
1686 0         0 $s = *$self->{net_telnet};
1687              
1688             ## Parse the named args.
1689 0         0 while (($_, $arg) = splice @args, 0, 2) {
1690             ## Verify and save arguments.
1691 0 0       0 if (/^-?do$/i) {
    0          
    0          
    0          
1692             ## Make sure a callback is defined.
1693             return $self->error("usage: an option callback must already ",
1694             "be defined when enabling with $_")
1695 0 0       0 unless $s->{opt_cback};
1696              
1697 0         0 $option = &_verify_telopt_arg($self, $arg, $_);
1698 0 0       0 return unless defined $option;
1699 0         0 push @opt_args, { option => $option,
1700             is_remote => '',
1701             is_enable => 1,
1702             };
1703             }
1704             elsif (/^-?dont$/i) {
1705 0         0 $option = &_verify_telopt_arg($self, $arg, $_);
1706 0 0       0 return unless defined $option;
1707 0         0 push @opt_args, { option => $option,
1708             is_remote => '',
1709             is_enable => '',
1710             };
1711             }
1712             elsif (/^-?will$/i) {
1713             ## Make sure a callback is defined.
1714             return $self->error("usage: an option callback must already ",
1715             "be defined when enabling with $_")
1716 0 0       0 unless $s->{opt_cback};
1717              
1718 0         0 $option = &_verify_telopt_arg($self, $arg, $_);
1719 0 0       0 return unless defined $option;
1720 0         0 push @opt_args, { option => $option,
1721             is_remote => 1,
1722             is_enable => 1,
1723             };
1724             }
1725             elsif (/^-?wont$/i) {
1726 0         0 $option = &_verify_telopt_arg($self, $arg, $_);
1727 0 0       0 return unless defined $option;
1728 0         0 push @opt_args, { option => $option,
1729             is_remote => 1,
1730             is_enable => '',
1731             };
1732             }
1733             else {
1734 0         0 return $self->error('usage: $obj->option_accept(' .
1735             '[Do => $telopt,] ',
1736             '[Dont => $telopt,] ',
1737             '[Will => $telopt,] ',
1738             '[Wont => $telopt,]');
1739             }
1740             }
1741              
1742             ## Set "receive ok" for options specified.
1743 0         0 &_opt_accept($self, @opt_args);
1744             } # end sub option_accept
1745              
1746              
1747             sub option_callback {
1748 0     0 0 0 my ($self, $callback) = @_;
1749             my (
1750 0         0 $prev,
1751             $s,
1752             );
1753              
1754 0         0 $s = *$self->{net_telnet};
1755 0         0 $prev = $s->{opt_cback};
1756              
1757 0 0       0 if (@_ >= 2) {
1758 0 0 0     0 unless (defined $callback and ref($callback) eq "CODE") {
1759 0         0 &_carp($self, "ignoring Option_callback argument because it's " .
1760             "not a code ref");
1761 0         0 $callback = $prev;
1762             }
1763              
1764 0         0 $s->{opt_cback} = $callback;
1765             }
1766              
1767 0         0 $prev;
1768             } # end sub option_callback
1769              
1770              
1771             sub option_log {
1772 0     0 1 0 my ($self, $name) = @_;
1773             my (
1774 0         0 $fh,
1775             $s,
1776             );
1777              
1778 0         0 $s = *$self->{net_telnet};
1779 0         0 $fh = $s->{opt_log};
1780              
1781 0 0       0 if (@_ >= 2) {
1782 0 0 0     0 if (!defined($name) or $name eq "") { # input arg is ""
    0          
    0          
1783             ## Turn off logging.
1784 0         0 $fh = "";
1785             }
1786             elsif (&_is_open_fh($name)) { # input arg is an open fh
1787             ## Use the open fh for logging.
1788 0         0 $fh = $name;
1789 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1790             }
1791             elsif (!ref $name) { # input arg is filename
1792             ## Open the file for logging.
1793 0 0       0 $fh = &_fname_to_handle($self, $name)
1794             or return;
1795 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1796             }
1797             else {
1798 0         0 return $self->error("bad Option_log argument ",
1799             "\"$name\": not filename or open fh");
1800             }
1801              
1802 0         0 $s->{opt_log} = $fh;
1803             }
1804              
1805 0         0 $fh;
1806             } # end sub option_log
1807              
1808              
1809             sub option_state {
1810 0     0 1 0 my ($self, $option) = @_;
1811             my (
1812 0         0 $opt_state,
1813             $s,
1814             %opt_state,
1815             );
1816              
1817             ## Ensure telnet option is non-negative integer.
1818 0         0 $option = &_verify_telopt_arg($self, $option);
1819 0 0       0 return unless defined $option;
1820              
1821             ## Init.
1822 0         0 $s = *$self->{net_telnet};
1823 0 0       0 unless (defined $s->{opts}{$option}) {
1824 0         0 &_set_default_option($s, $option);
1825             }
1826              
1827             ## Return hashref to a copy of the values.
1828 0         0 $opt_state = $s->{opts}{$option};
1829 0         0 %opt_state = %$opt_state;
1830 0         0 \%opt_state;
1831             } # end sub option_state
1832              
1833              
1834             ## Make ors() synonymous with output_record_separator().
1835 0     0 1 0 sub ors { &output_record_separator; }
1836              
1837              
1838             sub output_field_separator {
1839 0     0 1 0 my ($self, $ofs) = @_;
1840             my (
1841 0         0 $prev,
1842             $s,
1843             );
1844              
1845 0         0 $s = *$self->{net_telnet};
1846 0         0 $prev = $s->{"ofs"};
1847              
1848 0 0       0 if (@_ >= 2) {
1849 0 0       0 unless (defined $ofs) {
1850 0         0 $ofs = "";
1851             }
1852              
1853 0         0 $s->{"ofs"} = $ofs;
1854             }
1855              
1856 0         0 $prev;
1857             } # end sub output_field_separator
1858              
1859              
1860             sub output_log {
1861 0     0 1 0 my ($self, $name) = @_;
1862             my (
1863 0         0 $fh,
1864             $s,
1865             );
1866              
1867 0         0 $s = *$self->{net_telnet};
1868 0         0 $fh = $s->{outputlog};
1869              
1870 0 0       0 if (@_ >= 2) {
1871 0 0 0     0 if (!defined($name) or $name eq "") { # input arg is ""
    0          
    0          
1872             ## Turn off logging.
1873 0         0 $fh = "";
1874             }
1875             elsif (&_is_open_fh($name)) { # input arg is an open fh
1876             ## Use the open fh for logging.
1877 0         0 $fh = $name;
1878 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1879             }
1880             elsif (!ref $name) { # input arg is filename
1881             ## Open the file for logging.
1882 0 0       0 $fh = &_fname_to_handle($self, $name)
1883             or return;
1884 0         0 select((select($fh), $|=1)[$[]); # don't buffer writes
1885             }
1886             else {
1887 0         0 return $self->error("bad Output_log argument ",
1888             "\"$name\": not filename or open fh");
1889             }
1890              
1891 0         0 $s->{outputlog} = $fh;
1892             }
1893              
1894 0         0 $fh;
1895             } # end sub output_log
1896              
1897              
1898             sub output_record_separator {
1899 0     0 1 0 my ($self, $ors) = @_;
1900             my (
1901 0         0 $prev,
1902             $s,
1903             );
1904              
1905 0         0 $s = *$self->{net_telnet};
1906 0         0 $prev = $s->{"ors"};
1907              
1908 0 0       0 if (@_ >= 2) {
1909 0 0       0 unless (defined $ors) {
1910 0         0 $ors = "";
1911             }
1912              
1913 0         0 $s->{"ors"} = $ors;
1914             }
1915              
1916 0         0 $prev;
1917             } # end sub output_record_separator
1918              
1919              
1920             sub peerhost {
1921 0     0 1 0 my ($self) = @_;
1922             my (
1923 0         0 $host,
1924             $sockaddr,
1925             );
1926 0         0 local $^W = ''; # avoid closed socket warning from getpeername()
1927              
1928             ## Get packed sockaddr struct of remote side and then unpack it.
1929 0 0       0 $sockaddr = getpeername $self
1930             or return "";
1931 0         0 (undef, $host) = $self->_unpack_sockaddr($sockaddr);
1932              
1933 0         0 $host;
1934             } # end sub peerhost
1935              
1936              
1937             sub peerport {
1938 0     0 1 0 my ($self) = @_;
1939             my (
1940 0         0 $port,
1941             $sockaddr,
1942             );
1943 0         0 local $^W = ''; # avoid closed socket warning from getpeername()
1944              
1945             ## Get packed sockaddr struct of remote side and then unpack it.
1946 0 0       0 $sockaddr = getpeername $self
1947             or return "";
1948 0         0 ($port) = $self->_unpack_sockaddr($sockaddr);
1949              
1950 0         0 $port;
1951             } # end sub peerport
1952              
1953              
1954             sub port {
1955 0     0 1 0 my ($self, $port) = @_;
1956             my (
1957 0         0 $prev,
1958             $s,
1959             $service,
1960             );
1961              
1962 0         0 $s = *$self->{net_telnet};
1963 0         0 $prev = $s->{port};
1964              
1965 0 0       0 if (@_ >= 2) {
1966 0 0       0 $port = &_parse_port($self, $port)
1967             or return;
1968              
1969 0         0 $s->{port} = $port;
1970             }
1971              
1972 0         0 $prev;
1973             } # end sub port
1974              
1975              
1976             sub print {
1977 0     0 1 0 my ($self) = shift;
1978             my (
1979 0         0 $buf,
1980             $fh,
1981             $s,
1982             );
1983              
1984 0         0 $s = *$self->{net_telnet};
1985 0         0 $s->{timedout} = '';
1986             return $self->error("write error: filehandle isn't open")
1987 0 0       0 unless $s->{opened};
1988              
1989             ## Add field and record separators.
1990 0         0 $buf = join($s->{"ofs"}, @_) . $s->{"ors"};
1991              
1992             ## Log the output if requested.
1993 0 0       0 if ($s->{outputlog}) {
1994 0         0 &_log_print($s->{outputlog}, $buf);
1995             }
1996              
1997             ## Convert native newlines to CR LF.
1998 0 0       0 if (!$s->{bin_mode}) {
1999 0         0 $buf =~ s(\n)(\015\012)g;
2000             }
2001              
2002             ## Escape TELNET IAC and also CR not followed by LF.
2003 0 0       0 if ($s->{telnet_mode}) {
2004 0         0 $buf =~ s(\377)(\377\377)g;
2005 0         0 &_escape_cr(\$buf);
2006             }
2007              
2008 0         0 &_put($self, \$buf, "print");
2009             } # end sub print
2010              
2011              
2012             sub print_length {
2013 0     0 1 0 my ($self) = @_;
2014              
2015 0         0 *$self->{net_telnet}{num_wrote};
2016             } # end sub print_length
2017              
2018              
2019             sub prompt {
2020 0     0 1 0 my ($self, $prompt) = @_;
2021             my (
2022 0         0 $prev,
2023             $s,
2024             );
2025              
2026 0         0 $s = *$self->{net_telnet};
2027 0         0 $prev = $s->{cmd_prompt};
2028              
2029             ## Parse args.
2030 0 0       0 if (@_ == 2) {
2031 0 0       0 $prompt = &_parse_prompt($self, $prompt)
2032             or return;
2033              
2034 0         0 $s->{cmd_prompt} = $prompt;
2035             }
2036              
2037 0         0 $prev;
2038             } # end sub prompt
2039              
2040              
2041             sub put {
2042 0     0 1 0 my ($self) = @_;
2043             my (
2044 0         0 $binmode,
2045             $buf,
2046             $errmode,
2047             $is_timeout_arg,
2048             $s,
2049             $telnetmode,
2050             $timeout,
2051             %args,
2052             );
2053 0         0 local $_;
2054              
2055             ## Init.
2056 0         0 $s = *$self->{net_telnet};
2057 0         0 $s->{timedout} = '';
2058              
2059             ## Parse args.
2060 0 0       0 if (@_ == 2) { # one positional arg given
    0          
2061 0         0 $buf = $_[1];
2062             }
2063             elsif (@_ > 2) { # named args given
2064             ## Get the named args.
2065 0         0 (undef, %args) = @_;
2066              
2067             ## Parse the named args.
2068 0         0 foreach (keys %args) {
2069 0 0       0 if (/^-?binmode$/i) {
    0          
    0          
    0          
    0          
2070 0         0 $binmode = $args{$_};
2071 0 0       0 unless (defined $binmode) {
2072 0         0 $binmode = 0;
2073             }
2074             }
2075             elsif (/^-?errmode$/i) {
2076 0         0 $errmode = &_parse_errmode($self, $args{$_});
2077             }
2078             elsif (/^-?string$/i) {
2079 0         0 $buf = $args{$_};
2080             }
2081             elsif (/^-?telnetmode$/i) {
2082 0         0 $telnetmode = $args{$_};
2083 0 0       0 unless (defined $telnetmode) {
2084 0         0 $telnetmode = 0;
2085             }
2086             }
2087             elsif (/^-?timeout$/i) {
2088 0         0 $timeout = &_parse_timeout($self, $args{$_});
2089 0         0 $is_timeout_arg = 1;
2090             }
2091             else {
2092 0         0 &_croak($self, "bad named parameter \"$_\" given ",
2093             "to " . ref($self) . "::put()");
2094             }
2095             }
2096             }
2097              
2098             ## If any args given, override corresponding instance data.
2099 0 0       0 local $s->{bin_mode} = $binmode
2100             if defined $binmode;
2101 0 0       0 local $s->{errormode} = $errmode
2102             if defined $errmode;
2103 0 0       0 local $s->{telnet_mode} = $telnetmode
2104             if defined $telnetmode;
2105 0 0       0 local $s->{time_out} = $timeout
2106             if defined $is_timeout_arg;
2107              
2108             ## Check for errors.
2109             return $self->error("write error: filehandle isn't open")
2110 0 0       0 unless $s->{opened};
2111              
2112             ## Log the output if requested.
2113 0 0       0 if ($s->{outputlog}) {
2114 0         0 &_log_print($s->{outputlog}, $buf);
2115             }
2116              
2117             ## Convert native newlines to CR LF.
2118 0 0       0 if (!$s->{bin_mode}) {
2119 0         0 $buf =~ s(\n)(\015\012)g;
2120             }
2121              
2122             ## Escape TELNET IAC and also CR not followed by LF.
2123 0 0       0 if ($s->{telnet_mode}) {
2124 0         0 $buf =~ s(\377)(\377\377)g;
2125 0         0 &_escape_cr(\$buf);
2126             }
2127              
2128 0         0 &_put($self, \$buf, "put");
2129             } # end sub put
2130              
2131              
2132             ## Make rs() synonymous input_record_separator().
2133 0     0 1 0 sub rs { &input_record_separator; }
2134              
2135              
2136             sub sockfamily {
2137 0     0 1 0 my ($self) = @_;
2138 0         0 my $s = *$self->{net_telnet};
2139 0         0 my $sockfamily = "";
2140              
2141 0 0 0     0 if ($s->{sock_family} == AF_INET) {
    0          
2142 0         0 $sockfamily = "ipv4";
2143             }
2144             elsif (defined($AF_INET6) and $s->{sock_family} == $AF_INET6) {
2145 0         0 $sockfamily = "ipv6";
2146             }
2147              
2148 0         0 $sockfamily;
2149             } # end sub sockfamily
2150              
2151              
2152             sub sockhost {
2153 0     0 1 0 my ($self) = @_;
2154             my (
2155 0         0 $host,
2156             $sockaddr,
2157             );
2158 0         0 local $^W = ''; # avoid closed socket warning from getsockname()
2159              
2160             ## Get packed sockaddr struct of local side and then unpack it.
2161 0 0       0 $sockaddr = getsockname $self
2162             or return "";
2163 0         0 (undef, $host) = $self->_unpack_sockaddr($sockaddr);
2164              
2165 0         0 $host;
2166             } # end sub sockhost
2167              
2168              
2169             sub sockport {
2170 0     0 1 0 my ($self) = @_;
2171             my (
2172 0         0 $port,
2173             $sockaddr,
2174             );
2175 0         0 local $^W = ''; # avoid closed socket warning from getsockname()
2176              
2177             ## Get packed sockaddr struct of local side and then unpack it.
2178 0 0       0 $sockaddr = getsockname $self
2179             or return "";
2180 0         0 ($port) = $self->_unpack_sockaddr($sockaddr);
2181              
2182 0         0 $port;
2183             } # end sub sockport
2184              
2185              
2186             sub suboption_callback {
2187 0     0 0 0 my ($self, $callback) = @_;
2188             my (
2189 0         0 $prev,
2190             $s,
2191             );
2192              
2193 0         0 $s = *$self->{net_telnet};
2194 0         0 $prev = $s->{subopt_cback};
2195              
2196 0 0       0 if (@_ >= 2) {
2197 0 0 0     0 unless (defined $callback and ref($callback) eq "CODE") {
2198 0         0 &_carp($self,"ignoring Suboption_callback argument because it's " .
2199             "not a code ref");
2200 0         0 $callback = $prev;
2201             }
2202              
2203 0         0 $s->{subopt_cback} = $callback;
2204             }
2205              
2206 0         0 $prev;
2207             } # end sub suboption_callback
2208              
2209              
2210             sub telnetmode {
2211 0     0 1 0 my ($self, $mode) = @_;
2212             my (
2213 0         0 $prev,
2214             $s,
2215             );
2216              
2217 0         0 $s = *$self->{net_telnet};
2218 0         0 $prev = $s->{telnet_mode};
2219              
2220 0 0       0 if (@_ >= 2) {
2221 0 0       0 unless (defined $mode) {
2222 0         0 $mode = 0;
2223             }
2224              
2225 0         0 $s->{telnet_mode} = $mode;
2226             }
2227              
2228 0         0 $prev;
2229             } # end sub telnetmode
2230              
2231              
2232             sub timed_out {
2233 0     0 1 0 my ($self, $value) = @_;
2234             my (
2235 0         0 $prev,
2236             $s,
2237             );
2238              
2239 0         0 $s = *$self->{net_telnet};
2240 0         0 $prev = $s->{timedout};
2241              
2242 0 0       0 if (@_ >= 2) {
2243 0 0       0 unless (defined $value) {
2244 0         0 $value = "";
2245             }
2246              
2247 0         0 $s->{timedout} = $value;
2248             }
2249              
2250 0         0 $prev;
2251             } # end sub timed_out
2252              
2253              
2254             sub timeout {
2255 0     0 1 0 my ($self, $timeout) = @_;
2256             my (
2257 0         0 $prev,
2258             $s,
2259             );
2260              
2261 0         0 $s = *$self->{net_telnet};
2262 0         0 $prev = $s->{time_out};
2263              
2264 0 0       0 if (@_ >= 2) {
2265 0         0 $s->{time_out} = &_parse_timeout($self, $timeout);
2266             }
2267              
2268 0         0 $prev;
2269             } # end sub timeout
2270              
2271              
2272             sub waitfor {
2273 0     0 1 0 my ($self, @args) = @_;
2274             my (
2275 0         0 $arg,
2276             $binmode,
2277             $endtime,
2278             $errmode,
2279             $len,
2280             $match,
2281             $match_op,
2282             $pos,
2283             $prematch,
2284             $s,
2285             $search,
2286             $search_cond,
2287             $telnetmode,
2288             $timeout,
2289             @match_cond,
2290             @match_ops,
2291             @search_cond,
2292             @string_cond,
2293             @warns,
2294             );
2295 0         0 local $@;
2296 0         0 local $_;
2297              
2298             ## Init.
2299 0         0 $s = *$self->{net_telnet};
2300 0         0 $s->{timedout} = '';
2301 0 0       0 return if $s->{eofile};
2302 0 0       0 return unless @args;
2303 0         0 $timeout = $s->{time_out};
2304              
2305             ## Code template used to build string match conditional.
2306             ## Values between array elements must be supplied later.
2307 0         0 @string_cond =
2308             ('if (($pos = index $s->{buf}, ', ') > -1) {
2309             $len = ', ';
2310             $prematch = substr $s->{buf}, 0, $pos;
2311             $match = substr $s->{buf}, $pos, $len;
2312             substr($s->{buf}, 0, $pos + $len) = "";
2313             last;
2314             }');
2315              
2316             ## Code template used to build pattern match conditional.
2317             ## Values between array elements must be supplied later.
2318 0         0 @match_cond =
2319             ('if ($s->{buf} =~ ', ') {
2320             $prematch = $`;
2321             $match = $&;
2322             substr($s->{buf}, 0, length($`) + length($&)) = "";
2323             last;
2324             }');
2325              
2326             ## Parse args.
2327 0 0       0 if (@_ == 2) { # one positional arg given
    0          
2328 0         0 $arg = $_[1];
2329              
2330             ## Fill in the blanks in the code template.
2331 0         0 push @match_ops, $arg;
2332 0         0 push @search_cond, join("", $match_cond[0], $arg, $match_cond[1]);
2333             }
2334             elsif (@_ > 2) { # named args given
2335             ## Parse the named args.
2336 0         0 while (($_, $arg) = splice @args, 0, 2) {
2337 0 0       0 if (/^-?binmode$/i) {
    0          
    0          
    0          
    0          
    0          
2338 0         0 $binmode = $arg;
2339 0 0       0 unless (defined $binmode) {
2340 0         0 $binmode = 0;
2341             }
2342             }
2343             elsif (/^-?errmode$/i) {
2344 0         0 $errmode = &_parse_errmode($self, $arg);
2345             }
2346             elsif (/^-?match$/i) {
2347             ## Fill in the blanks in the code template.
2348 0         0 push @match_ops, $arg;
2349 0         0 push @search_cond, join("",
2350             $match_cond[0], $arg, $match_cond[1]);
2351             }
2352             elsif (/^-?string$/i) {
2353             ## Fill in the blanks in the code template.
2354 0         0 $arg =~ s/'/\\'/g; # quote ticks
2355 0         0 push @search_cond, join("",
2356             $string_cond[0], "'$arg'",
2357             $string_cond[1], length($arg),
2358             $string_cond[2]);
2359             }
2360             elsif (/^-?telnetmode$/i) {
2361 0         0 $telnetmode = $arg;
2362 0 0       0 unless (defined $telnetmode) {
2363 0         0 $telnetmode = 0;
2364             }
2365             }
2366             elsif (/^-?timeout$/i) {
2367 0         0 $timeout = &_parse_timeout($self, $arg);
2368             }
2369             else {
2370 0         0 &_croak($self, "bad named parameter \"$_\" given " .
2371             "to " . ref($self) . "::waitfor()");
2372             }
2373             }
2374             }
2375              
2376             ## If any args given, override corresponding instance data.
2377 0 0       0 local $s->{errormode} = $errmode
2378             if defined $errmode;
2379 0 0       0 local $s->{bin_mode} = $binmode
2380             if defined $binmode;
2381 0 0       0 local $s->{telnet_mode} = $telnetmode
2382             if defined $telnetmode;
2383              
2384             ## Check for bad match operator argument.
2385 0         0 foreach $match_op (@match_ops) {
2386 0 0 0     0 return $self->error("missing opening delimiter of match operator ",
2387             "in argument \"$match_op\" given to ",
2388             ref($self) . "::waitfor()")
2389             unless $match_op =~ m(^\s*/) or $match_op =~ m(^\s*m\s*\W);
2390             }
2391              
2392             ## Construct conditional to check for requested string and pattern matches.
2393             ## Turn subsequent "if"s into "elsif".
2394 0         0 $search_cond = join "\n\tels", @search_cond;
2395              
2396             ## Construct loop to fill buffer until string/pattern, timeout, or eof.
2397 0         0 $search = join "", "
2398             while (1) {\n\t",
2399             $search_cond, '
2400             &_fillbuf($self, $s, $endtime)
2401             or do {
2402             last if $s->{timedout};
2403             $self->close;
2404             last;
2405             };
2406             }';
2407              
2408             ## Set wall time when we timeout.
2409 0         0 $endtime = &_endtime($timeout);
2410              
2411             ## Run the loop.
2412             {
2413 0         0 local $^W = 1;
  0         0  
2414 0     0   0 local $SIG{"__WARN__"} = sub { push @warns, @_ };
  0         0  
2415 0         0 local $s->{errormode} = "return";
2416 0         0 $s->{errormsg} = "";
2417 0         0 eval $search;
2418             }
2419              
2420             ## Check for failure.
2421 0 0       0 return $self->error("pattern match timed-out") if $s->{timedout};
2422 0 0       0 return $self->error($s->{errormsg}) if $s->{errormsg} ne "";
2423 0 0       0 return $self->error("pattern match read eof") if $s->{eofile};
2424              
2425             ## Check for Perl syntax errors or warnings.
2426 0 0 0     0 if ($@ or @warns) {
2427 0         0 foreach $match_op (@match_ops) {
2428 0 0       0 &_match_check($self, $match_op)
2429             or return;
2430             }
2431 0 0       0 return $self->error($@) if $@;
2432 0 0       0 return $self->error(@warns) if @warns;
2433             }
2434              
2435 0 0       0 wantarray ? ($prematch, $match) : 1;
2436             } # end sub waitfor
2437              
2438              
2439             ######################## Private Subroutines #########################
2440              
2441              
2442             sub _append_lineno {
2443 0     0   0 my ($obj, @msgs) = @_;
2444             my (
2445 0         0 $file,
2446             $line,
2447             $pkg,
2448             );
2449              
2450             ## Find the caller that's not in object's class or one of its base classes.
2451 0         0 ($pkg, $file , $line) = &_user_caller($obj);
2452 0         0 join("", @msgs, " at ", $file, " line ", $line, "\n");
2453             } # end sub _append_lineno
2454              
2455              
2456             sub _carp {
2457 0     0   0 my ($self) = @_;
2458 0         0 my $s = *$self->{net_telnet};
2459              
2460 0         0 $s->{errormsg} = &_append_lineno(@_);
2461 0         0 warn $s->{errormsg}, "\n";
2462             } # end sub _carp
2463              
2464              
2465             sub _croak {
2466 0     0   0 my ($self) = @_;
2467 0         0 my $s = *$self->{net_telnet};
2468              
2469 0         0 $s->{errormsg} = &_append_lineno(@_);
2470 0         0 die $s->{errormsg}, "\n";
2471             } # end sub _croak
2472              
2473              
2474             sub _endtime {
2475 0     0   0 my ($interval) = @_;
2476              
2477             ## Compute wall time when timeout occurs.
2478 0 0       0 if (defined $interval) {
2479 0 0       0 if ($interval >= $^T) { # it's already an absolute time
    0          
2480 0         0 return $interval;
2481             }
2482             elsif ($interval > 0) { # it's relative to the current time
2483 0         0 return int($interval + time + 0.5);
2484             }
2485             else { # it's a one time poll
2486 0         0 return 0;
2487             }
2488             }
2489             else { # there's no timeout
2490 0         0 return undef;
2491             }
2492             } # end sub _endtime
2493              
2494              
2495             sub _errno_include {
2496 0     0   0 local $@;
2497 0         0 local $SIG{"__DIE__"} = "DEFAULT";
2498              
2499 0         0 eval "require Errno";
2500             } # end sub errno_include
2501              
2502              
2503             sub _escape_cr {
2504 0     0   0 my ($string) = @_;
2505             my (
2506 0         0 $nextchar,
2507             );
2508 0         0 my $pos = 0;
2509              
2510             ## Convert all CR (not followed by LF) to CR NULL.
2511 0         0 while (($pos = index($$string, "\015", $pos)) > -1) {
2512 0         0 $nextchar = substr $$string, $pos + 1, 1;
2513              
2514 0 0       0 substr($$string, $pos, 1) = "\015\000"
2515             unless $nextchar eq "\012";
2516              
2517 0         0 $pos++;
2518             }
2519              
2520 0         0 1;
2521             } # end sub _escape_cr
2522              
2523              
2524             sub _extract_arg_errmode {
2525 0     0   0 my ($self, $args) = @_;
2526             my (
2527 0         0 %args,
2528             );
2529 0         0 local $_;
2530 0         0 my $errmode = '';
2531              
2532             ## Check for named parameters.
2533 0 0       0 return '' unless @$args >= 2;
2534              
2535             ## Rebuild args without errmode parameter.
2536 0         0 %args = @$args;
2537 0         0 @$args = ();
2538              
2539             ## Extract errmode arg.
2540 0         0 foreach (keys %args) {
2541 0 0       0 if (/^-?errmode$/i) {
2542 0         0 $errmode = &_parse_errmode($self, $args{$_});
2543             }
2544             else {
2545 0         0 push @$args, $_, $args{$_};
2546             }
2547             }
2548              
2549 0         0 $errmode;
2550             } # end sub _extract_arg_errmode
2551              
2552              
2553             sub _fillbuf {
2554 0     0   0 my ($self, $s, $endtime) = @_;
2555             my (
2556 0         0 $msg,
2557             $nfound,
2558             $nread,
2559             $pushback_len,
2560             $read_pos,
2561             $ready,
2562             $timed_out,
2563             $timeout,
2564             $unparsed_pos,
2565             );
2566              
2567             ## If error from last read not yet reported then do it now.
2568 0 0       0 if ($s->{pending_errormsg}) {
2569 0         0 $msg = $s->{pending_errormsg};
2570 0         0 $s->{pending_errormsg} = "";
2571 0         0 return $self->error($msg);
2572             }
2573              
2574 0 0       0 return unless $s->{opened};
2575              
2576 0         0 while (1) {
2577             ## Maximum buffer size exceeded?
2578             return $self->error("maximum input buffer length exceeded: ",
2579             $s->{maxbufsize}, " bytes")
2580 0 0       0 unless length($s->{buf}) <= $s->{maxbufsize};
2581              
2582             ## Determine how long to wait for input ready.
2583 0         0 ($timed_out, $timeout) = &_timeout_interval($endtime);
2584 0 0       0 if ($timed_out) {
2585 0         0 $s->{timedout} = 1;
2586 0         0 return $self->error("read timed-out");
2587             }
2588              
2589             ## Wait for input ready.
2590 0         0 $nfound = select $ready=$s->{fdmask}, "", "", $timeout;
2591              
2592             ## Handle any errors while waiting.
2593 0 0 0     0 if ((!defined $nfound or $nfound <= 0) and $s->{select_supported}) {
      0        
2594 0 0 0     0 if (defined $nfound and $nfound == 0) { # timed-out
2595 0         0 $s->{timedout} = 1;
2596 0         0 return $self->error("read timed-out");
2597             }
2598             else { # error waiting for input ready
2599 0 0       0 if (defined $EINTR) {
2600 0 0       0 next if $! == $EINTR; # restart select()
2601             }
2602             else {
2603 0 0       0 next if $! =~ /^interrupted/i; # restart select()
2604             }
2605              
2606 0         0 $s->{opened} = '';
2607 0         0 return $self->error("read error: $!");
2608             }
2609             }
2610              
2611             ## Append to buffer any partially processed telnet or CR sequence.
2612 0         0 $pushback_len = length $s->{pushback_buf};
2613 0 0       0 if ($pushback_len) {
2614 0         0 $s->{buf} .= $s->{pushback_buf};
2615 0         0 $s->{pushback_buf} = "";
2616             }
2617              
2618             ## Read the waiting data.
2619 0         0 $read_pos = length $s->{buf};
2620 0         0 $unparsed_pos = $read_pos - $pushback_len;
2621 0         0 $nread = sysread $self, $s->{buf}, $s->{blksize}, $read_pos;
2622              
2623             ## Handle any read errors.
2624 0 0       0 if (!defined $nread) { # read failed
2625 0 0       0 if (defined $EINTR) {
2626 0 0       0 next if $! == $EINTR; # restart sysread()
2627             }
2628             else {
2629 0 0       0 next if $! =~ /^interrupted/i; # restart sysread()
2630             }
2631              
2632 0         0 $s->{opened} = '';
2633 0         0 return $self->error("read error: $!");
2634             }
2635              
2636             ## Handle eof.
2637 0 0       0 if ($nread == 0) { # eof read
2638 0         0 $s->{opened} = '';
2639 0         0 return;
2640             }
2641              
2642             ## Display network traffic if requested.
2643 0 0       0 if ($s->{dumplog}) {
2644 0         0 &_log_dump('<', $s->{dumplog}, \$s->{buf}, $read_pos);
2645             }
2646              
2647             ## Process any telnet commands in the data stream.
2648 0 0 0     0 if ($s->{telnet_mode} and index($s->{buf},"\377",$unparsed_pos) > -1) {
2649 0         0 &_interpret_tcmd($self, $s, $unparsed_pos);
2650             }
2651              
2652             ## Process any carriage-return sequences in the data stream.
2653 0         0 &_interpret_cr($s, $unparsed_pos);
2654              
2655             ## Read again if all chars read were consumed as telnet cmds.
2656 0 0       0 next if $unparsed_pos >= length $s->{buf};
2657              
2658             ## Log the input if requested.
2659 0 0       0 if ($s->{inputlog}) {
2660 0         0 &_log_print($s->{inputlog}, substr($s->{buf}, $unparsed_pos));
2661             }
2662              
2663             ## Save the last line read.
2664 0         0 &_save_lastline($s);
2665              
2666             ## We've successfully read some data into the buffer.
2667 0         0 last;
2668             } # end while(1)
2669              
2670 0         0 1;
2671             } # end sub _fillbuf
2672              
2673              
2674             sub _flush_opts {
2675 0     0   0 my ($self) = @_;
2676             my (
2677 0         0 $option_chars,
2678             );
2679 0         0 my $s = *$self->{net_telnet};
2680              
2681             ## Get option and clear the output buf.
2682 0         0 $option_chars = $s->{unsent_opts};
2683 0         0 $s->{unsent_opts} = "";
2684              
2685             ## Try to send options without waiting.
2686             {
2687 0         0 local $s->{errormode} = "return";
  0         0  
2688 0         0 local $s->{time_out} = 0;
2689             &_put($self, \$option_chars, "telnet option negotiation")
2690 0 0       0 or do {
2691             ## Save chars not printed for later.
2692 0         0 substr($option_chars, 0, $self->print_length) = "";
2693 0         0 $s->{unsent_opts} .= $option_chars;
2694             };
2695             }
2696              
2697 0         0 1;
2698             } # end sub _flush_opts
2699              
2700              
2701             sub _fname_to_handle {
2702 0     0   0 my ($self, $filename) = @_;
2703             my (
2704 0         0 $fh,
2705             );
2706 1     1   11 no strict "refs";
  1         2  
  1         5284  
2707              
2708 0         0 $fh = &_new_handle();
2709 0 0       0 CORE::open $fh, "> $filename"
2710             or return $self->error("problem creating $filename: $!");
2711              
2712 0         0 $fh;
2713             } # end sub _fname_to_handle
2714              
2715              
2716             sub _have_alarm {
2717 0     0   0 local $@;
2718              
2719 0         0 eval {
2720 0         0 local $SIG{"__DIE__"} = "DEFAULT";
2721 0     0   0 local $SIG{ALRM} = sub { die };
  0         0  
2722 0         0 alarm 0;
2723             };
2724              
2725 0         0 ! $@;
2726             } # end sub _have_alarm
2727              
2728              
2729             sub _import_af_inet6 {
2730 1     1   2 local $@;
2731              
2732 1         3 eval {
2733 1         7 local $SIG{"__DIE__"} = "DEFAULT";
2734              
2735 1         5 Socket::AF_INET6();
2736             };
2737             } # end sub _import_af_inet6
2738              
2739              
2740             sub _import_af_unspec {
2741 1     1   9 local $@;
2742              
2743 1         2 eval {
2744 1         3 local $SIG{"__DIE__"} = "DEFAULT";
2745              
2746 1         10 Socket::AF_UNSPEC();
2747             };
2748             } # end sub _import_af_unspec
2749              
2750              
2751             sub _import_ai_addrconfig {
2752 1     1   1 local $@;
2753              
2754 1         2 eval {
2755 1         3 local $SIG{"__DIE__"} = "DEFAULT";
2756              
2757 1         4 Socket::AI_ADDRCONFIG();
2758             };
2759             } # end sub _import_ai_addrconfig
2760              
2761              
2762             sub _import_eai_badflags {
2763 1     1   2 local $@;
2764              
2765 1         1 eval {
2766 1         3 local $SIG{"__DIE__"} = "DEFAULT";
2767              
2768 1         4 Socket::EAI_BADFLAGS();
2769             };
2770             } # end sub _import_eai_badflags
2771              
2772              
2773             sub _import_eintr {
2774 1     1   2 local $@;
2775 1         2 local $SIG{"__DIE__"} = "DEFAULT";
2776              
2777 1         68 eval "require Errno; Errno::EINTR();";
2778             } # end sub _import_eintr
2779              
2780              
2781             sub _interpret_cr {
2782 0     0     my ($s, $pos) = @_;
2783             my (
2784 0           $nextchar,
2785             );
2786              
2787 0           while (($pos = index($s->{buf}, "\015", $pos)) > -1) {
2788 0           $nextchar = substr($s->{buf}, $pos + 1, 1);
2789 0 0 0       if ($nextchar eq "\0") {
    0 0        
    0          
2790             ## Convert CR NULL to CR when in telnet mode.
2791 0 0         if ($s->{telnet_mode}) {
2792 0           substr($s->{buf}, $pos + 1, 1) = "";
2793             }
2794             }
2795             elsif ($nextchar eq "\012") {
2796             ## Convert CR LF to newline when not in binary mode.
2797 0 0         if (!$s->{bin_mode}) {
2798 0           substr($s->{buf}, $pos, 2) = "\n";
2799             }
2800             }
2801             elsif (!length($nextchar) and ($s->{telnet_mode} or !$s->{bin_mode})) {
2802             ## Save CR in alt buffer for possible CR LF or CR NULL conversion.
2803 0           $s->{pushback_buf} .= "\015";
2804 0           chop $s->{buf};
2805             }
2806              
2807 0           $pos++;
2808             }
2809              
2810 0           1;
2811             } # end sub _interpret_cr
2812              
2813              
2814             sub _interpret_tcmd {
2815 0     0     my ($self, $s, $offset) = @_;
2816             my (
2817 0           $callback,
2818             $endpos,
2819             $nextchar,
2820             $option,
2821             $parameters,
2822             $pos,
2823             $subcmd,
2824             );
2825 0           local $_;
2826              
2827             ## Parse telnet commands in the data stream.
2828 0           $pos = $offset;
2829 0           while (($pos = index $s->{buf}, "\377", $pos) > -1) { # unprocessed IAC
2830 0           $nextchar = substr $s->{buf}, $pos + 1, 1;
2831              
2832             ## Save command if it's only partially read.
2833 0 0         if (!length $nextchar) {
2834 0           $s->{pushback_buf} .= "\377";
2835 0           chop $s->{buf};
2836 0           last;
2837             }
2838              
2839 0 0 0       if ($nextchar eq "\377") { # IAC is escaping "\377" char
    0 0        
    0 0        
2840             ## Remove escape char from data stream.
2841 0           substr($s->{buf}, $pos, 1) = "";
2842 0           $pos++;
2843             }
2844             elsif ($nextchar eq "\375" or $nextchar eq "\373" or
2845             $nextchar eq "\374" or $nextchar eq "\376") { # opt negotiation
2846 0           $option = substr $s->{buf}, $pos + 2, 1;
2847              
2848             ## Save command if it's only partially read.
2849 0 0         if (!length $option) {
2850 0           $s->{pushback_buf} .= "\377" . $nextchar;
2851 0           chop $s->{buf};
2852 0           chop $s->{buf};
2853 0           last;
2854             }
2855              
2856             ## Remove command from data stream.
2857 0           substr($s->{buf}, $pos, 3) = "";
2858              
2859             ## Handle option negotiation.
2860 0           &_negotiate_recv($self, $s, $nextchar, ord($option), $pos);
2861             }
2862             elsif ($nextchar eq "\372") { # start of subnegotiation parameters
2863             ## Save command if it's only partially read.
2864 0           $endpos = index $s->{buf}, "\360", $pos;
2865 0 0         if ($endpos == -1) {
2866 0           $s->{pushback_buf} .= substr $s->{buf}, $pos;
2867 0           substr($s->{buf}, $pos) = "";
2868 0           last;
2869             }
2870              
2871             ## Remove subnegotiation cmd from buffer.
2872 0           $subcmd = substr($s->{buf}, $pos, $endpos - $pos + 1);
2873 0           substr($s->{buf}, $pos, $endpos - $pos + 1) = "";
2874              
2875             ## Invoke subnegotiation callback.
2876 0 0 0       if ($s->{subopt_cback} and length($subcmd) >= 5) {
2877 0           $option = unpack "C", substr($subcmd, 2, 1);
2878 0 0         if (length($subcmd) >= 6) {
2879 0           $parameters = substr $subcmd, 3, length($subcmd) - 5;
2880             }
2881             else {
2882 0           $parameters = "";
2883             }
2884              
2885 0           $callback = $s->{subopt_cback};
2886 0           &$callback($self, $option, $parameters);
2887             }
2888             }
2889             else { # various two char telnet commands
2890             ## Ignore and remove command from data stream.
2891 0           substr($s->{buf}, $pos, 2) = "";
2892             }
2893             }
2894              
2895             ## Try to send any waiting option negotiation.
2896 0 0         if (length $s->{unsent_opts}) {
2897 0           &_flush_opts($self);
2898             }
2899              
2900 0           1;
2901             } # end sub _interpret_tcmd
2902              
2903              
2904             sub _io_socket_include {
2905 0     0     local $@;
2906 0           local $SIG{"__DIE__"} = "DEFAULT";
2907              
2908 0           eval "require IO::Socket";
2909             } # end sub io_socket_include
2910              
2911              
2912             sub _is_open_fh {
2913 0     0     my ($fh) = @_;
2914 0           my $is_open = '';
2915 0           local $@;
2916              
2917 0           eval {
2918 0           local $SIG{"__DIE__"} = "DEFAULT";
2919 0           $is_open = defined(fileno $fh);
2920             };
2921              
2922 0           $is_open;
2923             } # end sub _is_open_fh
2924              
2925              
2926             sub _log_dump {
2927 0     0     my ($direction, $fh, $data, $offset, $len) = @_;
2928             my (
2929 0           $addr,
2930             $hexvals,
2931             $line,
2932             );
2933              
2934 0           $addr = 0;
2935 0 0         $len = length($$data) - $offset
2936             if !defined $len;
2937 0 0         return 1 if $len <= 0;
2938              
2939             ## Print data in dump format.
2940 0           while ($len > 0) {
2941             ## Convert up to the next 16 chars to hex, padding w/ spaces.
2942 0 0         if ($len >= 16) {
2943 0           $line = substr $$data, $offset, 16;
2944             }
2945             else {
2946 0           $line = substr $$data, $offset, $len;
2947             }
2948 0           $hexvals = unpack("H*", $line);
2949 0           $hexvals .= ' ' x (32 - length $hexvals);
2950              
2951             ## Place in 16 columns, each containing two hex digits.
2952 0           $hexvals = sprintf("%s %s %s %s " x 4,
2953             unpack("a2" x 16, $hexvals));
2954              
2955             ## For the ASCII column, change unprintable chars to a period.
2956 0           $line =~ s/[\000-\037,\177-\237]/./g;
2957              
2958             ## Print the line in dump format.
2959 0           &_log_print($fh, sprintf("%s 0x%5.5lx: %s%s\n",
2960             $direction, $addr, $hexvals, $line));
2961              
2962 0           $addr += 16;
2963 0           $offset += 16;
2964 0           $len -= 16;
2965             }
2966              
2967 0           &_log_print($fh, "\n");
2968              
2969 0           1;
2970             } # end sub _log_dump
2971              
2972              
2973             sub _log_option {
2974 0     0     my ($fh, $direction, $request, $option) = @_;
2975             my (
2976 0           $name,
2977             );
2978              
2979 0 0 0       if ($option >= 0 and $option <= $#Telopts) {
2980 0           $name = $Telopts[$option];
2981             }
2982             else {
2983 0           $name = $option;
2984             }
2985              
2986 0           &_log_print($fh, "$direction $request $name\n");
2987             } # end sub _log_option
2988              
2989              
2990             sub _log_print {
2991 0     0     my ($fh, $buf) = @_;
2992 0           local $\ = '';
2993              
2994 0 0         if (ref($fh) eq "GLOB") { # fh is GLOB ref
2995 0           print $fh $buf;
2996             }
2997             else { # fh isn't GLOB ref
2998 0           $fh->print($buf);
2999             }
3000             } # end sub _log_print
3001              
3002              
3003             sub _match_check {
3004 0     0     my ($self, $code) = @_;
3005 0           my $error;
3006 0           my @warns = ();
3007 0           local $@;
3008              
3009             ## Use eval to check for syntax errors or warnings.
3010             {
3011 0           local $SIG{"__DIE__"} = "DEFAULT";
  0            
3012 0     0     local $SIG{"__WARN__"} = sub { push @warns, @_ };
  0            
3013 0           local $^W = 1;
3014 0           local $_ = '';
3015 0           eval "\$_ =~ $code;";
3016             }
3017 0 0         if ($@) {
    0          
3018             ## Remove useless lines numbers from message.
3019 0           ($error = $@) =~ s/ at \(eval \d+\) line \d+.?//;
3020 0           chomp $error;
3021 0           return $self->error("bad match operator: $error");
3022             }
3023             elsif (@warns) {
3024             ## Remove useless lines numbers from message.
3025 0           ($error = shift @warns) =~ s/ at \(eval \d+\) line \d+.?//;
3026 0           $error =~ s/ while "strict subs" in use//;
3027 0           chomp $error;
3028 0           return $self->error("bad match operator: $error");
3029             }
3030              
3031 0           1;
3032             } # end sub _match_check
3033              
3034              
3035             sub _negotiate_callback {
3036 0     0     my ($self, $opt, $is_remote, $is_enabled, $was_enabled, $opt_bufpos) = @_;
3037             my (
3038 0           $callback,
3039             $s,
3040             );
3041 0           local $_;
3042              
3043             ## Keep track of remote echo.
3044 0 0 0       if ($is_remote and $opt == &TELOPT_ECHO) { # received WILL or WONT ECHO
3045 0           $s = *$self->{net_telnet};
3046              
3047 0 0 0       if ($is_enabled and !$was_enabled) { # received WILL ECHO
    0 0        
3048 0           $s->{remote_echo} = 1;
3049             }
3050             elsif (!$is_enabled and $was_enabled) { # received WONT ECHO
3051 0           $s->{remote_echo} = '';
3052             }
3053             }
3054              
3055             ## Invoke callback, if there is one.
3056 0           $callback = $self->option_callback;
3057 0 0         if ($callback) {
3058 0           &$callback($self, $opt, $is_remote,
3059             $is_enabled, $was_enabled, $opt_bufpos);
3060             }
3061              
3062 0           1;
3063             } # end sub _negotiate_callback
3064              
3065              
3066             sub _negotiate_recv {
3067 0     0     my ($self, $s, $opt_request, $opt, $opt_bufpos) = @_;
3068              
3069             ## Ensure data structure exists for this option.
3070 0 0         unless (defined $s->{opts}{$opt}) {
3071 0           &_set_default_option($s, $opt);
3072             }
3073              
3074             ## Process the option.
3075 0 0         if ($opt_request eq "\376") { # DONT
    0          
    0          
    0          
3076             &_negotiate_recv_disable($self, $s, $opt, "dont", $opt_bufpos,
3077             $s->{opts}{$opt}{local_enable_ok},
3078             \$s->{opts}{$opt}{local_enabled},
3079 0           \$s->{opts}{$opt}{local_state});
3080             }
3081             elsif ($opt_request eq "\375") { # DO
3082             &_negotiate_recv_enable($self, $s, $opt, "do", $opt_bufpos,
3083             $s->{opts}{$opt}{local_enable_ok},
3084             \$s->{opts}{$opt}{local_enabled},
3085 0           \$s->{opts}{$opt}{local_state});
3086             }
3087             elsif ($opt_request eq "\374") { # WONT
3088             &_negotiate_recv_disable($self, $s, $opt, "wont", $opt_bufpos,
3089             $s->{opts}{$opt}{remote_enable_ok},
3090             \$s->{opts}{$opt}{remote_enabled},
3091 0           \$s->{opts}{$opt}{remote_state});
3092             }
3093             elsif ($opt_request eq "\373") { # WILL
3094             &_negotiate_recv_enable($self, $s, $opt, "will", $opt_bufpos,
3095             $s->{opts}{$opt}{remote_enable_ok},
3096             \$s->{opts}{$opt}{remote_enabled},
3097 0           \$s->{opts}{$opt}{remote_state});
3098             }
3099             else { # internal error
3100 0           die;
3101             }
3102              
3103 0           1;
3104             } # end sub _negotiate_recv
3105              
3106              
3107             sub _negotiate_recv_disable {
3108 0     0     my ($self, $s, $opt, $opt_request,
3109             $opt_bufpos, $enable_ok, $is_enabled, $state) = @_;
3110             my (
3111 0           $ack,
3112             $disable_cmd,
3113             $enable_cmd,
3114             $is_remote,
3115             $nak,
3116             $was_enabled,
3117             );
3118              
3119             ## What do we use to request enable/disable or respond with ack/nak.
3120 0 0         if ($opt_request eq "wont") {
    0          
3121 0           $enable_cmd = "\377\375" . pack("C", $opt); # do command
3122 0           $disable_cmd = "\377\376" . pack("C", $opt); # dont command
3123 0           $is_remote = 1;
3124 0           $ack = "DO";
3125 0           $nak = "DONT";
3126              
3127             &_log_option($s->{opt_log}, "RCVD", "WONT", $opt)
3128 0 0         if $s->{opt_log};
3129             }
3130             elsif ($opt_request eq "dont") {
3131 0           $enable_cmd = "\377\373" . pack("C", $opt); # will command
3132 0           $disable_cmd = "\377\374" . pack("C", $opt); # wont command
3133 0           $is_remote = '';
3134 0           $ack = "WILL";
3135 0           $nak = "WONT";
3136              
3137             &_log_option($s->{opt_log}, "RCVD", "DONT", $opt)
3138 0 0         if $s->{opt_log};
3139             }
3140             else { # internal error
3141 0           die;
3142             }
3143              
3144             ## Respond to WONT or DONT based on the current negotiation state.
3145 0 0         if ($$state eq "no") { # state is already disabled
    0          
    0          
    0          
    0          
    0          
3146             }
3147             elsif ($$state eq "yes") { # they're initiating disable
3148 0           $$is_enabled = '';
3149 0           $$state = "no";
3150              
3151             ## Send positive acknowledgment.
3152 0           $s->{unsent_opts} .= $disable_cmd;
3153             &_log_option($s->{opt_log}, "SENT", $nak, $opt)
3154 0 0         if $s->{opt_log};
3155              
3156             ## Invoke callbacks.
3157 0           &_negotiate_callback($self, $opt, $is_remote,
3158             $$is_enabled, $was_enabled, $opt_bufpos);
3159             }
3160             elsif ($$state eq "wantno") { # they sent positive ack
3161 0           $$is_enabled = '';
3162 0           $$state = "no";
3163              
3164             ## Invoke callback.
3165 0           &_negotiate_callback($self, $opt, $is_remote,
3166             $$is_enabled, $was_enabled, $opt_bufpos);
3167             }
3168             elsif ($$state eq "wantno opposite") { # pos ack but we changed our mind
3169             ## Indicate disabled but now we want to enable.
3170 0           $$is_enabled = '';
3171 0           $$state = "wantyes";
3172              
3173             ## Send queued request.
3174 0           $s->{unsent_opts} .= $enable_cmd;
3175             &_log_option($s->{opt_log}, "SENT", $ack, $opt)
3176 0 0         if $s->{opt_log};
3177              
3178             ## Invoke callback.
3179 0           &_negotiate_callback($self, $opt, $is_remote,
3180             $$is_enabled, $was_enabled, $opt_bufpos);
3181             }
3182             elsif ($$state eq "wantyes") { # they sent negative ack
3183 0           $$is_enabled = '';
3184 0           $$state = "no";
3185              
3186             ## Invoke callback.
3187 0           &_negotiate_callback($self, $opt, $is_remote,
3188             $$is_enabled, $was_enabled, $opt_bufpos);
3189             }
3190             elsif ($$state eq "wantyes opposite") { # nak but we changed our mind
3191 0           $$is_enabled = '';
3192 0           $$state = "no";
3193              
3194             ## Invoke callback.
3195 0           &_negotiate_callback($self, $opt, $is_remote,
3196             $$is_enabled, $was_enabled, $opt_bufpos);
3197             }
3198             } # end sub _negotiate_recv_disable
3199              
3200              
3201             sub _negotiate_recv_enable {
3202 0     0     my ($self, $s, $opt, $opt_request,
3203             $opt_bufpos, $enable_ok, $is_enabled, $state) = @_;
3204             my (
3205 0           $ack,
3206             $disable_cmd,
3207             $enable_cmd,
3208             $is_remote,
3209             $nak,
3210             $was_enabled,
3211             );
3212              
3213             ## What we use to send enable/disable request or send ack/nak response.
3214 0 0         if ($opt_request eq "will") {
    0          
3215 0           $enable_cmd = "\377\375" . pack("C", $opt); # do command
3216 0           $disable_cmd = "\377\376" . pack("C", $opt); # dont command
3217 0           $is_remote = 1;
3218 0           $ack = "DO";
3219 0           $nak = "DONT";
3220              
3221             &_log_option($s->{opt_log}, "RCVD", "WILL", $opt)
3222 0 0         if $s->{opt_log};
3223             }
3224             elsif ($opt_request eq "do") {
3225 0           $enable_cmd = "\377\373" . pack("C", $opt); # will command
3226 0           $disable_cmd = "\377\374" . pack("C", $opt); # wont command
3227 0           $is_remote = '';
3228 0           $ack = "WILL";
3229 0           $nak = "WONT";
3230              
3231             &_log_option($s->{opt_log}, "RCVD", "DO", $opt)
3232 0 0         if $s->{opt_log};
3233             }
3234             else { # internal error
3235 0           die;
3236             }
3237              
3238             ## Save current enabled state.
3239 0           $was_enabled = $$is_enabled;
3240              
3241             ## Respond to WILL or DO based on the current negotiation state.
3242 0 0         if ($$state eq "no") { # they're initiating enable
    0          
    0          
    0          
    0          
    0          
3243 0 0         if ($enable_ok) { # we agree they/us should enable
3244 0           $$is_enabled = 1;
3245 0           $$state = "yes";
3246              
3247             ## Send positive acknowledgment.
3248 0           $s->{unsent_opts} .= $enable_cmd;
3249             &_log_option($s->{opt_log}, "SENT", $ack, $opt)
3250 0 0         if $s->{opt_log};
3251              
3252             ## Invoke callbacks.
3253 0           &_negotiate_callback($self, $opt, $is_remote,
3254             $$is_enabled, $was_enabled, $opt_bufpos);
3255             }
3256             else { # we disagree they/us should enable
3257             ## Send negative acknowledgment.
3258 0           $s->{unsent_opts} .= $disable_cmd;
3259             &_log_option($s->{opt_log}, "SENT", $nak, $opt)
3260 0 0         if $s->{opt_log};
3261             }
3262             }
3263             elsif ($$state eq "yes") { # state is already enabled
3264             }
3265             elsif ($$state eq "wantno") { # error: our disable req answered by enable
3266 0           $$is_enabled = '';
3267 0           $$state = "no";
3268              
3269             ## Invoke callbacks.
3270 0           &_negotiate_callback($self, $opt, $is_remote,
3271             $$is_enabled, $was_enabled, $opt_bufpos);
3272             }
3273             elsif ($$state eq "wantno opposite") { # err: disable req answerd by enable
3274 0           $$is_enabled = 1;
3275 0           $$state = "yes";
3276              
3277             ## Invoke callbacks.
3278 0           &_negotiate_callback($self, $opt, $is_remote,
3279             $$is_enabled, $was_enabled, $opt_bufpos);
3280             }
3281             elsif ($$state eq "wantyes") { # they sent pos ack
3282 0           $$is_enabled = 1;
3283 0           $$state = "yes";
3284              
3285             ## Invoke callback.
3286 0           &_negotiate_callback($self, $opt, $is_remote,
3287             $$is_enabled, $was_enabled, $opt_bufpos);
3288             }
3289             elsif ($$state eq "wantyes opposite") { # pos ack but we changed our mind
3290             ## Indicate enabled but now we want to disable.
3291 0           $$is_enabled = 1;
3292 0           $$state = "wantno";
3293              
3294             ## Inform other side we changed our mind.
3295 0           $s->{unsent_opts} .= $disable_cmd;
3296             &_log_option($s->{opt_log}, "SENT", $nak, $opt)
3297 0 0         if $s->{opt_log};
3298              
3299             ## Invoke callback.
3300 0           &_negotiate_callback($self, $opt, $is_remote,
3301             $$is_enabled, $was_enabled, $opt_bufpos);
3302             }
3303              
3304 0           1;
3305             } # end sub _negotiate_recv_enable
3306              
3307              
3308             sub _new_handle {
3309 0     0     return IO::Handle->new;
3310             } # end sub _new_handle
3311              
3312              
3313             sub _next_getlines {
3314 0     0     my ($self, $s) = @_;
3315             my (
3316 0           $len,
3317             $line,
3318             $pos,
3319             @lines,
3320             );
3321              
3322             ## Fill buffer and get first line.
3323 0 0         $line = $self->getline
3324             or return;
3325 0           push @lines, $line;
3326              
3327             ## Extract subsequent lines from buffer.
3328 0           while (($pos = index($s->{buf}, $s->{"rs"})) != -1) {
3329 0           $len = $pos + length $s->{"rs"};
3330 0           push @lines, substr($s->{buf}, 0, $len);
3331 0           substr($s->{buf}, 0, $len) = "";
3332             }
3333              
3334 0           @lines;
3335             } # end sub _next_getlines
3336              
3337              
3338             sub _opt_accept {
3339 0     0     my ($self, @args) = @_;
3340             my (
3341 0           $arg,
3342             $option,
3343             $s,
3344             );
3345              
3346             ## Init.
3347 0           $s = *$self->{net_telnet};
3348              
3349 0           foreach $arg (@args) {
3350             ## Ensure data structure defined for this option.
3351 0           $option = $arg->{option};
3352 0 0         if (!defined $s->{opts}{$option}) {
3353 0           &_set_default_option($s, $option);
3354             }
3355              
3356             ## Save whether we'll accept or reject this option.
3357 0 0         if ($arg->{is_remote}) {
3358 0           $s->{opts}{$option}{remote_enable_ok} = $arg->{is_enable};
3359             }
3360             else {
3361 0           $s->{opts}{$option}{local_enable_ok} = $arg->{is_enable};
3362             }
3363             }
3364              
3365 0           1;
3366             } # end sub _opt_accept
3367              
3368              
3369             sub _optimal_blksize {
3370 0     0     my ($blksize) = @_;
3371 0           local $^W = ''; # avoid non-numeric warning for ms-windows blksize of ""
3372              
3373             ## Use default when block size is invalid.
3374 0 0 0       if (!defined $blksize or $blksize < 512 or $blksize > 1_048_576) {
      0        
3375 0           $blksize = 4096;
3376             }
3377              
3378 0           $blksize;
3379             } # end sub _optimal_blksize
3380              
3381              
3382             sub _parse_cmd_remove_mode {
3383 0     0     my ($self, $mode) = @_;
3384              
3385 0 0         if (!defined $mode) {
    0          
    0          
3386 0           $mode = 0;
3387             }
3388             elsif ($mode =~ /^\s*auto\s*$/i) {
3389 0           $mode = "auto";
3390             }
3391             elsif ($mode !~ /^\d+$/) {
3392 0           &_carp($self, "ignoring bad Cmd_remove_mode " .
3393             "argument \"$mode\": it's not \"auto\" or a " .
3394             "non-negative integer");
3395 0           $mode = *$self->{net_telnet}{cmd_rm_mode};
3396             }
3397              
3398 0           $mode;
3399             } # end sub _parse_cmd_remove_mode
3400              
3401              
3402             sub _parse_errmode {
3403 0     0     my ($self, $errmode) = @_;
3404              
3405             ## Set the error mode.
3406 0 0         if (!defined $errmode) {
    0          
    0          
    0          
    0          
3407 0           &_carp($self, "ignoring undefined Errmode argument");
3408 0           $errmode = *$self->{net_telnet}{errormode};
3409             }
3410             elsif ($errmode =~ /^\s*return\s*$/i) {
3411 0           $errmode = "return";
3412             }
3413             elsif ($errmode =~ /^\s*die\s*$/i) {
3414 0           $errmode = "die";
3415             }
3416             elsif (ref($errmode) eq "CODE") {
3417             }
3418             elsif (ref($errmode) eq "ARRAY") {
3419 0 0         unless (ref($errmode->[0]) eq "CODE") {
3420 0           &_carp($self, "ignoring bad Errmode argument: " .
3421             "first list item isn't a code ref");
3422 0           $errmode = *$self->{net_telnet}{errormode};
3423             }
3424             }
3425             else {
3426 0           &_carp($self, "ignoring bad Errmode argument \"$errmode\"");
3427 0           $errmode = *$self->{net_telnet}{errormode};
3428             }
3429              
3430 0           $errmode;
3431             } # end sub _parse_errmode
3432              
3433              
3434             sub _parse_family {
3435 0     0     my ($self, $family) = @_;
3436             my (
3437 0           $parsed_family,
3438             );
3439              
3440 0 0         unless (defined $family) {
3441 0           $family = "";
3442             }
3443              
3444 0 0         if ($family =~ /^\s*ipv4\s*$/i) { # family arg is "ipv4"
    0          
    0          
3445 0           $parsed_family = "ipv4";
3446             }
3447             elsif ($family =~ /^\s*any\s*$/i) { # family arg is "any"
3448 0 0 0       if ($Socket::VERSION >= 1.94 and defined $AF_INET6) { # has IPv6
3449 0           $parsed_family = "any";
3450             }
3451             else { # IPv6 not supported on this machine
3452 0           $parsed_family = "ipv4";
3453             }
3454             }
3455             elsif ($family =~ /^\s*ipv6\s*$/i) { # family arg is "ipv6"
3456 0 0         return $self->error("Family arg ipv6 not supported when " .
3457             "Socket.pm version < 1.94")
3458             unless $Socket::VERSION >= 1.94;
3459 0 0         return $self->error("Family arg ipv6 not supported by " .
3460             "this OS: AF_INET6 not in Socket.pm")
3461             unless defined $AF_INET6;
3462              
3463 0           $parsed_family = "ipv6";
3464             }
3465             else {
3466 0           return $self->error("bad Family argument \"$family\": " .
3467             "must be \"ipv4\", \"ipv6\", or \"any\"");
3468             }
3469              
3470 0           $parsed_family;
3471             } # end sub _parse_family
3472              
3473              
3474             sub _parse_input_record_separator {
3475 0     0     my ($self, $rs) = @_;
3476              
3477 0 0 0       unless (defined $rs and length $rs) {
3478 0           &_carp($self, "ignoring null Input_record_separator argument");
3479 0           $rs = *$self->{net_telnet}{"rs"};
3480             }
3481              
3482 0           $rs;
3483             } # end sub _parse_input_record_separator
3484              
3485              
3486             sub _parse_localfamily {
3487 0     0     my ($self, $family) = @_;
3488              
3489 0 0         unless (defined $family) {
3490 0           $family = "";
3491             }
3492              
3493 0 0         if ($family =~ /^\s*ipv4\s*$/i) { # family arg is "ipv4"
    0          
    0          
3494 0           $family = "ipv4";
3495             }
3496             elsif ($family =~ /^\s*any\s*$/i) { # family arg is "any"
3497 0 0 0       if ($Socket::VERSION >= 1.94 and defined $AF_INET6) { # has IPv6
3498 0           $family = "any";
3499             }
3500             else { # IPv6 not supported on this machine
3501 0           $family = "ipv4";
3502             }
3503             }
3504             elsif ($family =~ /^\s*ipv6\s*$/i) { # family arg is "ipv6"
3505 0 0         return $self->error("Localfamily arg ipv6 not supported when " .
3506             "Socket.pm version < 1.94")
3507             unless $Socket::VERSION >= 1.94;
3508 0 0         return $self->error("Localfamily arg ipv6 not supported by " .
3509             "this OS: AF_INET6 not in Socket.pm")
3510             unless defined $AF_INET6;
3511              
3512 0           $family = "ipv6";
3513             }
3514             else {
3515 0           return $self->error("bad Localfamily argument \"$family\": " .
3516             "must be \"ipv4\", \"ipv6\", or \"any\"");
3517             }
3518              
3519 0           $family;
3520             } # end sub _parse_localfamily
3521              
3522              
3523             sub _parse_port {
3524 0     0     my ($self, $port) = @_;
3525             my (
3526 0           $service,
3527             );
3528              
3529 0 0         unless (defined $port) {
3530 0           $port = "";
3531             }
3532              
3533 0 0         return $self->error("bad Port argument \"$port\"")
3534             unless $port;
3535              
3536 0 0         if ($port !~ /^\d+$/) { # port isn't all digits
3537 0           $service = $port;
3538 0           $port = getservbyname($service, "tcp");
3539              
3540 0 0         return $self->error("bad Port argument \"$service\": " .
3541             "it's an unknown TCP service")
3542             unless $port;
3543             }
3544              
3545 0           $port;
3546             } # end sub _parse_port
3547              
3548              
3549             sub _parse_prompt {
3550 0     0     my ($self, $prompt) = @_;
3551              
3552 0 0         unless (defined $prompt) {
3553 0           $prompt = "";
3554             }
3555              
3556 0 0 0       return $self->error("bad Prompt argument \"$prompt\": " .
3557             "missing opening delimiter of match operator")
3558             unless $prompt =~ m(^\s*/) or $prompt =~ m(^\s*m\s*\W);
3559              
3560 0           $prompt;
3561             } # end sub _parse_prompt
3562              
3563              
3564             sub _parse_timeout {
3565 0     0     my ($self, $timeout) = @_;
3566 0           local $@;
3567              
3568             ## Ensure valid timeout.
3569 0 0         if (defined $timeout) {
3570             ## Test for non-numeric or negative values.
3571 0           eval {
3572 0           local $SIG{"__DIE__"} = "DEFAULT";
3573 0     0     local $SIG{"__WARN__"} = sub { die "non-numeric\n" };
  0            
3574 0           local $^W = 1;
3575 0           $timeout *= 1;
3576             };
3577 0 0         if ($@) { # timeout arg is non-numeric
    0          
3578 0           &_carp($self,
3579             "ignoring non-numeric Timeout argument \"$timeout\"");
3580 0           $timeout = *$self->{net_telnet}{time_out};
3581             }
3582             elsif ($timeout < 0) { # timeout arg is negative
3583 0           &_carp($self, "ignoring negative Timeout argument \"$timeout\"");
3584 0           $timeout = *$self->{net_telnet}{time_out};
3585             }
3586             }
3587              
3588 0           $timeout;
3589             } # end sub _parse_timeout
3590              
3591              
3592             sub _put {
3593 0     0     my ($self, $buf, $subname) = @_;
3594             my (
3595 0           $endtime,
3596             $len,
3597             $nfound,
3598             $nwrote,
3599             $offset,
3600             $ready,
3601             $s,
3602             $timed_out,
3603             $timeout,
3604             $zero_wrote_count,
3605             );
3606              
3607             ## Init.
3608 0           $s = *$self->{net_telnet};
3609 0           $s->{num_wrote} = 0;
3610 0           $zero_wrote_count = 0;
3611 0           $offset = 0;
3612 0           $len = length $$buf;
3613 0           $endtime = &_endtime($s->{time_out});
3614              
3615             return $self->error("write error: filehandle isn't open")
3616 0 0         unless $s->{opened};
3617              
3618             ## Try to send any waiting option negotiation.
3619 0 0         if (length $s->{unsent_opts}) {
3620 0           &_flush_opts($self);
3621             }
3622              
3623             ## Write until all data blocks written.
3624 0           while ($len) {
3625             ## Determine how long to wait for output ready.
3626 0           ($timed_out, $timeout) = &_timeout_interval($endtime);
3627 0 0         if ($timed_out) {
3628 0           $s->{timedout} = 1;
3629 0           return $self->error("$subname timed-out");
3630             }
3631              
3632             ## Wait for output ready.
3633 0           $nfound = select "", $ready=$s->{fdmask}, "", $timeout;
3634              
3635             ## Handle any errors while waiting.
3636 0 0 0       if ((!defined $nfound or $nfound <= 0) and $s->{select_supported}) {
      0        
3637 0 0 0       if (defined $nfound and $nfound == 0) { # timed-out
3638 0           $s->{timedout} = 1;
3639 0           return $self->error("$subname timed-out");
3640             }
3641             else { # error waiting for output ready
3642 0 0         if (defined $EINTR) {
3643 0 0         next if $! == $EINTR; # restart select()
3644             }
3645             else {
3646 0 0         next if $! =~ /^interrupted/i; # restart select()
3647             }
3648              
3649 0           $s->{opened} = '';
3650 0           return $self->error("write error: $!");
3651             }
3652             }
3653              
3654             ## Write the data.
3655 0           $nwrote = syswrite $self, $$buf, $s->{blksize}, $offset;
3656              
3657             ## Handle any write errors.
3658 0 0         if (!defined $nwrote) { # write failed
    0          
3659 0 0         if (defined $EINTR) {
3660 0 0         next if $! == $EINTR; # restart syswrite()
3661             }
3662             else {
3663 0 0         next if $! =~ /^interrupted/i; # restart syswrite()
3664             }
3665              
3666 0           $s->{opened} = '';
3667 0           return $self->error("write error: $!");
3668             }
3669             elsif ($nwrote == 0) { # zero chars written
3670             ## Try ten more times to write the data.
3671 0 0         if ($zero_wrote_count++ <= 10) {
3672 0           &_sleep(0.01);
3673 0           next;
3674             }
3675              
3676 0           $s->{opened} = '';
3677 0           return $self->error("write error: zero length write: $!");
3678             }
3679              
3680             ## Display network traffic if requested.
3681 0 0         if ($s->{dumplog}) {
3682 0           &_log_dump('>', $s->{dumplog}, $buf, $offset, $nwrote);
3683             }
3684              
3685             ## Increment.
3686 0           $s->{num_wrote} += $nwrote;
3687 0           $offset += $nwrote;
3688 0           $len -= $nwrote;
3689             }
3690              
3691 0           1;
3692             } # end sub _put
3693              
3694              
3695             sub _qualify_fh {
3696 0     0     my ($obj, $name) = @_;
3697             my (
3698 0           $user_class,
3699             );
3700 0           local $@;
3701 0           local $_;
3702              
3703             ## Get user's package name.
3704 0           ($user_class) = &_user_caller($obj);
3705              
3706             ## Ensure name is qualified with a package name.
3707 0           $name = qualify($name, $user_class);
3708              
3709             ## If it's not already, make it a typeglob ref.
3710 0 0         if (!ref $name) {
3711 1     1   10 no strict;
  1         3  
  1         2018  
3712 0           local $SIG{"__DIE__"} = "DEFAULT";
3713 0           local $^W = '';
3714              
3715 0           $name =~ s/^\*+//;
3716 0           $name = eval "\\*$name";
3717 0 0         return unless ref $name;
3718             }
3719              
3720 0           $name;
3721             } # end sub _qualify_fh
3722              
3723              
3724             sub _reset_options {
3725 0     0     my ($opts) = @_;
3726             my (
3727 0           $opt,
3728             );
3729              
3730 0           foreach $opt (keys %$opts) {
3731 0           $opts->{$opt}{remote_enabled} = '';
3732 0           $opts->{$opt}{remote_state} = "no";
3733 0           $opts->{$opt}{local_enabled} = '';
3734 0           $opts->{$opt}{local_state} = "no";
3735             }
3736              
3737 0           1;
3738             } # end sub _reset_options
3739              
3740              
3741             sub _save_lastline {
3742 0     0     my ($s) = @_;
3743             my (
3744 0           $firstpos,
3745             $lastpos,
3746             $len_w_sep,
3747             $len_wo_sep,
3748             $offset,
3749             );
3750 0           my $rs = "\n";
3751              
3752 0 0         if (($lastpos = rindex $s->{buf}, $rs) > -1) { # eol found
3753 0           while (1) {
3754             ## Find beginning of line.
3755 0           $firstpos = rindex $s->{buf}, $rs, $lastpos - 1;
3756 0 0         if ($firstpos == -1) {
3757 0           $offset = 0;
3758             }
3759             else {
3760 0           $offset = $firstpos + length $rs;
3761             }
3762              
3763             ## Determine length of line with and without separator.
3764 0           $len_wo_sep = $lastpos - $offset;
3765 0           $len_w_sep = $len_wo_sep + length $rs;
3766              
3767             ## Save line if it's not blank.
3768 0 0         if (substr($s->{buf}, $offset, $len_wo_sep)
3769             !~ /^\s*$/)
3770             {
3771             $s->{last_line} = substr($s->{buf},
3772 0           $offset,
3773             $len_w_sep);
3774 0           last;
3775             }
3776              
3777 0 0         last if $firstpos == -1;
3778              
3779 0           $lastpos = $firstpos;
3780             }
3781             }
3782              
3783 0           1;
3784             } # end sub _save_lastline
3785              
3786              
3787             sub _set_default_option {
3788 0     0     my ($s, $option) = @_;
3789              
3790 0           $s->{opts}{$option} = {
3791             remote_enabled => '',
3792             remote_state => "no",
3793             remote_enable_ok => '',
3794             local_enabled => '',
3795             local_state => "no",
3796             local_enable_ok => '',
3797             };
3798             } # end sub _set_default_option
3799              
3800              
3801             sub _sleep {
3802 0     0     my ($secs) = @_;
3803 0           my $bitmask = "";
3804 0           local *SOCK;
3805              
3806 0           socket SOCK, AF_INET, SOCK_STREAM, 0;
3807 0           vec($bitmask, fileno(SOCK), 1) = 1;
3808 0           select $bitmask, "", "", $secs;
3809 0           CORE::close SOCK;
3810              
3811 0           1;
3812             } # end sub _sleep
3813              
3814              
3815             sub _timeout_interval {
3816 0     0     my ($endtime) = @_;
3817             my (
3818 0           $timeout,
3819             );
3820              
3821             ## Return timed-out boolean and timeout interval.
3822 0 0         if (defined $endtime) {
3823             ## Is it a one-time poll.
3824 0 0         return ('', 0) if $endtime == 0;
3825              
3826             ## Calculate the timeout interval.
3827 0           $timeout = $endtime - time;
3828              
3829             ## Did we already timeout.
3830 0 0         return (1, 0) unless $timeout > 0;
3831              
3832 0           return ('', $timeout);
3833             }
3834             else { # there is no timeout
3835 0           return ('', undef);
3836             }
3837             } # end sub _timeout_interval
3838              
3839              
3840             sub _unpack_sockaddr {
3841 0     0     my ($self, $sockaddr) = @_;
3842             my (
3843 0           $packed_addr,
3844             $sockfamily,
3845             );
3846 0           my $addr = "";
3847 0           my $port = "";
3848              
3849 0           $sockfamily = $self->sockfamily;
3850              
3851             ## Parse sockaddr struct.
3852 0 0         if ($sockfamily eq "ipv4") {
    0          
3853 0           ($port, $packed_addr) = sockaddr_in($sockaddr);
3854 0           $addr = Socket::inet_ntoa($packed_addr);
3855             }
3856             elsif ($sockfamily eq "ipv6") {
3857 0           ($port, $packed_addr) = Socket::sockaddr_in6($sockaddr);
3858 0           $addr = Socket::inet_ntop($AF_INET6, $packed_addr);
3859             }
3860              
3861 0           ($port, $addr);
3862             } # end sub _unpack_sockaddr
3863              
3864              
3865             sub _user_caller {
3866 0     0     my ($obj) = @_;
3867             my (
3868 0           $class,
3869             $curr_pkg,
3870             $file,
3871             $i,
3872             $line,
3873             $pkg,
3874             %isa,
3875             @isa,
3876             );
3877 0           local $@;
3878 0           local $_;
3879              
3880             ## Create a boolean hash to test for isa. Make sure current
3881             ## package and the object's class are members.
3882 0           $class = ref $obj;
3883 0           @isa = eval "\@${class}::ISA";
3884 0           push @isa, $class;
3885 0           ($curr_pkg) = caller 1;
3886 0           push @isa, $curr_pkg;
3887 0           %isa = map { $_ => 1 } @isa;
  0            
3888              
3889             ## Search back in call frames for a package that's not in isa.
3890 0           $i = 1;
3891 0           while (($pkg, $file, $line) = caller ++$i) {
3892 0 0         next if $isa{$pkg};
3893              
3894 0           return ($pkg, $file, $line);
3895             }
3896              
3897             ## If not found, choose outer most call frame.
3898 0           ($pkg, $file, $line) = caller --$i;
3899 0           return ($pkg, $file, $line);
3900             } # end sub _user_caller
3901              
3902              
3903             sub _verify_telopt_arg {
3904 0     0     my ($self, $option, $argname) = @_;
3905 0           local $@;
3906              
3907             ## If provided, use argument name in error message.
3908 0 0         if (defined $argname) {
3909 0           $argname = "for arg $argname";
3910             }
3911             else {
3912 0           $argname = "";
3913             }
3914              
3915             ## Ensure telnet option is a non-negative integer.
3916 0           eval {
3917 0           local $SIG{"__DIE__"} = "DEFAULT";
3918 0     0     local $SIG{"__WARN__"} = sub { die "non-numeric\n" };
  0            
3919 0           local $^W = 1;
3920 0           $option = abs(int $option);
3921             };
3922 0 0         return $self->error("bad telnet option $argname: non-numeric")
3923             if $@;
3924              
3925 0 0         return $self->error("bad telnet option $argname: option > 255")
3926             unless $option <= 255;
3927              
3928 0           $option;
3929             } # end sub _verify_telopt_arg
3930              
3931              
3932             ######################## Exported Constants ##########################
3933              
3934              
3935             sub TELNET_IAC () {255}; # interpret as command:
3936             sub TELNET_DONT () {254}; # you are not to use option
3937             sub TELNET_DO () {253}; # please, you use option
3938             sub TELNET_WONT () {252}; # I won't use option
3939             sub TELNET_WILL () {251}; # I will use option
3940             sub TELNET_SB () {250}; # interpret as subnegotiation
3941             sub TELNET_GA () {249}; # you may reverse the line
3942             sub TELNET_EL () {248}; # erase the current line
3943             sub TELNET_EC () {247}; # erase the current character
3944             sub TELNET_AYT () {246}; # are you there
3945             sub TELNET_AO () {245}; # abort output--but let prog finish
3946             sub TELNET_IP () {244}; # interrupt process--permanently
3947             sub TELNET_BREAK () {243}; # break
3948             sub TELNET_DM () {242}; # data mark--for connect. cleaning
3949             sub TELNET_NOP () {241}; # nop
3950             sub TELNET_SE () {240}; # end sub negotiation
3951             sub TELNET_EOR () {239}; # end of record (transparent mode)
3952             sub TELNET_ABORT () {238}; # Abort process
3953             sub TELNET_SUSP () {237}; # Suspend process
3954             sub TELNET_EOF () {236}; # End of file
3955             sub TELNET_SYNCH () {242}; # for telfunc calls
3956              
3957             sub TELOPT_BINARY () {0}; # Binary Transmission
3958             sub TELOPT_ECHO () {1}; # Echo
3959             sub TELOPT_RCP () {2}; # Reconnection
3960             sub TELOPT_SGA () {3}; # Suppress Go Ahead
3961             sub TELOPT_NAMS () {4}; # Approx Message Size Negotiation
3962             sub TELOPT_STATUS () {5}; # Status
3963             sub TELOPT_TM () {6}; # Timing Mark
3964             sub TELOPT_RCTE () {7}; # Remote Controlled Trans and Echo
3965             sub TELOPT_NAOL () {8}; # Output Line Width
3966             sub TELOPT_NAOP () {9}; # Output Page Size
3967             sub TELOPT_NAOCRD () {10}; # Output Carriage-Return Disposition
3968             sub TELOPT_NAOHTS () {11}; # Output Horizontal Tab Stops
3969             sub TELOPT_NAOHTD () {12}; # Output Horizontal Tab Disposition
3970             sub TELOPT_NAOFFD () {13}; # Output Formfeed Disposition
3971             sub TELOPT_NAOVTS () {14}; # Output Vertical Tabstops
3972             sub TELOPT_NAOVTD () {15}; # Output Vertical Tab Disposition
3973             sub TELOPT_NAOLFD () {16}; # Output Linefeed Disposition
3974             sub TELOPT_XASCII () {17}; # Extended ASCII
3975             sub TELOPT_LOGOUT () {18}; # Logout
3976             sub TELOPT_BM () {19}; # Byte Macro
3977             sub TELOPT_DET () {20}; # Data Entry Terminal
3978             sub TELOPT_SUPDUP () {21}; # SUPDUP
3979             sub TELOPT_SUPDUPOUTPUT () {22}; # SUPDUP Output
3980             sub TELOPT_SNDLOC () {23}; # Send Location
3981             sub TELOPT_TTYPE () {24}; # Terminal Type
3982             sub TELOPT_EOR () {25}; # End of Record
3983             sub TELOPT_TUID () {26}; # TACACS User Identification
3984             sub TELOPT_OUTMRK () {27}; # Output Marking
3985             sub TELOPT_TTYLOC () {28}; # Terminal Location Number
3986             sub TELOPT_3270REGIME () {29}; # Telnet 3270 Regime
3987             sub TELOPT_X3PAD () {30}; # X.3 PAD
3988             sub TELOPT_NAWS () {31}; # Negotiate About Window Size
3989             sub TELOPT_TSPEED () {32}; # Terminal Speed
3990             sub TELOPT_LFLOW () {33}; # Remote Flow Control
3991             sub TELOPT_LINEMODE () {34}; # Linemode
3992             sub TELOPT_XDISPLOC () {35}; # X Display Location
3993             sub TELOPT_OLD_ENVIRON () {36}; # Environment Option
3994             sub TELOPT_AUTHENTICATION () {37}; # Authentication Option
3995             sub TELOPT_ENCRYPT () {38}; # Encryption Option
3996             sub TELOPT_NEW_ENVIRON () {39}; # New Environment Option
3997             sub TELOPT_TN3270E () {40}; # TN3270 Enhancements
3998             sub TELOPT_CHARSET () {42}; # CHARSET Option
3999             sub TELOPT_COMPORT () {44}; # Com Port Control Option
4000             sub TELOPT_KERMIT () {47}; # Kermit Option
4001             sub TELOPT_EXOPL () {255}; # Extended-Options-List
4002              
4003              
4004             1;
4005             __END__;