home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Buffer.pm < prev    next >
Encoding:
Perl POD Document  |  2001-07-11  |  9.5 KB  |  374 lines

  1. # $Id: Buffer.pm,v 1.13 2001/07/11 21:57:26 btrott Exp $
  2.  
  3. package Net::SSH::Perl::Buffer;
  4. use strict;
  5.  
  6. {
  7.     my %MP_MAP = (
  8.         SSH1 => [ "use Math::GMP;", \&_get_mp_int_ssh1, \&_put_mp_int_ssh1 ],
  9.         SSH2 => [ "use Net::SSH::Perl::Util qw( :ssh2mp )",
  10.                   \&_get_mp_int_ssh2, \&_put_mp_int_ssh2 ],
  11.     );
  12.  
  13.     sub new {
  14.         my $class = shift;
  15.         my $buf = bless { buf => '', offset => 0 }, $class;
  16.         my %param = @_;
  17.         my $mp = $MP_MAP{ $param{MP} || 'SSH1' };
  18.         die "Unrecognized SSH protocol $param{MP}" unless $mp;
  19.         eval $mp->[0];
  20.         $buf->{_get_mp_int} = $mp->[1];
  21.         $buf->{_put_mp_int} = $mp->[2];
  22.         $buf;
  23.     }
  24. }
  25.  
  26. sub empty {
  27.     my $buf = shift;
  28.     $buf->{buf} = "";
  29.     $buf->{offset} = 0;
  30. }
  31.  
  32. sub append {
  33.     my $buf = shift;
  34.     $buf->{buf} .= $_[0];
  35. }
  36.  
  37. sub consume {
  38.     my $buf = shift;
  39.     my $len = shift;
  40.     substr $buf->{buf}, 0, $len, '';
  41. }
  42.  
  43. sub bytes {
  44.     my $buf = shift;
  45.     my($off, $len, $rep) = @_;
  46.     $off ||= 0;
  47.     $len = length $buf->{buf} unless defined $len;
  48.     return defined $rep ?
  49.         substr($buf->{buf}, $off, $len, $rep) :
  50.         substr($buf->{buf}, $off, $len);
  51. }
  52.  
  53. sub length { length $_[0]->{buf} }
  54. sub offset { $_[0]->{offset} }
  55.  
  56. sub dump {
  57.     my $buf = shift;
  58.     my @r;
  59.     for my $c (split //, $buf->bytes(@_)) {
  60.         push @r, sprintf "%02x", ord $c;
  61.     }
  62.     join ' ', @r
  63. }
  64.  
  65. sub insert_padding {
  66.     my $buf = shift;
  67.     my $pad = 8 - ($buf->length + 4 - 8) % 8;
  68.     my $junk = join '', map chr rand 128, 0..$pad-1;
  69.     $buf->bytes(0, 0, $junk);
  70. }
  71.  
  72. sub get_int8 {
  73.     my $buf = shift;
  74.     my $off = defined $_[0] ? shift : $buf->{offset};
  75.     $buf->{offset} += 1;
  76.     unpack "c", $buf->bytes($off, 1);
  77. }
  78.  
  79. sub put_int8 {
  80.     my $buf = shift;
  81.     $buf->{buf} .= pack "c", $_[0];
  82. }
  83.  
  84. sub get_int16 {
  85.     my $buf = shift;
  86.     my $off = defined $_[0] ? shift : $buf->{offset};
  87.     $buf->{offset} += 2;
  88.     unpack "n", $buf->bytes($off, 2);
  89. }
  90.  
  91. sub put_int16 {
  92.     my $buf = shift;
  93.     $buf->{buf} .= pack "n", $_[0];
  94. }
  95.  
  96. sub get_int32 {
  97.     my $buf = shift;
  98.     my $off = defined $_[0] ? shift : $buf->{offset};
  99.     $buf->{offset} += 4;
  100.     unpack "N", $buf->bytes($off, 4);
  101. }
  102.  
  103. sub put_int32 {
  104.     my $buf = shift;
  105.     $buf->{buf} .= pack "N", $_[0];
  106. }
  107.  
  108. sub get_char {
  109.     my $buf = shift;
  110.     my $off = defined $_[0] ? shift : $buf->{offset};
  111.     $buf->{offset}++;
  112.     $buf->bytes($off, 1);
  113. }
  114.  
  115. sub put_char {
  116.     my $buf = shift;
  117.     $buf->{buf} .= $_[0];
  118. }
  119. *put_chars = \&put_char;
  120.  
  121. sub get_str {
  122.     my $buf = shift;
  123.     my $off = defined $_[0] ? shift : $buf->{offset};
  124.     my $len = $buf->get_int32;
  125.     $buf->{offset} += $len;
  126.     $buf->bytes($off+4, $len);
  127. }
  128.  
  129. sub put_str {
  130.     my $buf = shift;
  131.     my $str = shift;
  132.     $str = "" unless defined $str;
  133.     $buf->put_int32(CORE::length($str));
  134.     $buf->{buf} .= $str;
  135. }
  136.  
  137. sub get_mp_int { $_[0]->{_get_mp_int}->(@_) }
  138. sub put_mp_int { $_[0]->{_put_mp_int}->(@_) }
  139.  
  140. sub _get_mp_int_ssh1 {
  141.     my $buf = shift;
  142.     my $off = defined $_[0] ? shift : $buf->{offset};
  143.     my $bits = unpack "n", $buf->bytes($off, 2);
  144.     my $bytes = int(($bits + 7) / 8);
  145.     my $hex = join '', map { sprintf "%02x", ord } split //, 
  146.         $buf->bytes($off+2, $bytes);
  147.     $buf->{offset} += 2 + $bytes;
  148.     Math::GMP->new("0x$hex");
  149. }
  150.  
  151. sub _put_mp_int_ssh1 {
  152.     my $buf = shift;
  153.     my $int = shift;
  154.     my $bits = Math::GMP::sizeinbase_gmp($int, 2);
  155.     my $hex_size = Math::GMP::sizeinbase_gmp($int, 16);
  156.     my $tmp = Math::GMP::get_str_gmp($int, 16);
  157.     $tmp = "0$tmp" if CORE::length($tmp) % 2;
  158.     $tmp =~ s/(..)/ chr hex $1 /ge;
  159.     $buf->put_int16($bits);
  160.     $buf->put_chars($tmp);
  161. }
  162.  
  163. sub _get_mp_int_ssh2 {
  164.     my $buf = shift;
  165.     my $bits = $buf->get_str;
  166.     bin2mp($bits);
  167. }
  168.  
  169. sub _put_mp_int_ssh2 {
  170.     my $buf = shift;
  171.     my $int = shift;
  172.     my $bytes = (bitsize($int) / 8) + 1;
  173.     my $bin = mp2bin($int);
  174.     my $hasnohigh = (vec($bin, 0, 8) & 0x80) ? 0 : 1;
  175.     $bin = "\0" . $bin unless $hasnohigh;
  176.     $buf->put_str($bin);
  177. }
  178.  
  179. 1;
  180. __END__
  181.  
  182. =head1 NAME
  183.  
  184. Net::SSH::Perl::Buffer - Low-level read/write buffer class
  185.  
  186. =head1 SYNOPSIS
  187.  
  188.     use Net::SSH::Perl::Buffer (@args);
  189.     my $buffer = Net::SSH::Perl::Buffer->new;
  190.  
  191.     ## Add a 32-bit integer.
  192.     $buffer->put_int32(10932930);
  193.  
  194.     ## Get it back.
  195.     my $int = $buffer->get_int32;
  196.  
  197. =head1 DESCRIPTION
  198.  
  199. I<Net::SSH::Perl::Buffer> implements the low-level binary
  200. buffer needed by the I<Net::SSH::Perl> suite. Specifically,
  201. a I<Net::SSH::Perl::Buffer> object is what makes up the
  202. data segment of a packet transferred between server and
  203. client (a I<Net::SSH::Perl::Packet> object).
  204.  
  205. Buffers contain integers, strings, characters, etc. Because
  206. of the use of GMP integers in SSH, buffers can also contain
  207. multiple-precision integers (represented internally by
  208. I<Math::GMP> objects).
  209.  
  210. Note: the method documentation here is in what some might
  211. call a slightly backwards order. The reason for this is that
  212. the get and put methods (listed first) are probably what
  213. most users/developers of I<Net::SSH::Perl> need to care
  214. about; they're high-level methods used to get/put data
  215. from the buffer. The other methods (I<LOW-LEVEL METHODS>)
  216. are much more low-level, and typically you won't need to
  217. use them explicitly.
  218.  
  219. =head1 GET AND PUT METHODS
  220.  
  221. All of the I<get_*> and I<put_*> methods respect the
  222. internal offset state in the buffer object. This means
  223. that, for example, if you call I<get_int16> twice in a
  224. row, you can be ensured that you'll get the next two
  225. 16-bit integers in the buffer. You don't need to worry
  226. about the number of bytes a certain piece of data takes
  227. up, for example.
  228.  
  229. =head2 $buffer->get_int8
  230.  
  231. Returns the next 8-bit integer from the buffer (which
  232. is really just the ASCII code for the next character/byte
  233. in the buffer).
  234.  
  235. =head2 $buffer->put_int8
  236.  
  237. Appends an 8-bit integer to the buffer (which is really
  238. just the character corresponding to that integer, in
  239. ASCII).
  240.  
  241. =head2 $buffer->get_int16
  242.  
  243. Returns the next 16-bit integer from the buffer.
  244.  
  245. =head2 $buffer->put_int16($integer)
  246.  
  247. Appends a 16-bit integer to the buffer.
  248.  
  249. =head2 $buffer->get_int32
  250.  
  251. Returns the next 32-bit integer from the buffer.
  252.  
  253. =head2 $buffer->put_int32($integer)
  254.  
  255. Appends a 32-bit integer to the buffer.
  256.  
  257. =head2 $buffer->get_char
  258.  
  259. More appropriately called I<get_byte>, perhaps, this
  260. returns the next byte from the buffer.
  261.  
  262. =head2 $buffer->put_char($bytes)
  263.  
  264. Appends a byte (or a sequence of bytes) to the buffer.
  265. There is no restriction on the length of the byte
  266. string I<$bytes>; if it makes you uncomfortable to call
  267. I<put_char> to put multiple bytes, you can instead
  268. call this method as I<put_chars>. It's the same thing.
  269.  
  270. =head2 $buffer->get_str
  271.  
  272. Returns the next "string" from the buffer. A string here
  273. is represented as the length of the string (a 32-bit
  274. integer) followed by the string itself.
  275.  
  276. =head2 $buffer->put_str($string)
  277.  
  278. Appends a string (32-bit integer length and the string
  279. itself) to the buffer.
  280.  
  281. =head2 $buffer->get_mp_int
  282.  
  283. Returns a bigint object representing a multiple precision
  284. integer read from the buffer. Depending on the protocol,
  285. the object is either of type I<Math::GMP> (SSH1) or
  286. I<Math::Pari> (SSH2).
  287.  
  288. You determine which protocol will be in use when you
  289. I<use> the module: specify I<SSH1> or I<SSH2> to load
  290. the proper I<get> and I<put> routines for bigints:
  291.  
  292.     use Net::SSH::Perl::Buffer qw( SSH1 );
  293.  
  294. =head2 $buffer->put_mp_int($mp_int)
  295.  
  296. Appends a multiple precision integer to the buffer.
  297. Depending on the protocol in use, I<$mp_int> should
  298. be either a I<Math::GMP> object (SSH1) or a I<Math::Pari>
  299. object (SSH2). The format in which the integer is
  300. stored in the buffer differs between the protocols,
  301. as well.
  302.  
  303. =head1 LOW-LEVEL METHODS
  304.  
  305. =head2 Net::SSH::Perl::Buffer->new
  306.  
  307. Creates a new buffer object and returns it. The buffer is
  308. empty.
  309.  
  310. This method takes no arguments.
  311.  
  312. =head2 $buffer->append($bytes)
  313.  
  314. Appends raw data I<$bytes> to the end of the in-memory
  315. buffer. Generally you don't need to use this method
  316. unless you're initializing an empty buffer, because
  317. when you need to add data to a buffer you should
  318. generally use one of the I<put_*> methods.
  319.  
  320. =head2 $buffer->empty
  321.  
  322. Empties out the buffer object.
  323.  
  324. =head2 $buffer->bytes([ $offset [, $length [, $replacement ]]])
  325.  
  326. Behaves exactly like the I<substr> built-in function,
  327. except on the buffer I<$buffer>. Given no arguments,
  328. I<bytes> returns the entire buffer; given one argument
  329. I<$offset>, returns everything from that position to
  330. the end of the string; given I<$offset> and I<$length>,
  331. returns the segment of the buffer starting at I<$offset>
  332. and consisting of I<$length> bytes; and given all three
  333. arguments, replaces that segment with I<$replacement>.
  334.  
  335. This is a very low-level method, and you generally
  336. won't need to use it.
  337.  
  338. Also be warned that you should not intermix use of this
  339. method with use of the I<get_*> and I<put_*> methods;
  340. the latter classes of methods maintain internal state
  341. of the buffer offset where arguments will be gotten from
  342. and put, respectively. The I<bytes> method gives no
  343. thought to this internal offset state.
  344.  
  345. =head2 $buffer->length
  346.  
  347. Returns the length of the buffer object.
  348.  
  349. =head2 $buffer->offset
  350.  
  351. Returns the internal offset state.
  352.  
  353. If you insist on intermixing calls to I<bytes> with calls
  354. to the I<get_*> and I<put_*> methods, you'll probably
  355. want to use this method to get some status on that
  356. internal offset.
  357.  
  358. =head2 $buffer->dump
  359.  
  360. Returns a hex dump of the buffer.
  361.  
  362. =head2 $buffer->insert_padding
  363.  
  364. A helper method: pads out the buffer so that the length
  365. of the transferred packet will be evenly divisible by
  366. 8, which is a requirement of the SSH protocol.
  367.  
  368. =head1 AUTHOR & COPYRIGHTS
  369.  
  370. Please see the Net::SSH::Perl manpage for author, copyright,
  371. and license information.
  372.  
  373. =cut
  374.