Changeset 708

Show
Ignore:
Timestamp:
10/10/07 03:22:44 (11 months ago)
Author:
marksmith
Message:

* make SSL non-blocking

New Perlbal::SocketSSL class that manages the SSL_WANT_READ/WRITE states
and doing the proper thing when the handshake is complete. Some rather
nasty work had to be done to make it all play well together.

Still not recommended to put Perlbal SSL into production anywhere. But it
would be great to get some eyes on this and some more testing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/CHANGES

    r707 r708  
     1    -- make SSL non-blocking 
     2 
    13    -- make persist_client_timeout service tunable apply to the max_idle_time 
    24       value used to kill sockets that are idle 
  • trunk/lib/Perlbal/TCPListener.pm

    r687 r708  
    1212 
    1313use base "Perlbal::Socket"; 
    14 use fields qw(service hostport); 
     14use fields qw(service hostport sslopts); 
    1515use Socket qw(IPPROTO_TCP SOL_SOCKET SO_SNDBUF); 
     16use Perlbal::SocketSSL; 
    1617 
    1718# TCPListener 
     
    2021    $opts ||= {}; 
    2122 
    22     my $sockclass = $opts->{ssl} ? "IO::Socket::SSL" : "IO::Socket::INET"; 
    23     my $sock = eval { 
    24         $sockclass->new( 
    25                         LocalAddr => $hostport, 
    26                         Proto => IPPROTO_TCP, 
    27                         Listen => 1024, 
    28                         ReuseAddr => 1, 
    29                         ($opts->{ssl} ? %{$opts->{ssl}} : ()), 
    30                         ); 
    31     }; 
     23    my $sock = IO::Socket::INET->new( 
     24                                     LocalAddr => $hostport, 
     25                                     Proto => IPPROTO_TCP, 
     26                                     Listen => 1024, 
     27                                     ReuseAddr => 1, 
     28                                     ); 
    3229 
    3330    return Perlbal::error("Error creating listening socket: " . ($@ || $!)) 
     
    4946    $self->{service} = $service; 
    5047    $self->{hostport} = $hostport; 
     48    $self->{sslopts} = $opts->{ssl}; 
    5149    bless $self, ref $class || $class; 
    5250    $self->watch_read(1); 
     
    6058    # accept as many connections as we can 
    6159    while (my ($psock, $peeraddr) = $self->{sock}->accept) { 
    62         my $service_role = $self->{service}->role; 
    63  
    64         if (Perlbal::DEBUG >= 1) { 
    65             my ($pport, $pipr) = Socket::sockaddr_in($peeraddr); 
    66             my $pip = Socket::inet_ntoa($pipr); 
    67             print "Got new conn: $psock ($pip:$pport) for $service_role\n"; 
    68         } 
    69  
    7060        IO::Handle::blocking($psock, 0); 
    7161 
     
    7464        } 
    7565 
    76         if ($service_role eq "reverse_proxy") { 
    77             Perlbal::ClientProxy->new($self->{service}, $psock); 
    78         } elsif ($service_role eq "management") { 
    79             Perlbal::ClientManage->new($self->{service}, $psock); 
    80         } elsif ($service_role eq "web_server") { 
    81             Perlbal::ClientHTTP->new($self->{service}, $psock); 
    82         } elsif ($service_role eq "selector") { 
    83             # will be cast to a more specific class later... 
    84             Perlbal::ClientHTTPBase->new($self->{service}, $psock, $self->{service}); 
    85         } elsif (my $creator = Perlbal::Service::get_role_creator($service_role)) { 
    86             # was defined by a plugin, so we want to return one of these 
    87             $creator->($self->{service}, $psock); 
     66        if (Perlbal::DEBUG >= 1) { 
     67            my ($pport, $pipr) = Socket::sockaddr_in($peeraddr); 
     68            my $pip = Socket::inet_ntoa($pipr); 
     69            print "Got new conn: $psock ($pip:$pport) for " . $self->{service}->role . "\n"; 
    8870        } 
    8971 
     72        # SSL promotion if necessary 
     73        if ($self->{sslopts}) { 
     74            # try to upgrade to SSL, this does no IO it just reblesses 
     75            # and prepares the SSL engine for handling us later 
     76            IO::Socket::SSL->start_SSL( 
     77                                       $psock, 
     78                                       SSL_server => 1, 
     79                                       SSL_startHandshake => 0, 
     80                                       %{ $self->{sslopts} }, 
     81                                       ); 
     82            print "  .. socket upgraded to SSL!\n" if Perlbal::DEBUG >= 1; 
     83 
     84            # safety checking to ensure we got upgraded 
     85            return $psock->close 
     86                unless ref $psock eq 'IO::Socket::SSL'; 
     87 
     88            # class into new package and run with it 
     89            my $sslsock = new Perlbal::SocketSSL($psock, $self); 
     90            $sslsock->try_accept; 
     91 
     92            # all done from our point of view 
     93            next; 
     94        } 
     95 
     96        # puts this socket into the right class 
     97        $self->class_new_socket($psock); 
     98    } 
     99} 
     100 
     101sub class_new_socket { 
     102    my Perlbal::TCPListener $self = shift; 
     103    my $psock = shift; 
     104 
     105    my $service_role = $self->{service}->role; 
     106    if ($service_role eq "reverse_proxy") { 
     107        Perlbal::ClientProxy->new($self->{service}, $psock); 
     108    } elsif ($service_role eq "management") { 
     109        Perlbal::ClientManage->new($self->{service}, $psock); 
     110    } elsif ($service_role eq "web_server") { 
     111        Perlbal::ClientHTTP->new($self->{service}, $psock); 
     112    } elsif ($service_role eq "selector") { 
     113        # will be cast to a more specific class later... 
     114        Perlbal::ClientHTTPBase->new($self->{service}, $psock, $self->{service}); 
     115    } elsif (my $creator = Perlbal::Service::get_role_creator($service_role)) { 
     116        # was defined by a plugin, so we want to return one of these 
     117        $creator->($self->{service}, $psock); 
    90118    } 
    91119} 
     
    113141} 
    114142 
    115  
    1161431; 
    117144