Non-blocking socket not handled correctly.
https://github.com/ruby/openssl/blob/94fb921540fe49d3842b0ae562efbfea62a42901/ext/openssl/ossl_ssl.c#L2124
According to the documentation, SSL_shutdown can:
If the underlying BIO is nonblocking, SSL_shutdown() will also return when the underlying BIO could not satisfy the needs of SSL_shutdown() to continue the handshake. In this case a call to SSL_get_error() with the return value of SSL_shutdown() will yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. The calling process then must repeat the call after taking appropriate action to satisfy the needs of SSL_shutdown(). The action depends on the underlying BIO. When using a nonblocking socket, nothing is to be done, but select() can be used to check for the required condition. When using a buffering BIO, like a BIO pair, data must be written into or retrieved out of the BIO before being able to continue.
I don't know if we need to explicitly handle this when in non-blocking mode or not, but I'd assume so until otherwise confirmed/checked.
The underlying socket is always set to non-blocking by us in SSLSocket#initialize.
That SSL_shutdown() is not retried on error is a known issue, but I'm not sure how we're supposed to fix it.
https://github.com/ruby/openssl/blob/94fb921540fe49d3842b0ae562efbfea62a42901/ext/openssl/ossl_ssl.c#L2130-L2136
Would it be acceptable for IOish#close to potentially block? I have an impression it could be surprising.
I think it's okay. IO#close can block in some cases.
I don't know about other IO, but as far as I understand TCP sockets' #close can only block with the setsockopt(SO_LINGER) option.
I think the blocking behavior (ensuring close_notify to be sent) needs the user's explicit request. Changing the default behavior can be a DoS issue as I think people usually call SSLSocket#close without a timeout.
Perhaps we can just expose SSL_shutdown() as a new method?
Maybe in the first instance we can log when it fails, and then collect data about how frequently it happens?
I think we could consider exposing SSL_shutdown as part of https://github.com/ruby/openssl/issues/609