stream-ssl: Flush OpenSSL error queue after calling SSL_shutdown().
authorBen Pfaff <blp@nicira.com>
Thu, 13 May 2010 23:08:14 +0000 (16:08 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 13 May 2010 23:08:14 +0000 (16:08 -0700)
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>
lib/stream-ssl.c

index 462ac4283e0be928023c669c1a6075840a22c58a..c2a77a008a7840e679f9d4e68d4c3c5f80bf5930 100644 (file)
@@ -478,6 +478,11 @@ ssl_close(struct stream *stream)
      * 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);