home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / Handle.pm < prev    next >
Text File  |  2002-06-07  |  11KB  |  375 lines

  1. # $Id: Handle.pm,v 1.8 2002/06/07 12:32:26 sampo Exp $
  2.  
  3. package Net::SSLeay::Handle;
  4.  
  5. require 5.005_03;
  6. use strict;
  7.  
  8. use Socket;
  9. use Net::SSLeay;
  10.  
  11. require Exporter;
  12.  
  13. use vars qw(@ISA @EXPORT_OK $VERSION);
  14. @ISA = qw(Exporter);
  15. @EXPORT_OK = qw(shutdown);
  16. $VERSION = '0.61';
  17.  
  18. #=== Class Variables ==========================================================
  19. #
  20. # %Filenum_Object holds the attributes (see bottom of TIEHANDLE) of tied
  21. # handles keyed by fileno.  This was the only way I could figure out how
  22. # to "attach" attributes to a returned glob reference.
  23. #
  24. #==============================================================================
  25.  
  26. my $Initialized;       #-- only _initialize() once
  27. my %Filenum_Object;    #-- hash of hashes, keyed by fileno()
  28. my $Debug = 0;         #-- pretty hokey
  29. my %Glob_Ref;          #-- used to make unique \*S names for versions < 5.6
  30.  
  31. #== Tie Handle Methods ========================================================
  32. #
  33. # see perldoc perltie for details.
  34. #
  35. #==============================================================================
  36.  
  37. sub TIEHANDLE {
  38.     my ($class, $socket, $port) = @_;
  39.     $Debug > 10 and print "TIEHANDLE(@{[join ', ', @_]})\n";
  40.  
  41.     ref $socket eq "GLOB" or $socket = $class->make_socket($socket, $port);
  42.  
  43.     $class->_initialize();
  44.  
  45.     my $ctx = Net::SSLeay::CTX_new() or die_now("Failed to create SSL_CTX $!");
  46.     my $ssl = Net::SSLeay::new($ctx) or die_now("Failed to create SSL $!");
  47.  
  48.     my $fileno = fileno($socket);
  49.  
  50.   Net::SSLeay::set_fd($ssl, $fileno);   # Must use fileno
  51.  
  52.     my $resp = Net::SSLeay::connect($ssl);
  53.  
  54.     $Debug and print "Cipher '" . Net::SSLeay::get_cipher($ssl) . "'\n";
  55.  
  56.     $Filenum_Object{$fileno} = {
  57.         ssl    => $ssl, 
  58.         ctx    => $ctx,
  59.         socket => $socket,
  60.         fileno => $fileno,
  61.     };
  62.  
  63.     return bless $socket, $class;
  64. }
  65.  
  66. sub PRINT {
  67.     my $socket = shift;
  68.  
  69.     my $ssl  = _get_ssl($socket);
  70.     my $resp = 0;
  71.     for my $msg (@_) {
  72.         defined $msg or last;
  73.         $resp = Net::SSLeay::write($ssl, $msg) or last;
  74.     }
  75.     return $resp;
  76. }
  77.  
  78. sub READLINE {
  79.     my $socket = shift;
  80.     my $ssl  = _get_ssl($socket);
  81.     my $line = Net::SSLeay::ssl_read_until($ssl); 
  82.     return $line ? $line : undef;
  83. }
  84.  
  85. sub READ {
  86.     my ($socket, $buf, $len, $offset) = \ (@_);
  87.     my $ssl = _get_ssl($$socket);
  88.     defined($$offset) or 
  89.       return length($$buf = Net::SSLeay::ssl_read_all($ssl, $$len));
  90.  
  91.     defined(my $read = Net::SSLeay::ssl_read_all($ssl, $$len))
  92.       or return undef;
  93.  
  94.     my $buf_len = length($$buf);
  95.     $$offset > $buf_len and $$buf .= chr(0) x ($$offset - $buf_len);
  96.     substr($$buf, $$offset) = $read;
  97.     return length($read);
  98. }
  99.  
  100. sub WRITE {
  101.     my $socket = shift;
  102.     my ($buf, $len, $offset) = @_;
  103.     $offset = 0 unless defined $offset;
  104.  
  105.     # Return number of characters written.
  106.     my $ssl  = $socket->_get_ssl();
  107.     return $len if Net::SSLeay::write($ssl, substr($buf, $offset, $len));
  108.     return undef;
  109. }
  110.  
  111. sub CLOSE {
  112.     my $socket = shift;
  113.     my $fileno = fileno($socket);
  114.     $Debug > 10 and print "close($fileno)\n";
  115.     my $self = $socket->_get_self();
  116.     delete $Filenum_Object{$fileno};
  117.   Net::SSLeay::free ($self->{ssl});
  118.   Net::SSLeay::CTX_free ($self->{ctx});
  119.     close $socket;
  120. }
  121.  
  122. sub FILENO  { fileno($_[0]) }
  123.  
  124.  
  125. #== Exportable Functions  =====================================================
  126.  
  127. # TIEHANDLE, PRINT, READLINE, CLOSE FILENO, READ, WRITE
  128.  
  129. #--- shutdown(\*SOCKET, $mode) ------------------------------------------------
  130. # Calls to the main shutdown() don't work with tied sockets created with this
  131. # module.  This shutdown should be able to distinquish between tied and untied
  132. # sockets and do the right thing.
  133. #------------------------------------------------------------------------------
  134.  
  135. sub shutdown {
  136.     my ($socket, @params) = @_;
  137.  
  138.     my $obj = _get_self($socket);
  139.     $obj and $socket = $obj->{socket};
  140.     return shutdown($socket, @params);
  141. }
  142.  
  143. #==============================================================================
  144.  
  145. sub debug {
  146.     my ($class, $debug) = @_;
  147.     my $old_debug = $Debug;
  148.     @_ >1 and $Debug = $debug || 0;
  149.     return $old_debug;
  150. }
  151.  
  152. #=== Internal Methods =========================================================
  153.  
  154. sub make_socket {
  155.     my ($class, $host, $port) = @_;
  156.     $Debug > 10 and print "_make_socket(@{[join ', ', @_]})\n";
  157.     $host ||= 'localhost';
  158.     $port ||= 443;
  159.  
  160.     my $phost = $Net::SSLeay::proxyhost;
  161.     my $pport = $Net::SSLeay::proxyhost ? $Net::SSLeay::proxyport : $port;
  162.  
  163.     my $dest_ip     = gethostbyname( $phost || $host);
  164.     my $host_params = sockaddr_in($pport, $dest_ip);
  165.     my $socket = $^V lt 'v5.6.0' ? $class->_glob_ref("$host:$port") : undef;
  166.     
  167.     socket($socket, &PF_INET(), &SOCK_STREAM(), 0) or die "socket: $!";
  168.     connect($socket, $host_params)                 or die "connect: $!";
  169.  
  170.     my $old_select = select($socket); $| = 1; select($old_select);
  171.     $phost and do {
  172.         my $auth = $Net::SSLeay::proxyauth;
  173.         my $CRLF = $Net::SSLeay::CRLF;
  174.         print $socket "CONNECT $host:$port HTTP/1.0$auth$CRLF$CRLF";
  175.         my $line = <$socket>;
  176.     };
  177.     return $socket;
  178. }
  179.  
  180. #--- _glob_ref($strings) ------------------------------------------------------
  181. #
  182. # Create a unique namespace name and return a glob ref to it.  Would be great
  183. # to use the fileno but need this before we get back the fileno.
  184. # NEED TO LOCK THIS ROUTINE IF USING THREADS. (but it is only used for
  185. # versions < 5.6 :)
  186. #------------------------------------------------------------------------------
  187.  
  188. sub _glob_ref {
  189.     my $class = shift;
  190.     my $preamb = join("", @_) || "_glob_ref";
  191.     my $num = ++$Glob_Ref{$preamb};
  192.     my $name = "$preamb:$num";
  193.     no strict 'refs';
  194.     my $glob_ref = \*$name;
  195.     use strict 'refs';
  196.  
  197.     $Debug and do {
  198.         print "GLOB_REF $preamb\n";
  199.         while (my ($k, $v) = each %Glob_Ref) {print "$k = $v\n"} 
  200.         print "\n";
  201.     };
  202.  
  203.     return $glob_ref;
  204. }
  205.  
  206. sub _initialize {
  207.     $Initialized++ and return;
  208.   Net::SSLeay::load_error_strings();
  209.   Net::SSLeay::SSLeay_add_ssl_algorithms();
  210.   Net::SSLeay::randomize();
  211. }
  212.  
  213. sub __dummy {
  214.     my $host = $Net::SSLeay::proxyhost;
  215.     my $port = $Net::SSLeay::proxyport;
  216.     my $auth = $Net::SSLeay::proxyauth;
  217. }
  218.  
  219. #--- _get_self($socket) -------------------------------------------------------
  220. # Returns a hash containing attributes for $socket (= \*SOMETHING) based
  221. # on fileno($socket).  Will return undef if $socket was not created here.
  222. #------------------------------------------------------------------------------
  223.  
  224. sub _get_self {
  225.     return $Filenum_Object{fileno(shift)};
  226. }
  227.  
  228. #--- _get_ssl($socket) --------------------------------------------------------
  229. # Returns a the "ssl" attribute for $socket (= \*SOMETHING) based
  230. # on fileno($socket).  Will cause a warning and return undef if $socket was not
  231. # created here.
  232. #------------------------------------------------------------------------------
  233.  
  234. sub _get_ssl {
  235.     my $socket = shift;
  236.     return $Filenum_Object{fileno($socket)}->{ssl};
  237. }
  238.  
  239. 1;
  240. __END__
  241.  
  242. =head1 NAME
  243.  
  244. Net::SSLeay::Handle - Perl module that lets SSL (HTTPS) sockets be
  245. handled as standard file handles.
  246.  
  247. =head1 SYNOPSIS
  248.  
  249.   use Net::SSLeay::Handle qw/shutdown/;
  250.   my ($host, $port) = ("localhost", 443);
  251.  
  252.   tie(*SSL, "Net::SSLeay::Handle", $host, $port);
  253.  
  254.   print SSL "GET / HTTP/1.0\r\n";
  255.   shutdown(\*SSL, 1);
  256.   print while (<SSL>);
  257.   close SSL;                                                       
  258.   
  259.  
  260. =head1 DESCRIPTION
  261.  
  262. Net::SSLeay::Handle allows you to request and receive HTTPS web pages
  263. using "old-fashion" file handles as in:
  264.  
  265.     print SSL "GET / HTTP/1.0\r\n";
  266.  
  267. and
  268.  
  269.     print while (<SSL>);
  270.  
  271. If you export the shutdown routine, then the only extra code that
  272. you need to add to your program is the tie function as in:
  273.  
  274.     my $socket;
  275.     if ($scheme eq "https") {
  276.         tie(*S2, "Net::SSLeay::Handle", host, $port);
  277.         $socket = \*S2;
  278.     else {
  279.         $socket = Net::SSLeay::Handle->make_socket(host, $port);
  280.     }
  281.     print $socket $request_headers;
  282.     ... 
  283.  
  284. =head2 USING EXISTING SOCKETS
  285.  
  286. One of the motivations for writing this module was to avoid
  287. duplicating socket creation code (which is mostly error handling).
  288. The calls to tie() above where it is passed a $host and $port is
  289. provided for convenience testing.  If you already have a socket
  290. connected to the right host and port, S1, then you can do something
  291. like:
  292.  
  293.     my $socket \*S1;
  294.     if ($scheme eq "https") {
  295.         tie(*S2, "Net::SSLeay::Handle", $socket);
  296.         $socket = \*S2;
  297.     }
  298.     my $last_sel = select($socket); $| = 1; select($last_sel);
  299.     print $socket $request_headers;
  300.     ... 
  301.  
  302. Note: As far as I know you must be careful with the globs in the tie()
  303. function.  The first parameter must be a glob (*SOMETHING) and the
  304. last parameter must be a reference to a glob (\*SOMETHING_ELSE) or a
  305. scaler that was assigned to a reference to a glob (as in the example
  306. above)
  307.  
  308. Also, the two globs must be different.  When I tried to use the same
  309. glob, I got a core dump.
  310.  
  311. =head2 EXPORT
  312.  
  313. None by default.
  314.  
  315. You can export the shutdown() function.
  316.  
  317. It is suggested that you do export shutdown() or use the fully
  318. qualified Net::SSLeay::Handle::shutdown() function to shutdown SSL
  319. sockets.  It should be smart enough to distinguish between SSL and
  320. non-SSL sockets and do the right thing.
  321.  
  322. =head1 EXAMPLES
  323.  
  324.   use Net::SSLeay::Handle qw/shutdown/;
  325.   my ($host, $port) = ("localhost", 443);
  326.  
  327.   tie(*SSL, "Net::SSLeay::Handle", $host, $port);
  328.  
  329.   print SSL "GET / HTTP/1.0\r\n";
  330.   shutdown(\*SSL, 1);
  331.   print while (<SSL>);
  332.   close SSL; 
  333.  
  334. =head1 TODO
  335.  
  336. Better error handling.  Callback routine?
  337.  
  338. =head1 CAVEATS
  339.  
  340. Tying to a file handle is a little tricky (for me at least).
  341.  
  342. The first parameter to tie() must be a glob (*SOMETHING) and the last
  343. parameter must be a reference to a glob (\*SOMETHING_ELSE) or a scaler
  344. that was assigned to a reference to a glob ($s = \*SOMETHING_ELSE).
  345. Also, the two globs must be different.  When I tried to use the same
  346. glob, I got a core dump.
  347.  
  348. I was able to associate attributes to globs created by this module
  349. (like *SSL above) by making a hash of hashes keyed by the file head1.
  350.  
  351. Support for old perls may not be 100%. If in trouble try 5.6.0 or
  352. newer.
  353.  
  354. =head1 CHANGES
  355.  
  356. Please see Net-SSLeay-Handle-0.50/Changes file.
  357.  
  358. =head1 KNOWN BUGS
  359.  
  360. If you let this module construct sockets for you with Perl versions
  361. below v.5.6 then there is a slight memory leak.  Other upgrade your
  362. Perl, or create the sockets yourself.  The leak was created to let
  363. these older versions of Perl access more than one Handle at a time.
  364.  
  365. =head1 AUTHOR
  366.  
  367. Jim Bowlin jbowlin@linklint.org
  368.  
  369. =head1 SEE ALSO
  370.  
  371. Net::SSLeay, perl(1), http://openssl.org/
  372.  
  373. =cut
  374.  
  375.