File Coverage

blib/lib/Net/Server/Proto/SSLEAY.pm
Criterion Covered Total %
statement 261 346 75.4
branch 92 168 54.7
condition 30 72 41.6
subroutine 37 45 82.2
pod 7 34 20.5
total 427 665 64.2


line stmt bran cond sub pod time code
1             # -*- perl -*-
2             #
3             # Net::Server::Proto::SSLEAY - Net::Server Protocol module
4             #
5             # Copyright (C) 2010-2022
6             #
7             # Paul Seamons
8             #
9             # This package may be distributed under the terms of either the
10             # GNU General Public License
11             # or the
12             # Perl Artistic License
13             #
14             # All rights reserved.
15             #
16             ################################################################
17              
18             package Net::Server::Proto::SSLEAY;
19              
20 3     3   35147 use strict;
  3         9  
  3         135  
21 3     3   19 use warnings;
  3         7  
  3         228  
22 3     3   21 use Fcntl ();
  3         8  
  3         78  
23 3     3   94 use Errno ();
  3         10  
  3         116  
24 3     3   26 use Carp qw(croak);
  3         8  
  3         229  
25 3     3   21 use base qw(Net::Server::IP); # Can safely handle IPv4 or IPv6 on the fly
  3         6  
  3         757  
26 3     3   24 use Net::Server::Proto qw(SOMAXCONN AF_INET AF_INET6 AF_UNSPEC);
  3         6  
  3         26  
27              
28             BEGIN {
29 3 50   3   15 eval { require Net::SSLeay; 1 }
  3         21  
  3         51  
30             or warn "Module Net::SSLeay is required for SSLeay.";
31 3         12 for my $sub (qw(load_error_strings SSLeay_add_ssl_algorithms ENGINE_load_builtin_engines ENGINE_register_all_complete randomize)) {
32 15         111 my $subref = Net::SSLeay->can($sub);
33 15 50       7937 $subref->() if $subref;
34             }
35 3 50       14807 eval { [Fcntl::F_GETFL(), Fcntl::F_SETFL(), Fcntl::O_NONBLOCK()] } || die "Could not access Fcntl constant while loading ".__PACKAGE__.": $@";
  3         17887  
36             }
37              
38             our $AUTOLOAD;
39              
40             my @ssl_args = qw(
41             SSL_use_cert
42             SSL_verify_mode
43             SSL_key_file
44             SSL_cert_file
45             SSL_ca_path
46             SSL_ca_file
47             SSL_cipher_list
48             SSL_passwd_cb
49             SSL_max_getline_length
50             SSL_error_callback
51             );
52              
53 30     30 0 444 sub NS_proto { 'SSLEAY' }
54 38 100   38 0 360 sub NS_port { my $sock = shift; ${*$sock}{'NS_port'} = shift if @_; return ${*$sock}{'NS_port'} }
  38         92  
  11         50  
  38         58  
  38         223  
55 29 100   29 0 58 sub NS_host { my $sock = shift; ${*$sock}{'NS_host'} = shift if @_; return ${*$sock}{'NS_host'} }
  29         79  
  11         58  
  29         50  
  29         108  
56 29 100   29 0 52 sub NS_ipv { my $sock = shift; ${*$sock}{'NS_ipv'} = shift if @_; return ${*$sock}{'NS_ipv'} }
  29         67  
  11         29  
  29         44  
  29         96  
57 14 100   14 0 31 sub NS_listen { my $sock = shift; ${*$sock}{'NS_listen'} = shift if @_; return ${*$sock}{'NS_listen'} }
  14         34  
  7         39  
  14         27  
  14         39  
58              
59             sub object {
60 7     7 0 83 my ($class, $info, $server) = @_;
61              
62 7   66     53 my $ssl = $server->{'server'}->{'ssl_args'} ||= do {
63 4         24 my %temp = map {$_ => undef} @ssl_args;
  40         242  
64 4         15 $server->configure({map {$_ => \$temp{$_}} @ssl_args});
  40         122  
65 4         47 \%temp;
66             };
67              
68 7         174 my $sock = $class->new;
69 7         1291 $sock->NS_host($info->{'host'});
70 7         46 $sock->NS_port($info->{'port'});
71 7         26 $sock->NS_ipv( $info->{'ipv'} );
72             $sock->NS_listen(defined($info->{'listen'}) ? $info->{'listen'}
73 7 100       81 : defined($server->{'server'}->{'listen'}) ? $server->{'server'}->{'listen'}
    100          
74             : SOMAXCONN);
75 7 50       35 ${*$sock}{'NS_orig_port'} = $info->{'orig_port'} if defined $info->{'orig_port'};
  0         0  
76              
77 7         17 for my $key (@ssl_args) {
78             my $val = defined($info->{$key}) ? $info->{$key}
79             : defined($ssl->{$key}) ? $ssl->{$key}
80 70 100       400 : $server->can($key) ? $server->$key($info->{'host'}, $info->{'port'}, 'SSLEAY')
    100          
    100          
81             : undef;
82 70 100       173 next if ! defined $val;
83 13 50       160 $sock->$key($val) if defined $val;
84             }
85 7         92 return $sock;
86             }
87              
88             sub log_connect {
89 4     4 0 10 my ($sock, $server) = @_;
90 4         12 $server->log(2, "Binding to ".$sock->NS_proto." port ".$sock->NS_port." on host ".$sock->NS_host." with IPv".$sock->NS_ipv);
91             }
92              
93             sub connect { # connect the first time
94 4     4 0 10 my ($sock, $server) = @_;
95 4         12 my $host = $sock->NS_host;
96 4         11 my $port = $sock->NS_port;
97 4         10 my $ipv = $sock->NS_ipv;
98 4         11 my $lstn = $sock->NS_listen;
99              
100 4 50       154 $sock->SUPER::configure({
    50          
    50          
    50          
101             LocalPort => $port,
102             Proto => 'tcp',
103             Listen => $lstn,
104             ReuseAddr => 1,
105             Reuse => 1,
106             Family => ($ipv eq '6' ? AF_INET6 : $ipv eq '4' ? AF_INET : AF_UNSPEC),
107             (($host ne '*') ? (LocalAddr => $host) : ()), # * is all
108             }) || $server->fatal("Can't connect to SSLEAY port $port on $host [$!]");
109              
110 4 50 33     594 if ($port eq '0' and $port = $sock->sockport) {
    50 33        
111 0         0 $server->log(2, " Bound to auto-assigned port $port");
112 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
113 0         0 $sock->NS_port($port);
114             } elsif ($port =~ /\D/ and $port = $sock->sockport) {
115 0         0 $server->log(2, " Bound to service port ".$sock->NS_port()."($port)");
116 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
117 0         0 $sock->NS_port($port);
118             }
119              
120 4         37 $sock->bind_SSL($server);
121             }
122              
123             sub reconnect { # connect on a sig -HUP
124 0     0 0 0 my ($sock, $fd, $server, $port) = @_;
125 0         0 $server->log(3,"Reassociating file descriptor $fd with ".$sock->NS_proto." on [".$sock->NS_host."]:".$sock->NS_port.", using IPv".$sock->NS_ipv);
126 0 0       0 my $resp = $sock->fdopen( $fd, 'w' ) or $server->fatal("Error opening to file descriptor ($fd) [$!]");
127              
128 0         0 my $ipv = $sock->NS_ipv;
129 0 0       0 ${*$sock}{'io_socket_domain'} = $ipv eq '6' ? AF_INET6 : $ipv eq '4' ? AF_INET : AF_UNSPEC;
  0 0       0  
130              
131 0         0 $sock->bind_SSL($server);
132              
133 0 0       0 if ($port ne $sock->NS_port) {
134 0         0 $server->log(2, " Re-bound to previously assigned port $port");
135 0         0 ${*$sock}{'NS_orig_port'} = $sock->NS_port;
  0         0  
136 0         0 $sock->NS_port($port);
137             }
138              
139 0         0 return $resp;
140             }
141              
142             sub bind_SSL {
143 4     4 0 10 my ($sock, $server) = @_;
144 4         4787 my $ctx = Net::SSLeay::CTX_new(); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_new");
  4         33  
145              
146 4         182 Net::SSLeay::CTX_set_options($ctx, Net::SSLeay::OP_ALL()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_options");
  4         632  
147              
148             # 0x01: SSL_MODE_ENABLE_PARTIAL_WRITE
149             # 0x10: SSL_MODE_RELEASE_BUFFERS (ignored before OpenSSL v1.0.0)
150 4         18 Net::SSLeay::CTX_set_mode($ctx, 0x11); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_set_mode");
  4         14  
151              
152             # Load certificate. This will prompt for a password if necessary.
153 4   50     13 my $file_key = $sock->SSL_key_file || die "SSLeay missing SSL_key_file on ".$sock->hup_string.".\n";
154 4   50     10 my $file_cert = $sock->SSL_cert_file || die "SSLeay missing SSL_cert_file on ".$sock->hup_string>".\n";
155 4         141 Net::SSLeay::CTX_use_RSAPrivateKey_file($ctx, $file_key, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_RSAPrivateKey_file");
  4         9285  
156 4         162 Net::SSLeay::CTX_use_certificate_file( $ctx, $file_cert, Net::SSLeay::FILETYPE_PEM()); $sock->SSLeay_check_fatal("SSLeay bind_SSL CTX_use_certificate_file");
  4         3545  
157 4         31 $sock->SSLeay_context($ctx);
158             }
159              
160             sub close {
161 3     3 0 9 my $sock = shift;
162 3 50       12 if ($sock->SSLeay_is_client) {
163 3 50       6 if (my $ssl = ${*$sock}{'SSLeay'}) { # Avoid trying to build a new ctx just to throw it away
  3         14  
164 3         6 my $should_shutdown = 1; # Net::SSLeay <= 1.85 does not have is_init_finished(), so just attempt shutdown in this case:
165 3 50       6 eval { $should_shutdown = 0 if !Net::SSLeay::is_init_finished($ssl) };
  3         38  
166 3 50       189 Net::SSLeay::shutdown($ssl) if $should_shutdown;
167 3         118 Net::SSLeay::free($ssl);
168             }
169             } else {
170 0         0 Net::SSLeay::CTX_free($sock->SSLeay_context);
171             }
172 3         18 $sock->SSLeay_check_fatal("SSLeay close free");
173 3         47 return $sock->SUPER::close(@_);
174             }
175              
176             sub accept {
177 4     4 1 12 my ($sock, $class) = (@_);
178 4         10 my ($client, $peername);
179 4 50       13 if (wantarray) {
180 0         0 ($client, $peername) = $sock->SUPER::accept($class);
181             } else {
182 4         24 $client = $sock->SUPER::accept($class);
183             }
184 4 50       989 if (defined $client) {
185 4         35 $client->NS_proto($sock->NS_proto);
186 4         18 $client->NS_ipv( $sock->NS_ipv);
187 4         14 $client->NS_host( $sock->NS_host);
188 4         17 $client->NS_port( $sock->NS_port);
189 4         17 $client->SSLeay_context($sock->SSLeay_context);
190 4         31 $client->SSLeay_is_client(1);
191             }
192              
193 4 50       54 return wantarray ? ($client, $peername) : $client;
194             }
195              
196             sub post_accept {
197 4     4 0 9 my $client = shift;
198 4         11 $client->SSLeay;
199             }
200              
201             sub SSLeay {
202 23     23 0 41 my $client = shift;
203              
204 23 100       39 if (! exists ${*$client}{'SSLeay'}) {
  23         136  
205 4 50       12 die "SSLeay refusing to accept on non-client socket" if !$client->SSLeay_is_client;
206              
207 4         18 $client->autoflush(1);
208              
209 4   50     189 my $f = fcntl($client, Fcntl::F_GETFL(), 0) || die "SSLeay - fcntl get: $!\n";
210 4 50       24 fcntl($client, Fcntl::F_SETFL(), $f | Fcntl::O_NONBLOCK()) || die "SSLeay - fcntl set: $!\n";
211              
212 4         13 my $ssl = Net::SSLeay::new($client->SSLeay_context); $client->SSLeay_check_fatal("SSLeay new");
  4         19  
213 4         49 Net::SSLeay::set_fd($ssl, $client->fileno); $client->SSLeay_check_fatal("SSLeay set_fd");
  4         134  
214 4         8618 Net::SSLeay::accept($ssl); $client->SSLeay_check_fatal("SSLeay accept");
  4         27  
215 4         9 ${*$client}{'SSLeay'} = $ssl;
  4         40  
216             }
217              
218 23 100       72 return if ! defined wantarray;
219 19         30 return ${*$client}{'SSLeay'};
  19         70  
220             }
221              
222             sub SSLeay_check_fatal {
223 35     35 0 184 my ($client, $msg) = @_;
224 35 50       108 if (my $err = $client->SSLeay_check_error($msg, 1)) {
225 0         0 my ($pkg, $file, $line) = caller;
226 0         0 die "$msg at $file line $line\n ".join(' ', @$err);
227             }
228             }
229              
230             sub SSLeay_check_error {
231 35     35 0 114 my ($client, $msg, $fatal) = @_;
232 35         72 my @err;
233 35         183 while (my $n = Net::SSLeay::ERR_get_error()) {
234 0         0 push @err, "$n. ". Net::SSLeay::ERR_error_string($n) ."\n";
235             }
236 35 50       124 if (@err) {
237 0         0 my $cb = $client->SSL_error_callback;
238 0 0       0 $cb->($client, $msg, \@err, ($fatal ? 'is_fatal' : ())) if $cb;
    0          
239 0         0 return \@err;
240             }
241 35         116 return;
242             }
243              
244             # my $err = $sock->SSLeay_check_perm($msg)
245             # Returns permanent error string for $sock, or undef if no permanent error.
246             # Do not call this method unless you receive an unknown error response
247             # from one of the Net::SSLeay::* routines. If a temporary error is detected,
248             # then it will run select() using the corresponding READ or WRITE bits
249             # before returning undef.
250             sub SSLeay_check_perm {
251 8     8 0 38 my ($client, $msg) = @_;
252 8         14 my $perm;
253 8 50 33     17 if (my $ssl = ${*$client}{'SSLeay'} and my $fn = $client->fileno()) {
  8         93  
254 8         125 my $err = Net::SSLeay::get_error($ssl, -1);
255 8 50       25 return if !$err;
256 8         59 vec(my $vec = '', $fn, 1) = 1;
257 8 50       373 if ($err == Net::SSLeay::ERROR_WANT_READ()) {
258 8         130028 select($vec, undef, undef, undef); # This is not a real error. SSLeay just wants to read, so block until something is ready.
259 8         183 return;
260             }
261 0 0       0 if ($err == Net::SSLeay::ERROR_WANT_WRITE()) {
262 0         0 select(undef, $vec, undef, undef); # This is not a real error. SSLeay just wants to write, so block until socket has room.
263 0         0 return;
264             }
265 0 0 0     0 return if $!{'EAGAIN'} || $!{'EINTR'} || $!{'ENOBUFS'}; # Retryable safe errno
      0        
266 0         0 ($perm = "FD$fn-sslerr[$err] - ".Net::SSLeay::ERR_error_string($err)." [$!] $@")=~s/\s+$//;
267             }
268 0 0       0 return if !$perm;
269              
270 0   0     0 $msg ||= "SSL ERROR";
271 0         0 my $errs = [ ${*$client}{'_error'} = $perm = "$msg: ($perm)" ];
  0         0  
272 0 0       0 if (my $cb = $client->SSL_error_callback) {
273 0         0 $cb->($client, $msg, $errs);
274             }
275 0         0 return $errs->[0];
276             }
277              
278             # my $bytes = $sock->pending();
279             # Returns number of bytes in the buffer.
280             sub pending {
281 6     6 1 16 my $sock = shift;
282 6 50 33     43 my $ssl = $sock && ${*$sock}{'SSLeay'} or return 0;
283 6 100       12 return length ${*$sock}{'SSLeay_buffer'} if defined ${*$sock}{'SSLeay_buffer'};
  1         8  
  6         27  
284 5         33 return Net::SSLeay::pending($ssl);
285             }
286              
287              
288             ###----------------------------------------------------------------###
289              
290             sub read_until {
291 5     5 1 1000438 my ($client, $bytes, $end_qr) = @_;
292              
293 5 50 33     60 croak "read_until: bytes must be positive, or else undef" if defined $bytes and !$bytes || $bytes !~ /^\d+$/;
      66        
294              
295 5         23 my $ssl = $client->SSLeay;
296              
297 5         25 my $content = '';
298 5         11 my $ok = 0;
299 5         13 my $n = undef;
300 5         15 while (!$ok) {
301 5 100       25 $client->sysread($content, 16384, length $content) or last;
302 4 50 33     97 if (defined($end_qr) && $content =~ m/$end_qr/g) {
303 4         11 $n = pos($content);
304 4         9 $ok = 1;
305             }
306 4 0 66     27 if ($bytes and length $content >= $bytes and !$ok || $n > $bytes) { # Keep qr match only if found earlier than $bytes
      0        
      33        
307 0         0 $n = $bytes;
308 0         0 $ok = 2;
309             }
310             }
311 5         13 my $got = length $content;
312 5 100 66     41 if ($ok and $n and $got > $n) { # Whoops, got a little too much, so prepend the extra onto the front of the buffer for later
      100        
313 1 50       3 defined ${*$client}{'SSLeay_buffer'} or ${*$client}{'SSLeay_buffer'} = '';
  1         6  
  1         10  
314 1         5 ${*$client}{'SSLeay_buffer'} = substr($content,$n,$got-$n,'') . ${*$client}{'SSLeay_buffer'};
  1         4  
  1         4  
315             }
316 5 100       37 return wantarray ? ($ok, $content) : $content;
317             }
318              
319             sub read {
320 1     1 0 5 my ($client, $buf, $size, $offset) = @_;
321 1         6 my ($ok, $read) = $client->read_until($size);
322 1 50       6 defined($_[1]) or $_[1] = '';
323 1   50     28 substr($_[1], $offset || 0, length($_[1]), $read);
324 1         8 return length $read;
325             }
326              
327             sub sysread {
328 6     6 0 30 my ($client, $buf, $max, $offset) = @_;
329 6         13 delete ${*$client}{'_error'};
  6         24  
330 6 50 33     52 $max = 1 if !$max || $max<0;
331 6   50     36 $offset ||= 0;
332 6 50       24 ref $buf or $buf = \$_[1];
333 6 50       18 my $ssl = $client->SSLeay or return;
334 6         15 my $max_bytes = 16384; # Read as many bytes as possible
335 6         18 my ($retries, $data, $rv) = 5;
336 6 100       141 if (my $ready = $client->pending) {
337 1   33     2 my $buffer_size = defined ${*$client}{'SSLeay_buffer'} && length ${*$client}{'SSLeay_buffer'};
338 1 50       4 if (!$buffer_size) {
339 0         0 ($data, $rv) = Net::SSLeay::read($ssl, $max_bytes); # Hopefully $rv >= $ready
340 0 0       0 $buffer_size = length (${*$client}{'SSLeay_buffer'} = $data) if defined $data; # Successfully consumed Net::SSLeay buffer
  0         0  
341             }
342 1 50 50     5 !$buffer_size and ${*$client}{'_error'} = "SSLEAY failed reading buffer" and return;
  0         0  
343 1         3 $data = delete ${*$client}{'SSLeay_buffer'};
  1         5  
344             }
345              
346 6   66     52 while ($retries-->0 and !defined $data) {
347 10         43 $! = 0;
348 10         758 ($data, $rv) = Net::SSLeay::read($ssl, $max_bytes);
349 10 100       41 last if defined $data;
350 5 50       19 return if $client->SSLeay_check_perm("SSLEAY sysread");
351             }
352              
353 6 50       20 defined $data or return;
354 6         19 my $length = length $data;
355 6 50       21 $length>$max and ${*$client}{'SSLeay_buffer'} = substr $data,$max,$length-$max,''; # If too long, leave the extraneous bytes in the buffer
  0         0  
356              
357 6 100       19 defined $$buf or $$buf = '';
358 6 50       21 if ($offset > length($$buf)) {
359 0         0 $$buf .= "\0" x ($offset - length($$buf));
360             }
361              
362 6         21 substr $$buf, $offset, length($$buf)-$offset, $data;
363 6         32 return $length;
364             }
365              
366 0     0 1 0 sub error { my $client = shift; return ${*$client}{'_error'} }
  0         0  
  0         0  
367              
368             sub syswrite {
369 8     8 0 32 my ($client, $buf, $length, $offset) = @_;
370 8         17 delete ${*$client}{'_error'};
  8         28  
371              
372 8 100       22 $length = length $buf unless defined $length;
373 8   50     56 $offset ||= 0;
374 8         32 my $ssl = $client->SSLeay;
375 8         37 my $content = substr $buf, $offset, $length;
376 8         15 my $tries = 5;
377 8         26 while ($tries-->0) {
378 11         31 $! = 0;
379 11         12445 my $wrote = Net::SSLeay::write($ssl, $buf);
380 11 100       93 return $wrote if $wrote >= 0;
381 3 50       29 return if $client->SSLeay_check_perm("SSLEAY syswrite");
382             }
383              
384 0         0 return;
385             }
386              
387             sub getline {
388 2     2 1 5 my $client = shift;
389 2         23 my ($ok, $line) = $client->read_until($client->SSL_max_getline_length, $/);
390 2         20 return $line;
391             }
392              
393             sub getlines {
394 0     0 1 0 my $client = shift;
395 0         0 my @lines;
396 0         0 while (1) {
397 0         0 my ($ok, $line) = $client->read_until($client->SSL_max_getline_length, $/);
398 0         0 push @lines, $line;
399 0 0       0 last if $ok != 1;
400             }
401 0         0 return @lines;
402             }
403              
404             sub print {
405 6     6 0 14 my $client = shift;
406 6         9 delete ${*$client}{'_error'};
  6         25  
407 6 50       33 my $OFS = defined $, ? $, : '';
408 6         18 my $buf = join $OFS, @_;
409 6         88 return $client->write($buf);
410             }
411              
412             sub printf {
413 0     0 0 0 my $client = shift;
414 0         0 $client->print(sprintf(shift, @_));
415             }
416              
417             sub say {
418 0     0 0 0 my $client = shift;
419 0         0 $client->print(@_, "\n");
420             }
421              
422             # my $bytes = $sock->write($data, $length, $offset)
423             # Returns the number of bytes from $data sent to the $sock
424             # beginning at $offset and sending up to $length bytes.
425             # If length is omitted, the entire $data string is sent.
426             # If $offset is omitted, then starts from the beginning (0).
427             # If only partial data is sent, then it will keep retrying
428             # until all the data has been encrypted and sent.
429             sub write {
430 7     7 1 19 my $client = shift;
431 7         12 my $buf = shift;
432 7 100 50     29 $buf = substr($buf, $_[1] || 0, $_[0]) if @_;
433 7         14 my $total = 0;
434 7         61 while (my $sent = $client->syswrite($buf, length($buf)-$total, $total)) {
435 7         17 $total += $sent;
436 7 50       53 return $total if $total >= length $buf;
437             }
438 0         0 return;
439             }
440              
441             sub seek {
442 0     0 0 0 my $client = shift;
443 0         0 my ($pos, $whence) = @_;
444 0 0       0 if ($whence) {
445 0         0 $! = "Seek from $whence of non-zero is not supported.";
446 0         0 return 0;
447             }
448 0         0 my $n = $client->read(my $buf, $pos);
449 0 0       0 if ($n != $pos) {
450 0         0 $| = "Couldn't seek to $pos ($n)\n";
451 0         0 return 0;
452             }
453 0         0 return 1;
454             }
455              
456             sub poll_cb { # implemented for psgi compatibility - TODO - should poll appropriately for Multipex
457 0     0 0 0 my ($self, $cb) = @_;
458 0         0 return $cb->($self);
459             }
460              
461             ###----------------------------------------------------------------###
462              
463             sub hup_string {
464 3     3 0 1249 my $sock = shift;
465 3 50       9 return join "|", $sock->NS_host, $sock->NS_port, $sock->NS_proto, "ipv".$sock->NS_ipv, (defined(${*$sock}{'NS_orig_port'}) ? ${*$sock}{'NS_orig_port'} : ());
  3         24  
  0         0  
466             }
467              
468             sub show {
469 0     0 0 0 my $sock = shift;
470 0         0 my $t = "Ref = \"".ref($sock). "\" (".$sock->hup_string.")\n";
471 0         0 foreach my $prop (qw(SSLeay_context SSLeay_is_client)) {
472 0         0 $t .= " $prop = \"" .$sock->$prop()."\"\n";
473             }
474 0         0 return $t;
475             }
476              
477             sub AUTOLOAD {
478 7     7   23 my $sock = shift;
479 7 50       106 my $prop = $AUTOLOAD =~ /::([^:]+)$/ ? $1 : die "Missing property in AUTOLOAD.";
480 7 50       42 die "Unknown method or property [$prop]"
481             if $prop !~ /^(SSLeay_context|SSLeay_is_client|SSL_\w+)$/;
482              
483 3     3   30 no strict 'refs';
  3         6  
  3         718  
484 7         52 *{__PACKAGE__."::${prop}"} = sub {
485 55     55   109 my $sock = shift;
486 55 100       130 if (@_) {
487 25         35 ${*$sock}{$prop} = shift;
  25         145  
488 25 50       52 return delete ${*$sock}{$prop} if ! defined ${*$sock}{$prop};
  0         0  
  25         128  
489             } else {
490 30         51 return ${*$sock}{$prop};
  30         310  
491             }
492 7         76 };
493 7         50 return $sock->$prop(@_);
494             }
495              
496 4     4 0 23 sub tie_stdout { 1 }
497              
498             1;
499              
500             __END__