The OpenSSL manpage for SSL_get_error() says this:
In addition to ssl and ret, SSL_get_error() inspects the current
thread's OpenSSL error queue. Thus, SSL_get_error() must be used in
the same thread that performed the TLS/SSL I/O operation, and no other
OpenSSL function calls should appear in between. The current thread's
error queue must be empty before the TLS/SSL I/O operation is
attempted, or SSL_get_error() will not work reliably.
We weren't taking this advice literally enough, which meant that this
would happen:
1. Call SSL_shutdown() on one connection.
2. Call SSL_read() on another connection, returning 0 bytes. (This is
normal. It just means that no more data has arrived yet.)
3. Call SSL_get_error() for that second connection to check whether
the 0-byte return value was a real error. (This should return
SSL_ERROR_WANT_READ to indicate that more data is needed.)
4. Actually get some other error indicating that the SSL_shutdown()
call returned an error.
This commit fixes the problem by flushing the OpenSSL error queue after
calling SSL_shutdown().
Without this commit, starting an ovsdb-server with two active SSL remotes,
running two ovsdb-clients listening for connections from the ovsdb-server
remotes, then killing one of the ovsdb-clients (with e.g. Control+C), will
cause ovsdb-server to drop the other ovsdb-client connnection the next time
that SSL_read() is called on it. With this commit, this scenario works
correctly (e.g. ovsdb-server keeps the remaining connection up).
CC: Jeremy Stribling <strib@nicira.com>
* background. */
SSL_shutdown(sslv->ssl);
+ /* SSL_shutdown() might have signaled an error, in which case we need to
+ * flush it out of the OpenSSL error queue or the next OpenSSL operation
+ * will falsely signal an error. */
+ ERR_clear_error();
+
SSL_free(sslv->ssl);
close(sslv->fd);
free(sslv);