File Coverage

blib/lib/Net/SSH/Perl/Buffer.pm
Criterion Covered Total %
statement 73 112 65.1
branch 10 30 33.3
condition 4 10 40.0
subroutine 22 29 75.8
pod 20 23 86.9
total 129 204 63.2


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