From e0b42b0120b941b5675e4071445424dc8a1230e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= Date: Wed, 15 Aug 2018 14:46:52 +0200 Subject: [PATCH] Move SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE retry from read()/write() up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original OpenSSL 1.1.1 fix broke IO-Socket-SSL-2.058's t/core.t test because it tests non-blocking socket operations and expects to see SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE errors and to handle them byt itself. This patch purifies Net::SSLeay::{read,write}() to behave exactly as underlying OpenSSL functions. The retry is moved to Net::SSLeay::ssl_read_all. All relevant Net::SSLeay::{read,write}() calls in tests are changed into Net::SSLea::ssl_{read,write}_all(). All applications should implement the retry themsleves or use ssl_*_all() instead. Signed-off-by: Petr Písař --- SSLeay.xs | 28 +++++++--------------------- lib/Net/SSLeay.pm | 22 +++++++++++++++------- t/local/07_sslecho.t | 12 ++++++------ t/local/36_verify.t | 9 +++++---- 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/SSLeay.xs b/SSLeay.xs index 5aed4d7..7cb6eab 100644 --- a/SSLeay.xs +++ b/SSLeay.xs @@ -1997,19 +1997,13 @@ SSL_read(s,max=32768) PREINIT: char *buf; int got; + int succeeded = 1; PPCODE: New(0, buf, max, char); - do { - int err; - - got = SSL_read(s, buf, max); - if (got > 0) - break; - err = SSL_get_error(s, got); - if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) - break; - } while (1); + got = SSL_read(s, buf, max); + if (got <= 0 && SSL_ERROR_ZERO_RETURN != SSL_get_error(s, got)) + succeeded = 0; /* If in list context, return 2-item list: * first return value: data gotten, or undef on error (got<0) @@ -2017,13 +2011,13 @@ SSL_read(s,max=32768) */ if (GIMME_V==G_ARRAY) { EXTEND(SP, 2); - PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0))); + PUSHs(sv_2mortal(succeeded ? newSVpvn(buf, got) : newSV(0))); PUSHs(sv_2mortal(newSViv(got))); /* If in scalar or void context, return data gotten, or undef on error. */ } else { EXTEND(SP, 1); - PUSHs(sv_2mortal(got>=0 ? newSVpvn(buf, got) : newSV(0))); + PUSHs(sv_2mortal(succeeded ? newSVpvn(buf, got) : newSV(0))); } Safefree(buf); @@ -2066,15 +2060,7 @@ SSL_write(s,buf) INPUT: char * buf = SvPV( ST(1), len); CODE: - do { - ret = SSL_write (s, buf, (int)len); - if (ret > 0) - break; - err = SSL_get_error(s, ret); - if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) - break; - } while (1); - RETVAL = ret; + RETVAL = SSL_write (s, buf, (int)len); OUTPUT: RETVAL diff --git a/lib/Net/SSLeay.pm b/lib/Net/SSLeay.pm index 3adf12c..afc6c8f 100644 --- a/lib/Net/SSLeay.pm +++ b/lib/Net/SSLeay.pm @@ -579,14 +579,22 @@ sub debug_read { sub ssl_read_all { my ($ssl,$how_much) = @_; $how_much = 2000000000 unless $how_much; - my ($got, $errs); + my ($got, $rv, $errs); my $reply = ''; while ($how_much > 0) { - $got = Net::SSLeay::read($ssl, + ($got, $rv) = Net::SSLeay::read($ssl, ($how_much > 32768) ? 32768 : $how_much ); - last if $errs = print_errs('SSL_read'); + if (! defined $got) { + my $err = Net::SSLeay::get_error($ssl, $rv); + if ($err != Net::SSLeay::ERROR_WANT_READ() and + $err != Net::SSLeay::ERROR_WANT_WRITE()) { + $errs = print_errs('SSL_read'); + last; + } + next; + } $how_much -= blength($got); debug_read(\$reply, \$got) if $trace>1; last if $got eq ''; # EOF @@ -839,14 +847,14 @@ sub ssl_read_until ($;$$) { $found = index($match, $delim); if ($found > -1) { - #$got = Net::SSLeay::read($ssl, $found+$len_delim); + #$got = Net::SSLeay::ssl_read_all($ssl, $found+$len_delim); #read up to the end of the delimiter - $got = Net::SSLeay::read($ssl, + $got = Net::SSLeay::ssl_read_all($ssl, $found + $len_delim - ((blength($match)) - (blength($got)))); $done = 1; } else { - $got = Net::SSLeay::read($ssl, $peek_length); + $got = Net::SSLeay::ssl_read_all($ssl, $peek_length); $done = 1 if ($peek_length == $max_length - blength($reply)); } @@ -857,7 +865,7 @@ sub ssl_read_until ($;$$) { } } else { while (!defined $max_length || length $reply < $max_length) { - $got = Net::SSLeay::read($ssl,1); # one by one + $got = Net::SSLeay::ssl_read_all($ssl,1); # one by one last if print_errs('SSL_read'); debug_read(\$reply, \$got) if $trace>1; last if $got eq ''; diff --git a/t/local/07_sslecho.t b/t/local/07_sslecho.t index 74e317a..7f19027 100644 --- a/t/local/07_sslecho.t +++ b/t/local/07_sslecho.t @@ -134,10 +134,10 @@ my @results; push @results, [ Net::SSLeay::get_cipher($ssl), 'get_cipher' ]; - push @results, [ Net::SSLeay::write($ssl, $msg), 'write' ]; + push @results, [ Net::SSLeay::ssl_write_all($ssl, $msg), 'write' ]; shutdown($s, 1); - my ($got) = Net::SSLeay::read($ssl); + my $got = Net::SSLeay::ssl_read_all($ssl); push @results, [ $got eq uc($msg), 'read' ]; Net::SSLeay::free($ssl); @@ -177,7 +177,7 @@ my @results; Net::SSLeay::set_fd($ssl, fileno($s)); Net::SSLeay::connect($ssl); - Net::SSLeay::write($ssl, $msg); + Net::SSLeay::ssl_write_all($ssl, $msg); shutdown $s, 2; close $s; @@ -231,15 +231,15 @@ my @results; Net::SSLeay::set_fd($ssl3, $s3); Net::SSLeay::connect($ssl1); - Net::SSLeay::write($ssl1, $msg); + Net::SSLeay::ssl_write_all($ssl1, $msg); shutdown $s1, 2; Net::SSLeay::connect($ssl2); - Net::SSLeay::write($ssl2, $msg); + Net::SSLeay::ssl_write_all($ssl2, $msg); shutdown $s2, 2; Net::SSLeay::connect($ssl3); - Net::SSLeay::write($ssl3, $msg); + Net::SSLeay::ssl_write_all($ssl3, $msg); shutdown $s3, 2; close $s1; diff --git a/t/local/36_verify.t b/t/local/36_verify.t index 2837288..b04be13 100644 --- a/t/local/36_verify.t +++ b/t/local/36_verify.t @@ -252,8 +252,9 @@ sub client { Net::SSLeay::set_fd($ssl, $cl); Net::SSLeay::connect($ssl); my $end = "end"; - Net::SSLeay::write($ssl, $end); - ok($end eq Net::SSLeay::read($ssl), 'Successful termination'); + Net::SSLeay::ssl_write_all($ssl, $end); + Net::SSLeay::shutdown($ssl); + ok($end eq Net::SSLeay::ssl_read_all($ssl), 'Successful termination'); return; } @@ -291,10 +292,10 @@ sub run_server next unless $ret == 1; # Termination request or other message from client - my $msg = Net::SSLeay::read($ssl); + my $msg = Net::SSLeay::ssl_read_all($ssl); if (defined $msg and $msg eq 'end') { - Net::SSLeay::write($ssl, 'end'); + Net::SSLeay::ssl_write_all($ssl, 'end'); exit (0); } } -- 2.14.4