WIP: Do the same block-raw-read dance in backend. ssl-reneg-94
authorHeikki Linnakangas <[email protected]>
Thu, 12 Feb 2015 16:58:01 +0000 (18:58 +0200)
committerHeikki Linnakangas <[email protected]>
Mon, 23 Feb 2015 11:54:42 +0000 (13:54 +0200)
This is more complicated than in the client, because the callers of
secure_write() will not automatically do a read, if the write fails.
Need to expose pq_recvbuf() and call it from secure_write(), which is
modularity violation.

src/backend/libpq/be-secure.c
src/backend/libpq/pqcomm.c
src/include/libpq/libpq.h

index a8d14d5d8aadc19d8d79f31fcfd85e39713b52be..f37ec8ea062663c5282e43af5d715585e1559d9a 100644 (file)
@@ -108,6 +108,9 @@ int                 ssl_renegotiation_limit;
 /* are we in the middle of a renegotiation? */
 static bool in_ssl_renegotiation = false;
 
+/* kill-switch to have my_sock_read pretend there's no data */
+static bool my_block_raw_read = false;
+
 static SSL_CTX *SSL_context = NULL;
 static bool ssl_loaded_verify_locations = false;
 #endif
@@ -367,7 +370,9 @@ secure_write(Port *port, void *ptr, size_t len)
 
 wloop:
                errno = 0;
+               my_block_raw_read = true;
                n = SSL_write(port->ssl, ptr, len);
+               my_block_raw_read = false;
                err = SSL_get_error(port->ssl, n);
                switch (err)
                {
@@ -382,6 +387,15 @@ wloop:
                                                                        FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE,
                                                                                        INFINITE);
 #endif
+                               if (err == SSL_ERROR_WANT_READ)
+                               {
+                                       if (pq_recvbuf(false) != 0)
+                                       {
+                                               errno = ECONNRESET;
+                                               n = -1;
+                                               break;
+                                       }
+                               }
                                goto wloop;
                        case SSL_ERROR_SYSCALL:
                                /* leave it to caller to ereport the value of errno */
@@ -466,19 +480,28 @@ my_sock_read(BIO *h, char *buf, int size)
 {
        int                     res = 0;
 
-       prepare_for_client_read();
+       if (buf == NULL)
+               return 0;       /* XXX: can this happen? */
 
-       if (buf != NULL)
+       /* If the kill-switch is set, pretend that there is no data. */
+       if (my_block_raw_read)
        {
-               res = recv(h->num, buf, size, 0);
                BIO_clear_retry_flags(h);
-               if (res <= 0)
+               BIO_set_retry_read(h);
+               errno = EWOULDBLOCK;
+               return -1;
+       }
+
+       prepare_for_client_read();
+
+       res = recv(h->num, buf, size, 0);
+       BIO_clear_retry_flags(h);
+       if (res <= 0)
+       {
+               /* If we were interrupted, tell caller to retry */
+               if (errno == EINTR)
                {
-                       /* If we were interrupted, tell caller to retry */
-                       if (errno == EINTR)
-                       {
-                               BIO_set_retry_read(h);
-                       }
+                       BIO_set_retry_read(h);
                }
        }
 
index c08c5d73ba403ac8a7bad33bdbaf1e8343c5c820..88c34b09ab5f9fe572d050d98e739740e74b683d 100644 (file)
@@ -825,11 +825,11 @@ pq_set_nonblocking(bool nonblocking)
 /* --------------------------------
  *             pq_recvbuf - load some bytes into the input buffer
  *
- *             returns 0 if OK, EOF if trouble
+ *             returns 0 if OK, EOF if trouble
  * --------------------------------
  */
-static int
-pq_recvbuf(void)
+int
+pq_recvbuf(bool block)
 {
        if (PqRecvPointer > 0)
        {
@@ -845,8 +845,8 @@ pq_recvbuf(void)
                        PqRecvLength = PqRecvPointer = 0;
        }
 
-       /* Ensure that we're in blocking mode */
-       pq_set_nonblocking(false);
+       /* Ensure that we're in blocking mode (or not) */
+       pq_set_nonblocking(!block);
 
        /* Can fill buffer from PqRecvLength and upwards */
        for (;;)
@@ -861,6 +861,12 @@ pq_recvbuf(void)
                        if (errno == EINTR)
                                continue;               /* Ok if interrupted */
 
+                       if (!block)
+                       {
+                               if (errno == EWOULDBLOCK || errno == EAGAIN)
+                                       return 0;
+                       }
+
                        /*
                         * Careful: an ereport() that tries to write to the client would
                         * cause recursion to here, leading to stack overflow and core
@@ -896,7 +902,7 @@ pq_getbyte(void)
 
        while (PqRecvPointer >= PqRecvLength)
        {
-               if (pq_recvbuf())               /* If nothing in buffer, then recv some */
+               if (pq_recvbuf(true))           /* If nothing in buffer, then recv some */
                        return EOF;                     /* Failed to recv data */
        }
        return (unsigned char) PqRecvBuffer[PqRecvPointer++];
@@ -913,7 +919,7 @@ pq_peekbyte(void)
 {
        while (PqRecvPointer >= PqRecvLength)
        {
-               if (pq_recvbuf())               /* If nothing in buffer, then recv some */
+               if (pq_recvbuf(true))   /* If nothing in buffer, then recv some */
                        return EOF;                     /* Failed to recv data */
        }
        return (unsigned char) PqRecvBuffer[PqRecvPointer];
@@ -992,7 +998,7 @@ pq_getbytes(char *s, size_t len)
        {
                while (PqRecvPointer >= PqRecvLength)
                {
-                       if (pq_recvbuf())       /* If nothing in buffer, then recv some */
+                       if (pq_recvbuf(true))   /* If nothing in buffer, then recv some */
                                return EOF;             /* Failed to recv data */
                }
                amount = PqRecvLength - PqRecvPointer;
@@ -1026,7 +1032,7 @@ pq_discardbytes(size_t len)
        {
                while (PqRecvPointer >= PqRecvLength)
                {
-                       if (pq_recvbuf())       /* If nothing in buffer, then recv some */
+                       if (pq_recvbuf(true))   /* If nothing in buffer, then recv some */
                                return EOF;             /* Failed to recv data */
                }
                amount = PqRecvLength - PqRecvPointer;
@@ -1067,7 +1073,7 @@ pq_getstring(StringInfo s)
        {
                while (PqRecvPointer >= PqRecvLength)
                {
-                       if (pq_recvbuf())       /* If nothing in buffer, then recv some */
+                       if (pq_recvbuf(true))   /* If nothing in buffer, then recv some */
                                return EOF;             /* Failed to recv data */
                }
 
index 9d216facaee7394b981641bd287a35667531bb15..3b08fad11ba01990dd4857bfa43ed08171637fa8 100644 (file)
@@ -1,3 +1,4 @@
+
 /*-------------------------------------------------------------------------
  *
  * libpq.h
@@ -69,6 +70,7 @@ extern int    pq_putmessage(char msgtype, const char *s, size_t len);
 extern void pq_putmessage_noblock(char msgtype, const char *s, size_t len);
 extern void pq_startcopyout(void);
 extern void pq_endcopyout(bool errorAbort);
+extern int     pq_recvbuf(bool block);
 
 /*
  * prototypes for functions in be-secure.c