Package list libpoe-component-sslify-perl / ed9e2b3
fix random SSL failures, spotted by mire Apocalypse 10 years ago
1 changed file(s) with 59 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
2727 'fileno' => $fileno,
2828 'status' => $res,
2929 'on_connect' => $connref,
30 'ssl_started' => 0,
3031 }, $class;
3132
3233 return $self;
3334 }
35
36 # TODO should we make a convenience function to convert retval to string equivalents for easier debugging?
37 # From OpenSSL 1.0.0d
38 #define SSL_ERROR_NONE 0
39 #define SSL_ERROR_SSL 1
40 #define SSL_ERROR_WANT_READ 2
41 #define SSL_ERROR_WANT_WRITE 3
42 #define SSL_ERROR_WANT_X509_LOOKUP 4
43 #define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */
44 #define SSL_ERROR_ZERO_RETURN 6
45 #define SSL_ERROR_WANT_CONNECT 7
46 #define SSL_ERROR_WANT_ACCEPT 8
3447
3548 sub _check_status {
3649 my $self = shift;
4356 $self->{'status'} = Net::SSLeay::accept( $self->{'ssl'} );
4457 }
4558
46 # Only process the stuff if we actually have a callback!
47 return unless defined $self->{'on_connect'};
48
4959 if ( $self->{'status'} <= 0 ) {
5060 # http://www.openssl.org/docs/ssl/SSL_get_error.html
5161 my $errval = Net::SSLeay::get_error( $self->{'ssl'}, $self->{'status'} );
5262
63 # Handle the case of ERROR_WANT_READ and ERROR_WANT_WRITE
5364 # TODO should we skip ERROR_WANT_ACCEPT and ERROR_WANT_CONNECT ?
5465 # also, ERROR_WANT_ACCEPT isn't exported by Net::SSLeay, huh?
55 if ( $errval != ERROR_WANT_READ and $errval != ERROR_WANT_WRITE ) {
66 if ( $errval == ERROR_WANT_READ or $errval == ERROR_WANT_WRITE ) {
67 # continue reading/writing from the socket until we connect or not...
68 return 1;
69 } else {
5670 # call the hook function for error connect
57 $self->{'on_connect'}->( $self->{'orig_socket'}, 0, $errval );
71 if ( defined $self->{'on_connect'} ) {
72 $self->{'on_connect'}->( $self->{'orig_socket'}, 0, $errval );
73 }
74
75 # don't try to read/write from the socket anymore!
76 return 0;
5877 }
5978 } elsif ( $self->{'status'} == 1 ) {
79 # SSL handshake is done!
80 $self->{'ssl_started'} = 1;
81
6082 # call the hook function for successful connect
61 $self->{'on_connect'}->( $self->{'orig_socket'}, 1 );
83 if ( defined $self->{'on_connect'} ) {
84 $self->{'on_connect'}->( $self->{'orig_socket'}, 1 );
85 }
86
87 # we can now read/write from the socket!
88 return 1;
6289 }
6390 }
6491
7097 # Get the pointers to buffer, length, and the offset
7198 my( $buf, $len, $offset ) = \( @_ );
7299
73 # Check connection status
74 $self->_check_status if $self->{'status'} <= 0;
100 # Check the status of the SSL handshake
101 if ( ! $self->{'ssl_started'} ) {
102 return if $self->_check_status == 0;
103 }
75104
76105 # If we have no offset, replace the buffer with some input
77106 if ( ! defined $$offset ) {
79108
80109 # Are we done?
81110 if ( defined $$buf ) {
111 # TODO do we need the same "flush is success" logic in WRITE?
112
82113 return length( $$buf );
83114 } else {
84115 # Nah, clear the buffer too...
90121 # Now, actually read the data
91122 defined( my $read = Net::SSLeay::read( $self->{'ssl'}, $$len ) ) or return;
92123
124 # TODO do we need the same "flush is success" logic in WRITE?
125
93126 # Figure out the buffer and offset
94127 my $buf_len = length( $$buf );
95128
110143 # Get ourself + buffer + length + offset to write
111144 my( $self, $buf, $len, $offset ) = @_;
112145
113 # Check connection status
114 $self->_check_status if $self->{'status'} <= 0;
146 # Check the status of the SSL handshake
147 if ( ! $self->{'ssl_started'} ) {
148 # The normal syswrite() POE uses expects 0 here.
149 return 0 if $self->_check_status == 0;
150 }
115151
116152 # If we have nothing to offset, then start from the beginning
117153 if ( ! defined $offset ) {
128164 # The normal syswrite() POE uses expects 0 here.
129165 return 0;
130166 } else {
167 # We flushed some data, which means we finished the handshake!
168 # This is IMPORTANT, as mire__@irc found out!
169 # Otherwise openssl will zonk out and give us SSL_ERROR_SSL and things randomly break :(
170 if ( ! $self->{'ssl_started'} ) {
171 $self->{'ssl_started'} = 1;
172 $self->{'status'} = 1;
173
174 # call the hook function for successful connect
175 if ( defined $self->{'on_connect'} ) {
176 $self->{'on_connect'}->( $self->{'orig_socket'}, 1 );
177 }
178 }
179
131180 # All done!
132181 return $wrote_len;
133182 }