diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index db41179b78..e5c6ccfd92 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.87 2008/12/03 20:04:26 mha Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.88 2008/12/14 19:39:37 mha Exp $ * * Since the server static private key ($DataDir/server.key) * will normally be stored unencrypted so that the database @@ -394,45 +394,71 @@ wloop: #ifdef USE_SSL /* - * Private substitute BIO: this wraps the SSL library's standard socket BIO - * so that we can enable and disable interrupts just while calling recv(). - * We cannot have interrupts occurring while the bulk of openssl runs, - * because it uses malloc() and possibly other non-reentrant libc facilities. + * Private substitute BIO: this does the sending and receiving using send() and + * recv() instead. This is so that we can enable and disable interrupts + * just while calling recv(). We cannot have interrupts occurring while + * the bulk of openssl runs, because it uses malloc() and possibly other + * non-reentrant libc facilities. We also need to call send() and recv() + * directly so it gets passed through the socket/signals layer on Win32. + * + * They are closely modelled on the original socket implementations in OpenSSL. * - * As of openssl 0.9.7, we can use the reasonably clean method of interposing - * a wrapper around the standard socket BIO's sock_read() method. This relies - * on the fact that sock_read() doesn't call anything non-reentrant, in fact - * not much of anything at all except recv(). If this ever changes we'd - * probably need to duplicate the code of sock_read() in order to push the - * interrupt enable/disable down yet another level. */ static bool my_bio_initialized = false; static BIO_METHOD my_bio_methods; -static int (*std_sock_read) (BIO *h, char *buf, int size); static int my_sock_read(BIO *h, char *buf, int size) { - int res; + int res = 0; prepare_for_client_read(); - res = std_sock_read(h, buf, size); + if (buf != NULL) + { + 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) + { + BIO_set_retry_read(h); + } + } + } client_read_ended(); return res; } +static int +my_sock_write(BIO *h, const char *buf, int size) +{ + int res = 0; + + res = send(h->num, buf, size, 0); + if (res <= 0) + { + if (errno == EINTR) + { + BIO_set_retry_write(h); + } + } + + return res; +} + static BIO_METHOD * my_BIO_s_socket(void) { if (!my_bio_initialized) { memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD)); - std_sock_read = my_bio_methods.bread; my_bio_methods.bread = my_sock_read; + my_bio_methods.bwrite = my_sock_write; my_bio_initialized = true; } return &my_bio_methods;