Commit bcf23ba4 authored by Tom Lane's avatar Tom Lane

Fix previous patch so it also works if not USE_SSL (mea culpa).

On balance, the need to cover this case changes my mind in favor of pushing
all error-message generation duties into the two fe-secure.c routines.
So do it that way.
parent fee476da
...@@ -578,7 +578,6 @@ pqReadData(PGconn *conn) ...@@ -578,7 +578,6 @@ pqReadData(PGconn *conn)
{ {
int someread = 0; int someread = 0;
int nread; int nread;
char sebuf[256];
if (conn->sock < 0) if (conn->sock < 0)
{ {
...@@ -647,11 +646,7 @@ retry3: ...@@ -647,11 +646,7 @@ retry3:
if (SOCK_ERRNO == ECONNRESET) if (SOCK_ERRNO == ECONNRESET)
goto definitelyFailed; goto definitelyFailed;
#endif #endif
/* in SSL mode, pqsecure_read set the error message */ /* pqsecure_read set the error message for us */
if (conn->ssl == NULL)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not receive data from server: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return -1; return -1;
} }
if (nread > 0) if (nread > 0)
...@@ -711,6 +706,11 @@ retry3: ...@@ -711,6 +706,11 @@ retry3:
/* ready for read */ /* ready for read */
break; break;
default: default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
goto definitelyFailed; goto definitelyFailed;
} }
...@@ -739,11 +739,7 @@ retry4: ...@@ -739,11 +739,7 @@ retry4:
if (SOCK_ERRNO == ECONNRESET) if (SOCK_ERRNO == ECONNRESET)
goto definitelyFailed; goto definitelyFailed;
#endif #endif
/* in SSL mode, pqsecure_read set the error message */ /* pqsecure_read set the error message for us */
if (conn->ssl == NULL)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not receive data from server: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return -1; return -1;
} }
if (nread > 0) if (nread > 0)
...@@ -754,16 +750,10 @@ retry4: ...@@ -754,16 +750,10 @@ retry4:
/* /*
* OK, we are getting a zero read even though select() says ready. This * OK, we are getting a zero read even though select() says ready. This
* means the connection has been closed. Cope. * means the connection has been closed. Cope. Note that errorMessage
* has been set already.
*/ */
definitelyFailed: definitelyFailed:
/* in SSL mode, pqsecure_read set the error message */
if (conn->ssl == NULL)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
conn->status = CONNECTION_BAD; /* No more connection to backend */ conn->status = CONNECTION_BAD; /* No more connection to backend */
pqsecure_close(conn); pqsecure_close(conn);
closesocket(conn->sock); closesocket(conn->sock);
...@@ -799,7 +789,6 @@ pqSendSome(PGconn *conn, int len) ...@@ -799,7 +789,6 @@ pqSendSome(PGconn *conn, int len)
while (len > 0) while (len > 0)
{ {
int sent; int sent;
char sebuf[256];
#ifndef WIN32 #ifndef WIN32
sent = pqsecure_write(conn, ptr, len); sent = pqsecure_write(conn, ptr, len);
...@@ -815,11 +804,7 @@ pqSendSome(PGconn *conn, int len) ...@@ -815,11 +804,7 @@ pqSendSome(PGconn *conn, int len)
if (sent < 0) if (sent < 0)
{ {
/* /* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble */
* Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's
* EPIPE or ECONNRESET, assume we've lost the backend connection
* permanently.
*/
switch (SOCK_ERRNO) switch (SOCK_ERRNO)
{ {
#ifdef EAGAIN #ifdef EAGAIN
...@@ -833,17 +818,8 @@ pqSendSome(PGconn *conn, int len) ...@@ -833,17 +818,8 @@ pqSendSome(PGconn *conn, int len)
case EINTR: case EINTR:
continue; continue;
case EPIPE: default:
#ifdef ECONNRESET /* pqsecure_write set the error message for us */
case ECONNRESET:
#endif
/* in SSL mode, pqsecure_write set the error message */
if (conn->ssl == NULL)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
/* /*
* We used to close the socket here, but that's a bad idea * We used to close the socket here, but that's a bad idea
...@@ -855,16 +831,6 @@ pqSendSome(PGconn *conn, int len) ...@@ -855,16 +831,6 @@ pqSendSome(PGconn *conn, int len)
*/ */
conn->outCount = 0; conn->outCount = 0;
return -1; return -1;
default:
/* in SSL mode, pqsecure_write set the error message */
if (conn->ssl == NULL)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send data to server: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
/* We don't assume it's a fatal error... */
conn->outCount = 0;
return -1;
} }
} }
else else
......
...@@ -303,15 +303,16 @@ pqsecure_close(PGconn *conn) ...@@ -303,15 +303,16 @@ pqsecure_close(PGconn *conn)
/* /*
* Read data from a secure connection. * Read data from a secure connection.
* *
* If SSL is in use, this function is responsible for putting a suitable * On failure, this function is responsible for putting a suitable message
* message into conn->errorMessage upon error; but the caller does that * into conn->errorMessage. The caller must still inspect errno, but only
* when not using SSL. In either case, caller uses the returned errno * to determine whether to continue/retry after error.
* to decide whether to continue/retry after error.
*/ */
ssize_t ssize_t
pqsecure_read(PGconn *conn, void *ptr, size_t len) pqsecure_read(PGconn *conn, void *ptr, size_t len)
{ {
ssize_t n; ssize_t n;
int result_errno = 0;
char sebuf[256];
#ifdef USE_SSL #ifdef USE_SSL
if (conn->ssl) if (conn->ssl)
...@@ -332,10 +333,11 @@ rloop: ...@@ -332,10 +333,11 @@ rloop:
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
if (n < 0) if (n < 0)
{ {
/* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL_read failed but did not provide error information\n")); "SSL_read failed but did not provide error information\n");
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
} }
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
...@@ -351,26 +353,32 @@ rloop: ...@@ -351,26 +353,32 @@ rloop:
*/ */
goto rloop; goto rloop;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
if (n < 0)
{ {
char sebuf[256]; result_errno = SOCK_ERRNO;
REMEMBER_EPIPE(spinfo, result_errno == EPIPE);
if (n < 0) if (result_errno == EPIPE ||
{ result_errno == ECONNRESET)
REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE);
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext(
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); "server closed the connection unexpectedly\n"
} "\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
else else
{
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n")); libpq_gettext("SSL SYSCALL error: %s\n"),
/* assume the connection is broken */ SOCK_STRERROR(result_errno,
SOCK_ERRNO_SET(ECONNRESET); sebuf, sizeof(sebuf)));
n = -1; }
} else
break; {
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
} }
break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
{ {
char *errm = SSLerrmessage(); char *errm = SSLerrmessage();
...@@ -379,14 +387,19 @@ rloop: ...@@ -379,14 +387,19 @@ rloop:
libpq_gettext("SSL error: %s\n"), errm); libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm); SSLerrfree(errm);
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
} }
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
/*
* Per OpenSSL documentation, this error code is only returned
* for a clean connection closure, so we should not report it
* as a server crash.
*/
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL connection has been closed unexpectedly\n")); libpq_gettext("SSL connection has been closed unexpectedly\n"));
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
default: default:
...@@ -394,7 +407,7 @@ rloop: ...@@ -394,7 +407,7 @@ rloop:
libpq_gettext("unrecognized SSL error code: %d\n"), libpq_gettext("unrecognized SSL error code: %d\n"),
err); err);
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
} }
...@@ -402,24 +415,66 @@ rloop: ...@@ -402,24 +415,66 @@ rloop:
RESTORE_SIGPIPE(conn, spinfo); RESTORE_SIGPIPE(conn, spinfo);
} }
else else
#endif #endif /* USE_SSL */
{
n = recv(conn->sock, ptr, len, 0); n = recv(conn->sock, ptr, len, 0);
if (n < 0)
{
result_errno = SOCK_ERRNO;
/* Set error message if appropriate */
switch (result_errno)
{
#ifdef EAGAIN
case EAGAIN:
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
case EWOULDBLOCK:
#endif
case EINTR:
/* no error message, caller is expected to retry */
break;
#ifdef ECONNRESET
case ECONNRESET:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
break;
#endif
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not receive data from server: %s\n"),
SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf)));
break;
}
}
}
/* ensure we return the intended errno to caller */
SOCK_ERRNO_SET(result_errno);
return n; return n;
} }
/* /*
* Write data to a secure connection. * Write data to a secure connection.
* *
* If SSL is in use, this function is responsible for putting a suitable * On failure, this function is responsible for putting a suitable message
* message into conn->errorMessage upon error; but the caller does that * into conn->errorMessage. The caller must still inspect errno, but only
* when not using SSL. In either case, caller uses the returned errno * to determine whether to continue/retry after error.
* to decide whether to continue/retry after error.
*/ */
ssize_t ssize_t
pqsecure_write(PGconn *conn, const void *ptr, size_t len) pqsecure_write(PGconn *conn, const void *ptr, size_t len)
{ {
ssize_t n; ssize_t n;
int result_errno = 0;
char sebuf[256];
DECLARE_SIGPIPE_INFO(spinfo); DECLARE_SIGPIPE_INFO(spinfo);
...@@ -438,10 +493,11 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -438,10 +493,11 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
if (n < 0) if (n < 0)
{ {
/* Not supposed to happen, so we don't translate the msg */
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL_write failed but did not provide error information\n")); "SSL_write failed but did not provide error information\n");
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
} }
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
...@@ -457,26 +513,32 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -457,26 +513,32 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
n = 0; n = 0;
break; break;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
if (n < 0)
{ {
char sebuf[256]; result_errno = SOCK_ERRNO;
REMEMBER_EPIPE(spinfo, result_errno == EPIPE);
if (n < 0) if (result_errno == EPIPE ||
{ result_errno == ECONNRESET)
REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE);
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: %s\n"), libpq_gettext(
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); "server closed the connection unexpectedly\n"
} "\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
else else
{
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n")); libpq_gettext("SSL SYSCALL error: %s\n"),
/* assume the connection is broken */ SOCK_STRERROR(result_errno,
SOCK_ERRNO_SET(ECONNRESET); sebuf, sizeof(sebuf)));
n = -1; }
} else
break; {
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL SYSCALL error: EOF detected\n"));
/* assume the connection is broken */
result_errno = ECONNRESET;
n = -1;
} }
break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
{ {
char *errm = SSLerrmessage(); char *errm = SSLerrmessage();
...@@ -485,14 +547,19 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -485,14 +547,19 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
libpq_gettext("SSL error: %s\n"), errm); libpq_gettext("SSL error: %s\n"), errm);
SSLerrfree(errm); SSLerrfree(errm);
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
} }
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
/*
* Per OpenSSL documentation, this error code is only returned
* for a clean connection closure, so we should not report it
* as a server crash.
*/
printfPQExpBuffer(&conn->errorMessage, printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("SSL connection has been closed unexpectedly\n")); libpq_gettext("SSL connection has been closed unexpectedly\n"));
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
default: default:
...@@ -500,13 +567,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len) ...@@ -500,13 +567,13 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
libpq_gettext("unrecognized SSL error code: %d\n"), libpq_gettext("unrecognized SSL error code: %d\n"),
err); err);
/* assume the connection is broken */ /* assume the connection is broken */
SOCK_ERRNO_SET(ECONNRESET); result_errno = ECONNRESET;
n = -1; n = -1;
break; break;
} }
} }
else else
#endif #endif /* USE_SSL */
{ {
int flags = 0; int flags = 0;
...@@ -523,13 +590,15 @@ retry_masked: ...@@ -523,13 +590,15 @@ retry_masked:
if (n < 0) if (n < 0)
{ {
result_errno = SOCK_ERRNO;
/* /*
* If we see an EINVAL, it may be because MSG_NOSIGNAL isn't * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't
* available on this machine. So, clear sigpipe_flag so we don't * available on this machine. So, clear sigpipe_flag so we don't
* try the flag again, and retry the send(). * try the flag again, and retry the send().
*/ */
#ifdef MSG_NOSIGNAL #ifdef MSG_NOSIGNAL
if (flags != 0 && SOCK_ERRNO == EINVAL) if (flags != 0 && result_errno == EINVAL)
{ {
conn->sigpipe_flag = false; conn->sigpipe_flag = false;
flags = 0; flags = 0;
...@@ -537,12 +606,49 @@ retry_masked: ...@@ -537,12 +606,49 @@ retry_masked:
} }
#endif /* MSG_NOSIGNAL */ #endif /* MSG_NOSIGNAL */
REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE); /* Set error message if appropriate */
switch (result_errno)
{
#ifdef EAGAIN
case EAGAIN:
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
case EWOULDBLOCK:
#endif
case EINTR:
/* no error message, caller is expected to retry */
break;
case EPIPE:
/* Set flag for EPIPE */
REMEMBER_EPIPE(spinfo, true);
/* FALL THRU */
#ifdef ECONNRESET
case ECONNRESET:
#endif
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"server closed the connection unexpectedly\n"
"\tThis probably means the server terminated abnormally\n"
"\tbefore or while processing the request.\n"));
break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send data to server: %s\n"),
SOCK_STRERROR(result_errno,
sebuf, sizeof(sebuf)));
break;
}
} }
} }
RESTORE_SIGPIPE(conn, spinfo); RESTORE_SIGPIPE(conn, spinfo);
/* ensure we return the intended errno to caller */
SOCK_ERRNO_SET(result_errno);
return n; return n;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment