File Coverage

blib/lib/Perlbal/SocketSSL.pm
Criterion Covered Total %
statement 39 84 46.4
branch 0 16 0.0
condition n/a
subroutine 13 20 65.0
pod 4 6 66.6
total 56 126 44.4


line stmt bran cond sub pod time code
1             # Base class for SSL sockets.
2             #
3             # This is a simple class that extends Danga::Socket and contains an IO::Socket::SSL
4             # for the purpose of allowing non-blocking SSL in Perlbal.
5             #
6             # Copyright 2007, Mark Smith .
7             #
8             # This file is licensed under the same terms as Perl itself.
9              
10             package Perlbal::SocketSSL;
11              
12 22     22   414 use strict;
  22         47  
  22         838  
13 22     22   124 use warnings;
  22         46  
  22         785  
14 22     22   201 no warnings qw(deprecated);
  22         47  
  22         837  
15              
16 22     22   126 use Danga::Socket 1.44;
  22         856  
  22         668  
17 22     22   40448 use IO::Socket::SSL 0.98;
  22         3572852  
  22         229  
18 22     22   5405 use Errno qw( EAGAIN );
  22         61  
  22         1262  
19 22     22   133 use Perlbal::Socket;
  22         52  
  22         559  
20              
21 22     22   126 use base 'Danga::Socket';
  22         45  
  22         4248  
22 22     22   147 use fields qw( listener create_time alive_time);
  22         133  
  22         217  
23              
24             Perlbal::Socket->set_socket_idle_handler('Perlbal::SocketSSL' => sub {
25             my Perlbal::SocketSSL $v = shift;
26              
27             my $max_age = eval { $v->max_idle_time } || 0;
28             return unless $max_age;
29              
30             # Attributes are in another class, don't violate object boundaries.
31             $v->{sock}->close(SSL_no_shutdown => 1, SSL_ctx_free => 1)
32             if $v->{alive_time} < $Perlbal::tick_time - $max_age;
33             });
34              
35             # called: CLASS->new( $sock, $tcplistener )
36             sub new {
37 0     0 1   my Perlbal::SocketSSL $self = shift;
38 0 0         $self = fields::new( $self ) unless ref $self;
39              
40 0           Perlbal::objctor($self);
41              
42 0           my ($sock, $listener) = @_;
43              
44 0           ${*$sock}->{_danga_socket} = $self;
  0            
45 0           $self->{listener} = $listener;
46 0           $self->{alive_time} = $self->{create_time} = time;
47              
48 0           $self->SUPER::new($sock);
49              
50             # TODO: would be good to have an overall timeout so that we can
51             # kill sockets that are open and just sitting there. "ssl_handshake_timeout"
52             # or something like that...
53              
54 0           return $self;
55             }
56              
57             # this is nonblocking, it attempts to setup SSL and if it can't then
58             # it returns whether it needs to read or write. we then setup to wait
59             # for the event it indicates and then wait. when that event fires, we
60             # call down again, and repeat the process until we have setup the
61             # SSL connection.
62             sub try_accept {
63 0     0 0   my Perlbal::SocketSSL $self = shift;
64              
65 0           my $sock = $self->{sock}->accept_SSL;
66              
67 0 0         if (defined $sock) {
68             # looks like we got it! let's steal it from ourselves
69             # so Danga::Socket gives up on it and we can send
70             # it out to someone else. (we discard the return value
71             # as we already have it in $sock)
72             #
73             # of course, life isn't as simple as that. we have to do
74             # some trickery with the ordering here to ensure that we
75             # don't setup the new class until after the Perlbal::SocketSSL
76             # goes away according to Danga::Socket.
77             #
78             # if we don't do it this way, we get nasty errors because
79             # we (this object) still exists in the DescriptorMap of
80             # Danga::Socket when the new Perlbal::ClientXX tries to
81             # insert itself there.
82              
83             # removes us from the active polling, closes up shop, but
84             # save our fd first!
85 0           my $fd = $self->{fd};
86 0           $self->steal_socket;
87              
88             # finish blowing us away
89 0           my $ref = Danga::Socket->DescriptorMap();
90 0           delete $ref->{$fd};
91              
92             # now stick the new one in
93 0           my Perlbal::ClientHTTPBase $cb = $self->{listener}->class_new_socket($sock);
94 0           $cb->{is_ssl} = 1;
95 0           return;
96             }
97              
98             # nope, let's see if we can continue the process
99 0 0         if ($! == EAGAIN) {
100 0 0         if ($SSL_ERROR == SSL_WANT_READ) {
    0          
101 0           $self->watch_read(1);
102             } elsif ($SSL_ERROR == SSL_WANT_WRITE) {
103 0           $self->watch_write(1);
104             } else {
105 0           $self->close('invalid_ssl_state');
106             }
107             } else {
108 0           $self->close('invalid_ssl_error');
109             }
110             }
111              
112             sub event_read {
113 0     0 1   $_[0]->watch_read(0);
114 0           $_[0]->{alive_time} = $Perlbal::tick_time;
115 0           $_[0]->try_accept;
116             }
117              
118             sub event_write {
119 0     0 1   $_[0]->watch_write(0);
120 0           $_[0]->{alive_time} = $Perlbal::tick_time;
121 0           $_[0]->try_accept;
122             }
123              
124             sub event_err {
125 0     0 1   $_[0]->close('invalid_ssl_state');
126             }
127              
128             # You can tuna-fish, but you can't tune a Perlbal::SocketSSL
129             sub max_idle_time {
130 0     0 0   return 60;
131             }
132              
133             package Perlbal::SocketSSL2;
134              
135 22     22   14906 use strict;
  22         55  
  22         814  
136 22     22   131 use warnings;
  22         50  
  22         863  
137              
138 22     22   126 use IO::Socket::SSL;
  22         49  
  22         198  
139              
140 22     22   3645 use base 'IO::Socket::SSL';
  22         51  
  22         6321  
141              
142             sub close {
143 0 0   0     my $self = shift
144             or return IO::Socket::SSL::_invalid_object();
145              
146             # If we our Danga::Socket sibling has a sock then we're being called for the first time.
147             # NOTE: this isn't strictly safe, ->close can get called on a sock multiple times. We
148             # really could use a safe way to know if this handle is being called from the post-
149             # event-loop cleanup code in Danga::Socket.
150 0 0         if (my $ds = ${*$self}->{_danga_socket}) {
  0            
151 0           ${*$self}->{__close_args} = [ @_ ];
  0            
152 0           delete ${*$self}->{_danga_socket};
  0            
153 0 0         $ds->close('intercepted_ssl_close')
154             if $ds->sock;
155             } else {
156 0           return $self->SUPER::close(@{${*$self}->{__close_args}});
  0            
  0            
157             }
158             }
159              
160             1;