home *** CD-ROM | disk | FTP | other *** search
/ isnet Internet / Isnet Internet CD.iso / prog / hiz / 09 / 09.exe / adynware.exe / perl / lib / site / LWP / SecureSocket.pm < prev    next >
Encoding:
Perl POD Document  |  1999-12-28  |  9.3 KB  |  422 lines

  1.  
  2.  
  3. require Socket;
  4. require Net::SSLeay;
  5.  
  6.  
  7. package LWP::SecureSocket;
  8.  
  9. =head1 NAME
  10.  
  11. LWP::SecureSocket - SSL TCP/IP socket interface
  12.  
  13. =head1 SYNOPSIS
  14.  
  15.  $socket = new LWP::SecureSocket;
  16.  $socket->connect('localhost', 7); # echo
  17.  $quote = 'I dunno, I dream in Perl sometimes...';
  18.  $socket->write("$quote\n");
  19.  $socket->read_until("\n", \$buffer);
  20.  $socket->read(\$buffer);
  21.  $socket = undef;  # close
  22.  
  23. =head1 DESCRIPTION
  24.  
  25. This class implements TCP/IP sockets.  It groups socket generation,
  26. TCP address manipulation and buffered reading. Errors are handled by
  27. dying (throws exceptions).
  28.  
  29. This class should really not be required, something like this should
  30. be part of the standard Perl5 library.
  31.  
  32. Running this module standalone executes a self test which requires
  33. localhost to serve chargen and echo protocols.
  34.  
  35. =head1 METHODS
  36.  
  37. =cut
  38.  
  39.  
  40. $VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);
  41. sub Version { $VERSION; }
  42.  
  43. use Socket qw(pack_sockaddr_in unpack_sockaddr_in
  44.           PF_INET SOCK_STREAM INADDR_ANY
  45.           inet_ntoa inet_aton);
  46. Socket->require_version(1.5);
  47.  
  48. use Carp ();
  49. use Symbol qw(gensym);
  50.  
  51. use LWP::Debug ();
  52. use LWP::IO ();
  53. use Net::SSLeay;
  54.  
  55.  
  56. my $tcp_proto = (getprotobyname('tcp'))[2];
  57.  
  58.  
  59. =head2 $sock = new LWP::SecureSocket()
  60.  
  61. Constructs a new socket object.
  62.  
  63. =cut
  64.  
  65. sub new
  66. {
  67.     my($class, $socket, $host, $port) = @_;
  68.  
  69.     unless ($socket) {
  70.     $socket = gensym();
  71.     LWP::Debug::debug("SecureSocket $socket");
  72.  
  73.     socket($socket, PF_INET, SOCK_STREAM, $tcp_proto) or
  74.       Carp::croak("socket: $!");
  75.     }
  76.  
  77.     my $self = bless {
  78.     'socket' => $socket,
  79.     'host'   => $host,
  80.     'port'   => $port,
  81.     'buffer' => '',
  82.     'size'   => 4096,
  83.     }, $class;
  84.  
  85.     $self;
  86. }
  87.  
  88. sub DESTROY
  89. {
  90.     my $socket = shift->{'socket'};
  91.     close($socket);
  92. }
  93.  
  94. sub host { shift->{'host'}; }
  95. sub port { shift->{'port'}; }
  96.  
  97.  
  98. =head2 $sock->connect($host, $port)
  99.  
  100. Connect the socket to given host and port.
  101.  
  102. =cut
  103.  
  104. sub connect
  105. {
  106.     my($self, $host, $port) = @_;
  107.     Carp::croak("no host") unless defined $host && length $host;
  108.     Carp::croak("no port") unless defined $port && $port > 0;
  109.  
  110.     LWP::Debug::trace("($host, $port)");
  111.  
  112.     $self->{'host'} = $host;
  113.     $self->{'port'} = $port;
  114.  
  115.     my @addr = $self->_getaddress($host, $port);
  116.     Carp::croak("Can't resolv address for $host")
  117.       unless @addr;
  118.     $socket=$self->{'socket'};
  119.     LWP::Debug::debug("Connecting to host '$host' on port '$port'...");
  120.     for (@addr) {
  121.     if (connect($self->{'socket'}, $_)) 
  122.     {
  123.         my $ctx= Net::SSLeay::CTX_new() or 
  124.           Carp::croak "Failed to create SSL_CTX $!";
  125.         $self->{'context'}=$ctx;
  126.         $self->{SSL} = Net::SSLeay::new($ctx) or 
  127.           Carp::croak "Failed to create SSL $!";
  128.         ($err=Net::SSLeay::set_fd($self->{SSL}, ($fn=fileno($socket)))) or 
  129.         (Carp::croak "Can't set_fd somehow $!"); 
  130.         my $res= Net::SSLeay::connect($self->{SSL});
  131.         return;
  132.     }
  133.     }
  134.     Carp::croak("Could not connect to $host:$port");
  135. }
  136.  
  137.  
  138. =head2 $sock->shutdown()
  139.  
  140. Shuts down the connection.
  141.  
  142. =cut
  143.  
  144. sub shutdown
  145. {
  146.     my($self, $how) = @_;
  147.     $how = 2 unless defined $how;
  148.     shutdown($self->{'socket'}, $how);
  149.     delete $self->{'host'};
  150.     delete $self->{'port'};
  151. }
  152.  
  153.  
  154. =head2 $sock->bind($host, $port)
  155.  
  156. Binds a name to the socket.
  157.  
  158. =cut
  159.  
  160. sub bind
  161. {
  162.     my($self, $host, $port) = @_;
  163.     my $name = $self->_getaddress($host, $port);
  164.     bind($self->{'socket'}, $name);
  165. }
  166.  
  167.  
  168. =head2 $sock->listen($queuesize)
  169.  
  170. Set up listen queue for socket.
  171.  
  172. =cut
  173.  
  174. sub listen
  175. {
  176.     listen(shift->{'socket'}, @_);
  177. }
  178.  
  179.  
  180. =head2 $sock->accept($timeout)
  181.  
  182. Accepts a new connection.  Returns a new LWP::SecureSocket object if successful.
  183. Timeout not implemented yet.  would require modifying new, and not
  184.     necessary for app, so I\'m not bothering to modify.  Might work
  185. anyways, though.
  186.  
  187. =cut
  188.  
  189. sub accept
  190. {
  191.     my $self = shift;
  192.     my $timeout = shift;
  193.     my $ns = gensym();
  194.     my $addr = accept($ns, $self->{'socket'});
  195.     if ($addr) {
  196.     my($port, $addr) = unpack_sockaddr_in($addr);
  197.     return new LWP::SecureSocket $ns, inet_ntoa($addr), $port;
  198.     } else {
  199.     Carp::croak("Can't accept: $!");
  200.     }
  201. }
  202.  
  203.  
  204. =head2 $sock->getsockname()
  205.  
  206. Returns a 2 element array ($host, $port)
  207.  
  208. =cut
  209.  
  210. sub getsockname
  211. {
  212.     my($port, $addr) = unpack_sockaddr_in(getsockname(shift->{'socket'}));
  213.     (inet_ntoa($addr), $port);
  214. }
  215.  
  216.  
  217. =head2 $sock->read_until($delim, $data_ref, $size, $timeout)
  218.  
  219. Reads data from the socket, up to a delimiter specified by a regular
  220. expression.  If $delim is undefined all data is read.  If $size is
  221. defined, data will be read internally in chunks of $size bytes.  This
  222. does not mean that we will return the data when size bytes are read.
  223.  
  224. Note that $delim is discarded from the data returned.
  225.  
  226. =cut
  227.  
  228. sub read_until
  229. {
  230.     my ($self, $delim, $data_ref, $size, $timeout) = @_;
  231.  
  232.     {
  233.     my $d = $delim;
  234.     $d =~ s/\r/\\r/g;
  235.     $d =~ s/\n/\\n/g;
  236.     LWP::Debug::trace("('$d',...)");
  237.     }
  238.  
  239.     my $socket = $self->{'socket'};
  240.     my $ssl = $self->{SSL};
  241.     $delim = '' unless defined $delim;
  242.     $size ||= $self->{'size'};
  243.  
  244.     my $buf = \$self->{'buffer'};
  245.  
  246.     if (length $delim) {
  247.     while ($$buf !~ /$delim/) {
  248.         my $data=Net::SSLeay::read($ssl) or die "Unexpected EOF 1";     
  249.         $$buf .=$data;
  250.         
  251.     }
  252.     ($$data_ref, $self->{'buffer'}) = split(/$delim/, $$buf, 2);
  253.     } else {
  254.     $data_ref = $buf;
  255.     $self->{'buffer'} = '';
  256.     }
  257.  
  258.     1;
  259. }
  260.  
  261.  
  262. =head2 $sock->read($bufref, [$size, $timeout])
  263.  
  264. Reads data of the socket.  Not more than $size bytes.  Might return
  265. less if the data is available.  Dies on timeout.
  266.  
  267. =cut
  268.  
  269. sub read
  270. {
  271.     my($self, $data_ref, $size, $timeout) = @_;
  272.     $size ||= $self->{'size'};
  273.  
  274.     LWP::Debug::trace('(...)');
  275.     if (length $self->{'buffer'}) {
  276.     $$data_ref = substr($self->{'buffer'}, 0, $size);
  277.     substr($self->{'buffer'}, 0, $size) = '';
  278.     return length $$data_ref;
  279.     }
  280.     
  281.     my $ssl = $self->{SSL};
  282.     (my $data=Net::SSLeay::read($ssl));
  283.     $$data_ref.=$data;
  284.     return(length $data);
  285. }
  286.  
  287.  
  288. =head2 $sock->pushback($data)
  289.  
  290. Put data back into the socket.  Data will returned next time you
  291. read().  Can be used if you find out that you have read too much.
  292.  
  293. =cut
  294.  
  295. sub pushback
  296. {
  297.     LWP::Debug::trace('(' . length($_[1]) . ' bytes)');
  298.     my $self = shift;
  299.     substr($self->{'buffer'}, 0, 0) = shift;
  300. }
  301.  
  302.  
  303. =head2 $sock->write($data, [$timeout])
  304.  
  305. Write data to socket.  The $data argument might be a scalar or code.
  306.  
  307. If data is a reference to a subroutine, then we will call this routine
  308. to obtain the data to be written.  The routine will be called until it
  309. returns undef or empty data.  Data might be returned from the callback
  310. as a scalar or as a reference to a scalar.
  311.  
  312. Write returns the number of bytes written to the socket.
  313.  
  314. =cut
  315.  
  316. sub write
  317. {
  318.     my $self = shift;
  319.     my $ssl = $self->{SSL};
  320.  
  321.     my $timeout = $_[1];  # we don't want to copy data in $_[0]
  322.     LWP::Debug::trace('()');
  323.     my $bytes_written = 0;
  324.     if (!ref $_[0]) {
  325.     my $got = Net::SSLeay::write($ssl,  $_[0]);
  326.     $bytes_written=length $_[0] if $got;
  327.     } elsif (ref($_[0]) eq 'CODE') {
  328.     my $callback = shift;
  329.     while (1) {
  330.         my $data = &$callback;
  331.         last unless defined $data;
  332.         my $dataRef = ref($data) ? $data : \$data;
  333.         my $len = length $$dataRef;
  334.         last unless $len;
  335.         my $n = $self->write($$dataRef, $timeout);
  336.         $bytes_written += $n;
  337.         last if $n != $len;
  338.     }
  339.     } else {
  340.     Carp::croak('Illegal LWP::SecureSocket->write() argument');
  341.     }
  342.     $bytes_written;
  343. }
  344.  
  345.  
  346.  
  347. =head2 _getaddress($h, $p)
  348.  
  349. Given a host and a port, it will return the address (sockaddr_in)
  350. suitable as the C<name> argument for connect() or bind(). Might return
  351. several addresses in array context if the hostname is bound to several
  352. IP addresses.
  353.  
  354. =cut
  355.  
  356.  
  357. sub _getaddress
  358. {
  359.     my($self, $host, $port) = @_;
  360.  
  361.     my(@addr);
  362.     if (!defined $host) {
  363.     $addr[0] = pack_sockaddr_in($port, INADDR_ANY);
  364.     }
  365.     elsif ($host =~ /^(\d+\.\d+\.\d+\.\d+)$/) {
  366.     $addr[0] = pack_sockaddr_in($port, inet_aton($1));
  367.     } else {
  368.     LWP::Debug::debug("resolving host '$host'...");
  369.     (undef,undef,undef,undef,@addr) = gethostbyname($host);
  370.     for (@addr) {
  371.         LWP::Debug::debug("   ..." . inet_ntoa($_));
  372.         $_ = pack_sockaddr_in($port, $_);
  373.     }
  374.     }
  375.     wantarray ? @addr : $addr[0];
  376. }
  377.  
  378.  
  379.  
  380. package main;
  381.  
  382. eval join('',<DATA>) || die $@ unless caller();
  383.  
  384. =head1 SELF TEST
  385.  
  386. This self test is only executed when this file is run standalone. It
  387. tests its functions against some standard TCP services implemented by
  388. inetd. If you do not have them around the tests will fail.
  389.  
  390. =cut
  391.  
  392. 1;
  393.  
  394. __END__
  395.  
  396. LWP::Debug::level('+');
  397.  
  398. &chargen;
  399. &echo;
  400. print "SecureSocket.pm $LWP::SecureSocket::VERSION ok\n";
  401.  
  402. sub chargen
  403. {
  404.     my $socket = new LWP::SecureSocket;
  405.     $socket->connect('localhost', 19); # chargen
  406.     $socket->read_until('A', \$buffer, 8);
  407.  
  408.     die 'Read Error' unless $buffer eq ' !"#$%&\'()*+,-./0123456789:;<=>?@';
  409.     $socket->read_until('Z', \$buffer, 8);
  410.     die 'Read Error' unless $buffer eq 'BCDEFGHIJKLMNOPQRSTUVWXY';
  411. }
  412.  
  413. sub echo
  414. {
  415.     $socket = new LWP::SecureSocket;
  416.     $socket->connect('localhost', 7); # echo
  417.     $quote = 'I dunno, I dream in Perl sometimes...';
  418.     $socket->write("$quote\n");
  419.     $socket->read_until("\n", \$buffer);
  420.     die 'Read Error' unless $buffer eq $quote;
  421. }
  422.