From: Heikki Linnakangas Date: Thu, 12 Feb 2015 16:58:01 +0000 (+0200) Subject: WIP: Do the same block-raw-read dance in backend. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=63eb36c44bd95776ecf2d7dfc68928a245b96d33;p=users%2Fheikki%2Fpostgres.git WIP: Do the same block-raw-read dance in backend. 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. --- diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index a8d14d5d8a..f37ec8ea06 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -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); } } diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index c08c5d73ba..88c34b09ab 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -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 */ } diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index 9d216facae..3b08fad11b 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -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