* to clear the channel eventually because it's blocked trying to
* send data to us. (This can happen when we are sending a large
* amount of COPY data, and the server has generated lots of
- * NOTICE responses.) To avoid a deadlock situation, we must be
- * prepared to accept and buffer incoming data before we try
- * again. Furthermore, it is possible that such incoming data
- * might not arrive until after we've gone to sleep. Therefore,
- * we wait for either read ready or write ready.
+ * NOTICE responses.) A similar scenario is that SSL
+ * renegotiation is in progress, and the SSL library needs to read
+ * a message to complete the handshake, before it can send more
+ * data. To avoid a deadlock situation, we must be prepared to
+ * accept and buffer incoming data before we try again.
+ * Furthermore, it is possible that such incoming data might not
+ * arrive until after we've gone to sleep. Therefore, we wait for
+ * either read ready or write ready.
*
* In non-blocking mode, we don't wait here directly, but return
* 1 to indicate that data is still pending. The caller should
static BIO_METHOD *my_BIO_s_socket(void);
static int my_SSL_set_fd(PGconn *conn, int fd);
+static bool my_block_raw_read = false;
static bool pq_init_ssl_lib = true;
static bool pq_init_crypto_lib = true;
char sebuf[256];
int err;
+ /*
+ * To work-around an issue with OpenSSL and renegotiation, don't let
+ * SSL_write() read any incoming data.
+ *
+ * If SSL_write() is called, and renegotiation has just been inititated,
+ * SSL_write() might try to read from the socket to complete the
+ * handshake. If there was some application data in-flight, it might
+ * receive the application data instead. That confuses it, and it throws
+ * an "sslv3 alert unexpected message" error.
+ *
+ * We avoid that by setting a kill-switch, my_block_raw_read, which tells
+ * my_sock_read() to not return any data to the caller, even if some is
+ * available.
+ *
+ * NB: This relies on the calling code to call pqsecure_read(), completing
+ * the renegotiation handshake, if pqsecure_write() returns 0. Otherwise
+ * we'll never make progress.
+ */
SOCK_ERRNO_SET(0);
+ my_block_raw_read = true;
n = SSL_write(conn->ssl, ptr, len);
+ my_block_raw_read = false;
err = SSL_get_error(conn->ssl, n);
switch (err)
{
int res;
int save_errno;
+ /* If the kill-switch is set, pretend that there is no data. */
+ if (my_block_raw_read)
+ {
+ errno = EWOULDBLOCK;
+ BIO_clear_retry_flags(h);
+ BIO_set_retry_read(h);
+ return -1;
+ }
+
res = pqsecure_raw_read((PGconn *) h->ptr, buf, size);
save_errno = errno;
BIO_clear_retry_flags(h);