File Coverage

blib/lib/Net/SSH/Perl/Buffer.pm
Criterion Covered Total %
statement 99 112 88.3
branch 13 30 43.3
condition 4 10 40.0
subroutine 27 29 93.1
pod 20 23 86.9
total 163 204 79.9


line stmt bran cond sub pod time code
1             package Net::SSH::Perl::Buffer;
2 8     8   107645 use strict;
  8         33  
  8         269  
3 8     8   46 use warnings;
  8         82  
  8         279  
4              
5 8     8   48 use constant MAX_BIGNUM => 2048;
  8         15  
  8         12199  
6              
7             {
8             my %MP_MAP = (
9             SSH1 => [ "use Math::GMP;", \&_get_mp_int_ssh1, \&_put_mp_int_ssh1 ],
10             SSH2 => [ "1;", \&get_bignum2_bytes, \&put_bignum2_bytes],
11             );
12              
13             sub new {
14 22     22 1 169 my $class = shift;
15 22         70 my $buf = bless { buf => '', offset => 0 }, $class;
16 22         56 my %param = @_;
17 22   100     76 my $mp = $MP_MAP{ $param{MP} || 'SSH1' };
18 22 50       40 die "Unrecognized SSH protocol $param{MP}" unless $mp;
19 22     2   1528 eval $mp->[0];
  2         692  
  2         3896  
  2         11  
20 22         362 $buf->{_get_mp_int} = $mp->[1];
21 22         44 $buf->{_put_mp_int} = $mp->[2];
22 22         86 $buf;
23             }
24             }
25              
26             sub empty {
27 5     5 1 787 my $buf = shift;
28 5         13 $buf->{buf} = "";
29 5         15 $buf->{offset} = 0;
30             }
31              
32             sub append {
33 15     15 1 36 my $buf = shift;
34 15         60 $buf->{buf} .= $_[0];
35             }
36              
37             sub consume {
38 2     2 0 7 my $buf = shift;
39 2         12 my $len = shift;
40 2         6 substr $buf->{buf}, 0, $len, '';
41             }
42              
43             sub bytes {
44 125     125 1 226 my $buf = shift;
45 125         220 my($off, $len, $rep) = @_;
46 125   100     352 $off ||= 0;
47 125 100       224 $len = length $buf->{buf} unless defined $len;
48             return defined $rep ?
49             substr($buf->{buf}, $off, $len, $rep) :
50 125 100       705 substr($buf->{buf}, $off, $len);
51             }
52              
53 55     55 1 154 sub length { length $_[0]->{buf} }
54 20     20 1 47 sub offset { $_[0]->{offset} }
55              
56             sub dump {
57 4     4 1 15 my $buf = shift;
58 4         7 my @r;
59 4         11 for my $c (split //, $buf->bytes(@_)) {
60 4         20 push @r, sprintf "%02x", ord $c;
61             }
62 4         21 join ' ', @r
63             }
64              
65             sub insert_padding {
66 6     6 1 11 my $buf = shift;
67 6         17 my $pad = 8 - ($buf->length + 4 - 8) % 8;
68 6         77 my $junk = join '', map chr rand 128, 0..$pad-1;
69 6         21 $buf->bytes(0, 0, $junk);
70             }
71              
72             sub get_int8 {
73 2     2 1 8 my $buf = shift;
74 2 50       9 my $off = defined $_[0] ? shift : $buf->{offset};
75 2         6 $buf->{offset} += 1;
76 2         9 unpack "c", $buf->bytes($off, 1);
77             }
78              
79             sub put_int8 {
80 7     7 1 18 my $buf = shift;
81 7         39 $buf->{buf} .= pack "c", $_[0];
82             }
83              
84             sub get_int16 {
85 1     2 1 3 my $buf = shift;
86 1 50       4 my $off = defined $_[0] ? shift : $buf->{offset};
87 1         2 $buf->{offset} += 2;
88 1         3 unpack "n", $buf->bytes($off, 2);
89             }
90              
91             sub put_int16 {
92 2     3 1 4 my $buf = shift;
93 2         8 $buf->{buf} .= pack "n", $_[0];
94             }
95              
96             sub get_int32 {
97 21     21 1 45 my $buf = shift;
98 21 50       48 my $off = defined $_[0] ? shift : $buf->{offset};
99 21         30 $buf->{offset} += 4;
100 21         47 unpack "N", $buf->bytes($off, 4);
101             }
102              
103             sub put_int32 {
104 17     17 1 30 my $buf = shift;
105 17         74 $buf->{buf} .= pack "N", $_[0];
106             }
107              
108             sub get_char {
109 16     16 1 25 my $buf = shift;
110 16 50       35 my $off = defined $_[0] ? shift : $buf->{offset};
111 16         23 $buf->{offset}++;
112 16         41 $buf->bytes($off, 1);
113             }
114              
115             sub put_char {
116 7     7 1 14 my $buf = shift;
117 7         18 $buf->{buf} .= $_[0];
118             }
119             *put_chars = \&put_char;
120              
121             sub get_str {
122 16     16 1 37 my $buf = shift;
123 16 50       44 my $off = defined $_[0] ? shift : $buf->{offset};
124 16         37 my $len = $buf->get_int32;
125 16         33 $buf->{offset} += $len;
126 16         37 $buf->bytes($off+4, $len);
127             }
128              
129             sub put_str {
130 6     6 1 550 my $buf = shift;
131 6         13 my $str = shift;
132 6 50       25 $str = "" unless defined $str;
133 6         60 $buf->put_int32(CORE::length($str));
134 6         18 $buf->{buf} .= $str;
135             }
136              
137 1     1 1 6 sub get_mp_int { $_[0]->{_get_mp_int}->(@_) }
138 1     1 1 69 sub put_mp_int { $_[0]->{_put_mp_int}->(@_) }
139              
140             sub _get_mp_int_ssh1 {
141 1     1   2 my $buf = shift;
142 1 50       3 my $off = defined $_[0] ? shift : $buf->{offset};
143 1         4 my $bits = unpack "n", $buf->bytes($off, 2);
144 1         7 my $bytes = int(($bits + 7) / 8);
145 1         4 my $hex = join '', map { sprintf "%02x", ord } split //,
  13         30  
146             $buf->bytes($off+2, $bytes);
147 1         5 $buf->{offset} += 2 + $bytes;
148 1         6 Math::GMP->new("0x$hex");
149             }
150              
151             sub _put_mp_int_ssh1 {
152 1     1   6 my $buf = shift;
153 1         1 my $int = shift;
154 1         8 my $bits = Math::GMP::sizeinbase_gmp($int, 2);
155 1         4 my $hex_size = Math::GMP::sizeinbase_gmp($int, 16);
156 1         6 my $tmp = Math::GMP::get_str_gmp($int, 16);
157 1 50       5 $tmp = "0$tmp" if CORE::length($tmp) % 2;
158 1         8 $tmp =~ s/(..)/ chr hex $1 /ge;
  13         36  
159 1         8 $buf->put_int16($bits);
160 1         2 $buf->put_chars($tmp);
161             }
162              
163             sub put_bignum2_bytes {
164 0     0 0 0 my $buf = shift;
165 0         0 my $num = shift;
166              
167             # skip leading zero bytes
168 0         0 substr($num,0,1,'') while ord(substr($num,0,1)) == 0;
169              
170             # prepend a zero byte if mosting significant bit is set
171             # (to avoid interpretation as a negative number)
172 0 0       0 $num = "\0" . $num
173             if (ord(substr($num,0,1))) & 0x80;
174 0         0 $buf->put_str($num);
175             }
176              
177             sub get_bignum2_bytes {
178 0     0 0 0 my $buf = shift;
179              
180 0         0 my $num = $buf->get_str;
181 0         0 my $len = CORE::length($num);
182 0 0       0 return unless $len;
183             # refuse negative (MSB set) bignums
184 0 0       0 return if ord(substr($num,0,1)) & 0x80;
185             # refuse overlong bignums, allow prepended \0 to avoid MSB set
186 0 0 0     0 return if $len > MAX_BIGNUM+1 ||
      0        
187             ($len == MAX_BIGNUM+1 &&
188             ord(substr($num,0,1)) != 0);
189             # trim leading zero bytes
190 0         0 substr($num,0,1,'') while ord(substr($num,0,1)) == 0;
191 0         0 return $num;
192             }
193              
194             1;
195             __END__