|
|
b47050 |
From c0af30b47db023b87c4eb6b55190a8c081697241 Mon Sep 17 00:00:00 2001
|
|
|
b47050 |
From: Tom Lane <tgl@sss.pgh.pa.us>
|
|
|
b47050 |
Date: Fri, 7 Sep 2012 16:02:23 -0400
|
|
|
b47050 |
Subject: [PATCH 1/4] Centralize libpq's low-level code for dropping a
|
|
|
b47050 |
connection.
|
|
|
b47050 |
|
|
|
b47050 |
Create an internal function pqDropConnection that does the physical socket
|
|
|
b47050 |
close and cleans up closely-associated state. This removes a bunch of ad
|
|
|
b47050 |
hoc, not always consistent closure code. The ulterior motive is to have a
|
|
|
b47050 |
single place to wait for a spawned child backend to exit, but this seems
|
|
|
b47050 |
like good cleanup even if that never happens.
|
|
|
b47050 |
|
|
|
b47050 |
I went back and forth on whether to include "conn->status = CONNECTION_BAD"
|
|
|
b47050 |
in pqDropConnection's actions, but for the moment decided not to. Only a
|
|
|
b47050 |
minority of the call sites actually want that, and in any case it's
|
|
|
b47050 |
arguable that conn->status is slightly higher-level state, and thus not
|
|
|
b47050 |
part of this function's purview.
|
|
|
b47050 |
|
|
|
b47050 |
Upstream commit: 210eb9b743c0645df05e5c8be4490ba4f09fc871
|
|
|
b47050 |
---
|
|
|
b47050 |
src/interfaces/libpq/fe-connect.c | 95 +++++++++++------------------
|
|
|
b47050 |
src/interfaces/libpq/fe-misc.c | 5 +-
|
|
|
b47050 |
src/interfaces/libpq/fe-protocol3.c | 4 +-
|
|
|
b47050 |
src/interfaces/libpq/libpq-int.h | 1 +
|
|
|
b47050 |
4 files changed, 38 insertions(+), 67 deletions(-)
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
index 28b96a6..6985118 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
@@ -363,6 +363,28 @@ static void default_threadlock(int acquire);
|
|
|
b47050 |
pgthreadlock_t pg_g_threadlock = default_threadlock;
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
+/*
|
|
|
b47050 |
+ * pqDropConnection
|
|
|
b47050 |
+ *
|
|
|
b47050 |
+ * Close any physical connection to the server, and reset associated
|
|
|
b47050 |
+ * state inside the connection object. We don't release state that
|
|
|
b47050 |
+ * would be needed to reconnect, though.
|
|
|
b47050 |
+ */
|
|
|
b47050 |
+void
|
|
|
b47050 |
+pqDropConnection(PGconn *conn)
|
|
|
b47050 |
+{
|
|
|
b47050 |
+ /* Drop any SSL state */
|
|
|
b47050 |
+ pqsecure_close(conn);
|
|
|
b47050 |
+ /* Close the socket itself */
|
|
|
b47050 |
+ if (conn->sock >= 0)
|
|
|
b47050 |
+ closesocket(conn->sock);
|
|
|
b47050 |
+ conn->sock = -1;
|
|
|
b47050 |
+ /* Discard any unread/unsent data */
|
|
|
b47050 |
+ conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
+ conn->outCount = 0;
|
|
|
b47050 |
+}
|
|
|
b47050 |
+
|
|
|
b47050 |
+
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Connecting to a Database
|
|
|
b47050 |
*
|
|
|
b47050 |
@@ -1477,12 +1499,7 @@ connectDBStart(PGconn *conn)
|
|
|
b47050 |
return 1;
|
|
|
b47050 |
|
|
|
b47050 |
connect_errReturn:
|
|
|
b47050 |
- if (conn->sock >= 0)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
- }
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_BAD;
|
|
|
b47050 |
return 0;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1720,8 +1737,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
if (!connectNoDelay(conn))
|
|
|
b47050 |
{
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1731,8 +1747,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1743,8 +1758,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1792,8 +1806,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
|
|
|
b47050 |
if (err)
|
|
|
b47050 |
{
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1880,11 +1893,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* failure and keep going if there are more addresses.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, SOCK_ERRNO);
|
|
|
b47050 |
- if (conn->sock >= 0)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
- }
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Try the next address, if any.
|
|
|
b47050 |
@@ -1929,6 +1938,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* error message.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, optval);
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* If more addresses remain, keep trying, just as in the
|
|
|
b47050 |
@@ -1936,11 +1946,6 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
*/
|
|
|
b47050 |
if (conn->addr_cur->ai_next != NULL)
|
|
|
b47050 |
{
|
|
|
b47050 |
- if (conn->sock >= 0)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
- }
|
|
|
b47050 |
conn->addr_cur = conn->addr_cur->ai_next;
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
@@ -2215,12 +2220,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2330,13 +2331,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
conn->pversion = PG_PROTOCOL(2, 0);
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -2401,12 +2397,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->wait_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -2421,13 +2413,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
#endif
|
|
|
b47050 |
@@ -2587,13 +2574,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
PQclear(res);
|
|
|
b47050 |
conn->send_appname = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2987,12 +2969,7 @@ closePGconn(PGconn *conn)
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Close the connection, reset all transient state, flush I/O buffers.
|
|
|
b47050 |
*/
|
|
|
b47050 |
- if (conn->sock >= 0)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- }
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
|
|
|
b47050 |
* absent */
|
|
|
b47050 |
conn->asyncStatus = PGASYNC_IDLE;
|
|
|
b47050 |
@@ -3022,8 +2999,6 @@ closePGconn(PGconn *conn)
|
|
|
b47050 |
if (conn->lobjfuncs)
|
|
|
b47050 |
free(conn->lobjfuncs);
|
|
|
b47050 |
conn->lobjfuncs = NULL;
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
- conn->outCount = 0;
|
|
|
b47050 |
#ifdef ENABLE_GSS
|
|
|
b47050 |
{
|
|
|
b47050 |
OM_uint32 min_s;
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
index 8b0d8ef..c1c5c75 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
@@ -815,11 +815,8 @@ definitelyEOF:
|
|
|
b47050 |
|
|
|
b47050 |
/* Come here if lower-level code already set a suitable errorMessage */
|
|
|
b47050 |
definitelyFailed:
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* No more connection to backend */
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
-
|
|
|
b47050 |
return -1;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
index f997257..b130b4c 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
@@ -457,9 +457,7 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
|
|
|
b47050 |
pqSaveErrorResult(conn);
|
|
|
b47050 |
conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */
|
|
|
b47050 |
|
|
|
b47050 |
- pqsecure_close(conn);
|
|
|
b47050 |
- closesocket(conn->sock);
|
|
|
b47050 |
- conn->sock = -1;
|
|
|
b47050 |
+ pqDropConnection(conn);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* No more connection to backend */
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
index bc2be3c..70b956b 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
+++ b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
@@ -489,6 +489,7 @@ extern char *const pgresStatus[];
|
|
|
b47050 |
|
|
|
b47050 |
/* === in fe-connect.c === */
|
|
|
b47050 |
|
|
|
b47050 |
+extern void pqDropConnection(PGconn *conn);
|
|
|
b47050 |
extern int pqPacketSend(PGconn *conn, char pack_type,
|
|
|
b47050 |
const void *buf, size_t buf_len);
|
|
|
b47050 |
extern bool pqGetHomeDirectory(char *buf, int bufsize);
|
|
|
b47050 |
--
|
|
|
b47050 |
2.17.1
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
From 299e76cdeebf150f51cf29fa4269ae02cf6e7f24 Mon Sep 17 00:00:00 2001
|
|
|
b47050 |
From: Tom Lane <tgl@sss.pgh.pa.us>
|
|
|
b47050 |
Date: Thu, 12 Nov 2015 13:03:53 -0500
|
|
|
b47050 |
Subject: [PATCH 2/4] Fix unwanted flushing of libpq's input buffer when socket
|
|
|
b47050 |
EOF is seen.
|
|
|
b47050 |
|
|
|
b47050 |
In commit 210eb9b743c0645d I centralized libpq's logic for closing down
|
|
|
b47050 |
the backend communication socket, and made the new pqDropConnection
|
|
|
b47050 |
routine always reset the I/O buffers to empty. Many of the call sites
|
|
|
b47050 |
previously had not had such code, and while that amounted to an oversight
|
|
|
b47050 |
in some cases, there was one place where it was intentional and necessary
|
|
|
b47050 |
*not* to flush the input buffer: pqReadData should never cause that to
|
|
|
b47050 |
happen, since we probably still want to process whatever data we read.
|
|
|
b47050 |
|
|
|
b47050 |
This is the true cause of the problem Robert was attempting to fix in
|
|
|
b47050 |
c3e7c24a1d60dc6a, namely that libpq no longer reported the backend's final
|
|
|
b47050 |
ERROR message before reporting "server closed the connection unexpectedly".
|
|
|
b47050 |
But that only accidentally fixed it, by invoking parseInput before the
|
|
|
b47050 |
input buffer got flushed; and very likely there are timing scenarios
|
|
|
b47050 |
where we'd still lose the message before processing it.
|
|
|
b47050 |
|
|
|
b47050 |
To fix, pass a flag to pqDropConnection to tell it whether to flush the
|
|
|
b47050 |
input buffer or not. On review I think flushing is actually correct for
|
|
|
b47050 |
every other call site.
|
|
|
b47050 |
|
|
|
b47050 |
Back-patch to 9.3 where the problem was introduced. In HEAD, also improve
|
|
|
b47050 |
the comments added by c3e7c24a1d60dc6a.
|
|
|
b47050 |
|
|
|
b47050 |
Upstream commit: db6e8e1624a8f0357373450136c850f2b6e7fc8a
|
|
|
b47050 |
---
|
|
|
b47050 |
src/interfaces/libpq/fe-connect.c | 38 +++++++++++++++++------------
|
|
|
b47050 |
src/interfaces/libpq/fe-misc.c | 3 ++-
|
|
|
b47050 |
src/interfaces/libpq/fe-protocol3.c | 4 +--
|
|
|
b47050 |
src/interfaces/libpq/libpq-int.h | 2 +-
|
|
|
b47050 |
4 files changed, 27 insertions(+), 20 deletions(-)
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
index 6985118..c22901d 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
@@ -369,9 +369,13 @@ pgthreadlock_t pg_g_threadlock = default_threadlock;
|
|
|
b47050 |
* Close any physical connection to the server, and reset associated
|
|
|
b47050 |
* state inside the connection object. We don't release state that
|
|
|
b47050 |
* would be needed to reconnect, though.
|
|
|
b47050 |
+ *
|
|
|
b47050 |
+ * We can always flush the output buffer, since there's no longer any hope
|
|
|
b47050 |
+ * of sending that data. However, unprocessed input data might still be
|
|
|
b47050 |
+ * valuable, so the caller must tell us whether to flush that or not.
|
|
|
b47050 |
*/
|
|
|
b47050 |
void
|
|
|
b47050 |
-pqDropConnection(PGconn *conn)
|
|
|
b47050 |
+pqDropConnection(PGconn *conn, bool flushInput)
|
|
|
b47050 |
{
|
|
|
b47050 |
/* Drop any SSL state */
|
|
|
b47050 |
pqsecure_close(conn);
|
|
|
b47050 |
@@ -379,8 +383,10 @@ pqDropConnection(PGconn *conn)
|
|
|
b47050 |
if (conn->sock >= 0)
|
|
|
b47050 |
closesocket(conn->sock);
|
|
|
b47050 |
conn->sock = -1;
|
|
|
b47050 |
- /* Discard any unread/unsent data */
|
|
|
b47050 |
- conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
+ /* Optionally discard any unread data */
|
|
|
b47050 |
+ if (flushInput)
|
|
|
b47050 |
+ conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
+ /* Always discard any unsent data */
|
|
|
b47050 |
conn->outCount = 0;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -1499,7 +1505,7 @@ connectDBStart(PGconn *conn)
|
|
|
b47050 |
return 1;
|
|
|
b47050 |
|
|
|
b47050 |
connect_errReturn:
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_BAD;
|
|
|
b47050 |
return 0;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1737,7 +1743,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
if (!connectNoDelay(conn))
|
|
|
b47050 |
{
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1747,7 +1753,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1758,7 +1764,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1806,7 +1812,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
|
|
|
b47050 |
if (err)
|
|
|
b47050 |
{
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
continue;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1893,7 +1899,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* failure and keep going if there are more addresses.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, SOCK_ERRNO);
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Try the next address, if any.
|
|
|
b47050 |
@@ -1938,7 +1944,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* error message.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, optval);
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* If more addresses remain, keep trying, just as in the
|
|
|
b47050 |
@@ -2220,7 +2226,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2331,7 +2337,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
conn->pversion = PG_PROTOCOL(2, 0);
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2397,7 +2403,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->wait_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2413,7 +2419,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2574,7 +2580,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
PQclear(res);
|
|
|
b47050 |
conn->send_appname = false;
|
|
|
b47050 |
/* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2969,7 +2975,7 @@ closePGconn(PGconn *conn)
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Close the connection, reset all transient state, flush I/O buffers.
|
|
|
b47050 |
*/
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
|
|
|
b47050 |
* absent */
|
|
|
b47050 |
conn->asyncStatus = PGASYNC_IDLE;
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
index c1c5c75..58c9ce0 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-misc.c
|
|
|
b47050 |
@@ -815,7 +815,8 @@ definitelyEOF:
|
|
|
b47050 |
|
|
|
b47050 |
/* Come here if lower-level code already set a suitable errorMessage */
|
|
|
b47050 |
definitelyFailed:
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ /* Do *not* drop any already-read data; caller still wants it */
|
|
|
b47050 |
+ pqDropConnection(conn, false);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* No more connection to backend */
|
|
|
b47050 |
return -1;
|
|
|
b47050 |
}
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
index b130b4c..88ff74a 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-protocol3.c
|
|
|
b47050 |
@@ -456,8 +456,8 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
|
|
|
b47050 |
/* build an error result holding the error message */
|
|
|
b47050 |
pqSaveErrorResult(conn);
|
|
|
b47050 |
conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */
|
|
|
b47050 |
-
|
|
|
b47050 |
- pqDropConnection(conn);
|
|
|
b47050 |
+ /* flush input data since we're giving up on processing it */
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* No more connection to backend */
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
index 70b956b..8843ccb 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
+++ b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
@@ -489,7 +489,7 @@ extern char *const pgresStatus[];
|
|
|
b47050 |
|
|
|
b47050 |
/* === in fe-connect.c === */
|
|
|
b47050 |
|
|
|
b47050 |
-extern void pqDropConnection(PGconn *conn);
|
|
|
b47050 |
+extern void pqDropConnection(PGconn *conn, bool flushInput);
|
|
|
b47050 |
extern int pqPacketSend(PGconn *conn, char pack_type,
|
|
|
b47050 |
const void *buf, size_t buf_len);
|
|
|
b47050 |
extern bool pqGetHomeDirectory(char *buf, int bufsize);
|
|
|
b47050 |
--
|
|
|
b47050 |
2.17.1
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
From 3b08b525a118be43a334045409b1bad9cfaeb438 Mon Sep 17 00:00:00 2001
|
|
|
b47050 |
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
|
|
|
b47050 |
Date: Wed, 7 Jun 2017 14:01:46 +0300
|
|
|
b47050 |
Subject: [PATCH 3/4] Clear auth context correctly when re-connecting after
|
|
|
b47050 |
failed auth attempt.
|
|
|
b47050 |
|
|
|
b47050 |
If authentication over an SSL connection fails, with sslmode=prefer,
|
|
|
b47050 |
libpq will reconnect without SSL and retry. However, we did not clear
|
|
|
b47050 |
the variables related to GSS, SSPI, and SASL authentication state, when
|
|
|
b47050 |
reconnecting. Because of that, the second authentication attempt would
|
|
|
b47050 |
always fail with a "duplicate GSS/SASL authentication request" error.
|
|
|
b47050 |
pg_SSPI_startup did not check for duplicate authentication requests like
|
|
|
b47050 |
the corresponding GSS and SASL functions, so with SSPI, you would leak
|
|
|
b47050 |
some memory instead.
|
|
|
b47050 |
|
|
|
b47050 |
Another way this could manifest itself, on version 10, is if you list
|
|
|
b47050 |
multiple hostnames in the "host" parameter. If the first server requests
|
|
|
b47050 |
Kerberos or SCRAM authentication, but it fails, the attempts to connect to
|
|
|
b47050 |
the other servers will also fail with "duplicate authentication request"
|
|
|
b47050 |
errors.
|
|
|
b47050 |
|
|
|
b47050 |
To fix, move the clearing of authentication state from closePGconn to
|
|
|
b47050 |
pgDropConnection, so that it is cleared also when re-connecting.
|
|
|
b47050 |
|
|
|
b47050 |
Patch by Michael Paquier, with some kibitzing by me.
|
|
|
b47050 |
|
|
|
b47050 |
Backpatch down to 9.3. 9.2 has the same bug, but the code around closing
|
|
|
b47050 |
the connection is somewhat different, so that this patch doesn't apply.
|
|
|
b47050 |
To fix this in 9.2, I think we would need to back-port commit 210eb9b743
|
|
|
b47050 |
first, and then apply this patch. However, given that we only bumped into
|
|
|
b47050 |
this in our own testing, we haven't heard any reports from users about
|
|
|
b47050 |
this, and that 9.2 will be end-of-lifed in a couple of months anyway, it
|
|
|
b47050 |
doesn't seem worth the risk and trouble.
|
|
|
b47050 |
|
|
|
b47050 |
Discussion: https://www.postgresql.org/message-id/CAB7nPqRuOUm0MyJaUy9L3eXYJU3AKCZ-0-03=-aDTZJGV4GyWw@mail.gmail.com
|
|
|
b47050 |
|
|
|
b47050 |
Upstream commit: f2fa0c6514b6c5b7bccfe5050f6791dea1113c2e
|
|
|
b47050 |
---
|
|
|
b47050 |
src/interfaces/libpq/fe-auth.c | 7 ++-
|
|
|
b47050 |
src/interfaces/libpq/fe-connect.c | 76 +++++++++++++++++--------------
|
|
|
b47050 |
2 files changed, 47 insertions(+), 36 deletions(-)
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
|
|
|
b47050 |
index d10bd9f..ee961d9 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-auth.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-auth.c
|
|
|
b47050 |
@@ -618,7 +618,12 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate)
|
|
|
b47050 |
SECURITY_STATUS r;
|
|
|
b47050 |
TimeStamp expire;
|
|
|
b47050 |
|
|
|
b47050 |
- conn->sspictx = NULL;
|
|
|
b47050 |
+ if (conn->sspictx)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ printfPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
+ libpq_gettext("duplicate SSPI authentication request\n"));
|
|
|
b47050 |
+ return STATUS_ERROR;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Retreive credentials handle
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
index c22901d..6dbcbc6 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
@@ -379,15 +379,56 @@ pqDropConnection(PGconn *conn, bool flushInput)
|
|
|
b47050 |
{
|
|
|
b47050 |
/* Drop any SSL state */
|
|
|
b47050 |
pqsecure_close(conn);
|
|
|
b47050 |
+
|
|
|
b47050 |
/* Close the socket itself */
|
|
|
b47050 |
if (conn->sock >= 0)
|
|
|
b47050 |
closesocket(conn->sock);
|
|
|
b47050 |
conn->sock = -1;
|
|
|
b47050 |
+
|
|
|
b47050 |
/* Optionally discard any unread data */
|
|
|
b47050 |
if (flushInput)
|
|
|
b47050 |
conn->inStart = conn->inCursor = conn->inEnd = 0;
|
|
|
b47050 |
+
|
|
|
b47050 |
/* Always discard any unsent data */
|
|
|
b47050 |
conn->outCount = 0;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Free authentication state */
|
|
|
b47050 |
+#ifdef ENABLE_GSS
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ OM_uint32 min_s;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ if (conn->gctx)
|
|
|
b47050 |
+ gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
|
|
|
b47050 |
+ if (conn->gtarg_nam)
|
|
|
b47050 |
+ gss_release_name(&min_s, &conn->gtarg_nam);
|
|
|
b47050 |
+ if (conn->ginbuf.length)
|
|
|
b47050 |
+ gss_release_buffer(&min_s, &conn->ginbuf);
|
|
|
b47050 |
+ if (conn->goutbuf.length)
|
|
|
b47050 |
+ gss_release_buffer(&min_s, &conn->goutbuf);
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+#endif
|
|
|
b47050 |
+#ifdef ENABLE_SSPI
|
|
|
b47050 |
+ if (conn->ginbuf.length)
|
|
|
b47050 |
+ free(conn->ginbuf.value);
|
|
|
b47050 |
+ conn->ginbuf.length = 0;
|
|
|
b47050 |
+ conn->ginbuf.value = NULL;
|
|
|
b47050 |
+ if (conn->sspitarget)
|
|
|
b47050 |
+ free(conn->sspitarget);
|
|
|
b47050 |
+ conn->sspitarget = NULL;
|
|
|
b47050 |
+ if (conn->sspicred)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ FreeCredentialsHandle(conn->sspicred);
|
|
|
b47050 |
+ free(conn->sspicred);
|
|
|
b47050 |
+ conn->sspicred = NULL;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ if (conn->sspictx)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ DeleteSecurityContext(conn->sspictx);
|
|
|
b47050 |
+ free(conn->sspictx);
|
|
|
b47050 |
+ conn->sspictx = NULL;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ conn->usesspi = 0;
|
|
|
b47050 |
+#endif
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
@@ -3005,41 +3046,6 @@ closePGconn(PGconn *conn)
|
|
|
b47050 |
if (conn->lobjfuncs)
|
|
|
b47050 |
free(conn->lobjfuncs);
|
|
|
b47050 |
conn->lobjfuncs = NULL;
|
|
|
b47050 |
-#ifdef ENABLE_GSS
|
|
|
b47050 |
- {
|
|
|
b47050 |
- OM_uint32 min_s;
|
|
|
b47050 |
-
|
|
|
b47050 |
- if (conn->gctx)
|
|
|
b47050 |
- gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
|
|
|
b47050 |
- if (conn->gtarg_nam)
|
|
|
b47050 |
- gss_release_name(&min_s, &conn->gtarg_nam);
|
|
|
b47050 |
- if (conn->ginbuf.length)
|
|
|
b47050 |
- gss_release_buffer(&min_s, &conn->ginbuf);
|
|
|
b47050 |
- if (conn->goutbuf.length)
|
|
|
b47050 |
- gss_release_buffer(&min_s, &conn->goutbuf);
|
|
|
b47050 |
- }
|
|
|
b47050 |
-#endif
|
|
|
b47050 |
-#ifdef ENABLE_SSPI
|
|
|
b47050 |
- if (conn->ginbuf.length)
|
|
|
b47050 |
- free(conn->ginbuf.value);
|
|
|
b47050 |
- conn->ginbuf.length = 0;
|
|
|
b47050 |
- conn->ginbuf.value = NULL;
|
|
|
b47050 |
- if (conn->sspitarget)
|
|
|
b47050 |
- free(conn->sspitarget);
|
|
|
b47050 |
- conn->sspitarget = NULL;
|
|
|
b47050 |
- if (conn->sspicred)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- FreeCredentialsHandle(conn->sspicred);
|
|
|
b47050 |
- free(conn->sspicred);
|
|
|
b47050 |
- conn->sspicred = NULL;
|
|
|
b47050 |
- }
|
|
|
b47050 |
- if (conn->sspictx)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- DeleteSecurityContext(conn->sspictx);
|
|
|
b47050 |
- free(conn->sspictx);
|
|
|
b47050 |
- conn->sspictx = NULL;
|
|
|
b47050 |
- }
|
|
|
b47050 |
-#endif
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
--
|
|
|
b47050 |
2.17.1
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
From f25aa65f201df8925c39373aa10dfee19253d03e Mon Sep 17 00:00:00 2001
|
|
|
b47050 |
From: Tom Lane <tgl@sss.pgh.pa.us>
|
|
|
b47050 |
Date: Mon, 6 Aug 2018 10:53:35 -0400
|
|
|
b47050 |
Subject: [PATCH 4/4] Fix failure to reset libpq's state fully between
|
|
|
b47050 |
connection attempts.
|
|
|
b47050 |
|
|
|
b47050 |
The logic in PQconnectPoll() did not take care to ensure that all of
|
|
|
b47050 |
a PGconn's internal state variables were reset before trying a new
|
|
|
b47050 |
connection attempt. If we got far enough in the connection sequence
|
|
|
b47050 |
to have changed any of these variables, and then decided to try a new
|
|
|
b47050 |
server address or server name, the new connection might be completed
|
|
|
b47050 |
with some state that really only applied to the failed connection.
|
|
|
b47050 |
|
|
|
b47050 |
While this has assorted bad consequences, the only one that is clearly
|
|
|
b47050 |
a security issue is that password_needed didn't get reset, so that
|
|
|
b47050 |
if the first server asked for a password and the second didn't,
|
|
|
b47050 |
PQconnectionUsedPassword() would return an incorrect result. This
|
|
|
b47050 |
could be leveraged by unprivileged users of dblink or postgres_fdw
|
|
|
b47050 |
to allow them to use server-side login credentials that they should
|
|
|
b47050 |
not be able to use.
|
|
|
b47050 |
|
|
|
b47050 |
Other notable problems include the possibility of forcing a v2-protocol
|
|
|
b47050 |
connection to a server capable of supporting v3, or overriding
|
|
|
b47050 |
"sslmode=prefer" to cause a non-encrypted connection to a server that
|
|
|
b47050 |
would have accepted an encrypted one. Those are certainly bugs but
|
|
|
b47050 |
it's harder to paint them as security problems in themselves. However,
|
|
|
b47050 |
forcing a v2-protocol connection could result in libpq having a wrong
|
|
|
b47050 |
idea of the server's standard_conforming_strings setting, which opens
|
|
|
b47050 |
the door to SQL-injection attacks. The extent to which that's actually
|
|
|
b47050 |
a problem, given the prerequisite that the attacker needs control of
|
|
|
b47050 |
the client's connection parameters, is unclear.
|
|
|
b47050 |
|
|
|
b47050 |
These problems have existed for a long time, but became more easily
|
|
|
b47050 |
exploitable in v10, both because it introduced easy ways to force libpq
|
|
|
b47050 |
to abandon a connection attempt at a late stage and then try another one
|
|
|
b47050 |
(rather than just giving up), and because it provided an easy way to
|
|
|
b47050 |
specify multiple target hosts.
|
|
|
b47050 |
|
|
|
b47050 |
Fix by rearranging PQconnectPoll's state machine to provide centralized
|
|
|
b47050 |
places to reset state properly when moving to a new target host or when
|
|
|
b47050 |
dropping and retrying a connection to the same host.
|
|
|
b47050 |
|
|
|
b47050 |
Tom Lane, reviewed by Noah Misch. Our thanks to Andrew Krasichkov
|
|
|
b47050 |
for finding and reporting the problem.
|
|
|
b47050 |
|
|
|
b47050 |
Security: CVE-2018-10915
|
|
|
b47050 |
|
|
|
b47050 |
Upstream commit: 243de06be96d6001d01f2ec7c4573aad8b657195
|
|
|
b47050 |
---
|
|
|
b47050 |
src/interfaces/libpq/fe-connect.c | 301 +++++++++++++++++++-----------
|
|
|
b47050 |
src/interfaces/libpq/libpq-int.h | 2 +
|
|
|
b47050 |
2 files changed, 196 insertions(+), 107 deletions(-)
|
|
|
b47050 |
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
index 6dbcbc6..ca06337 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
+++ b/src/interfaces/libpq/fe-connect.c
|
|
|
b47050 |
@@ -368,7 +368,8 @@ pgthreadlock_t pg_g_threadlock = default_threadlock;
|
|
|
b47050 |
*
|
|
|
b47050 |
* Close any physical connection to the server, and reset associated
|
|
|
b47050 |
* state inside the connection object. We don't release state that
|
|
|
b47050 |
- * would be needed to reconnect, though.
|
|
|
b47050 |
+ * would be needed to reconnect, though, nor local state that might still
|
|
|
b47050 |
+ * be useful later.
|
|
|
b47050 |
*
|
|
|
b47050 |
* We can always flush the output buffer, since there's no longer any hope
|
|
|
b47050 |
* of sending that data. However, unprocessed input data might still be
|
|
|
b47050 |
@@ -432,6 +433,64 @@ pqDropConnection(PGconn *conn, bool flushInput)
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
|
|
|
b47050 |
+/*
|
|
|
b47050 |
+ * pqDropServerData
|
|
|
b47050 |
+ *
|
|
|
b47050 |
+ * Clear all connection state data that was received from (or deduced about)
|
|
|
b47050 |
+ * the server. This is essential to do between connection attempts to
|
|
|
b47050 |
+ * different servers, else we may incorrectly hold over some data from the
|
|
|
b47050 |
+ * old server.
|
|
|
b47050 |
+ *
|
|
|
b47050 |
+ * It would be better to merge this into pqDropConnection, perhaps, but
|
|
|
b47050 |
+ * right now we cannot because that function is called immediately on
|
|
|
b47050 |
+ * detection of connection loss (cf. pqReadData, for instance). This data
|
|
|
b47050 |
+ * should be kept until we are actually starting a new connection.
|
|
|
b47050 |
+ */
|
|
|
b47050 |
+static void
|
|
|
b47050 |
+pqDropServerData(PGconn *conn)
|
|
|
b47050 |
+{
|
|
|
b47050 |
+ PGnotify *notify;
|
|
|
b47050 |
+ pgParameterStatus *pstatus;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Forget pending notifies */
|
|
|
b47050 |
+ notify = conn->notifyHead;
|
|
|
b47050 |
+ while (notify != NULL)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ PGnotify *prev = notify;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ notify = notify->next;
|
|
|
b47050 |
+ free(prev);
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ conn->notifyHead = conn->notifyTail = NULL;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Reset ParameterStatus data, as well as variables deduced from it */
|
|
|
b47050 |
+ pstatus = conn->pstatus;
|
|
|
b47050 |
+ while (pstatus != NULL)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ pgParameterStatus *prev = pstatus;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ pstatus = pstatus->next;
|
|
|
b47050 |
+ free(prev);
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ conn->pstatus = NULL;
|
|
|
b47050 |
+ conn->client_encoding = PG_SQL_ASCII;
|
|
|
b47050 |
+ conn->std_strings = false;
|
|
|
b47050 |
+ conn->sversion = 0;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Drop large-object lookup data */
|
|
|
b47050 |
+ if (conn->lobjfuncs)
|
|
|
b47050 |
+ free(conn->lobjfuncs);
|
|
|
b47050 |
+ conn->lobjfuncs = NULL;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Reset assorted other per-connection state */
|
|
|
b47050 |
+ conn->last_sqlstate[0] = '\0';
|
|
|
b47050 |
+ conn->auth_req_received = false;
|
|
|
b47050 |
+ conn->password_needed = false;
|
|
|
b47050 |
+ conn->be_pid = 0;
|
|
|
b47050 |
+ conn->be_key = 0;
|
|
|
b47050 |
+}
|
|
|
b47050 |
+
|
|
|
b47050 |
+
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Connecting to a Database
|
|
|
b47050 |
*
|
|
|
b47050 |
@@ -1517,22 +1576,14 @@ connectDBStart(PGconn *conn)
|
|
|
b47050 |
goto connect_errReturn;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
-#ifdef USE_SSL
|
|
|
b47050 |
- /* setup values based on SSL mode */
|
|
|
b47050 |
- if (conn->sslmode[0] == 'd') /* "disable" */
|
|
|
b47050 |
- conn->allow_ssl_try = false;
|
|
|
b47050 |
- else if (conn->sslmode[0] == 'a') /* "allow" */
|
|
|
b47050 |
- conn->wait_ssl_try = true;
|
|
|
b47050 |
-#endif
|
|
|
b47050 |
-
|
|
|
b47050 |
/*
|
|
|
b47050 |
- * Set up to try to connect, with protocol 3.0 as the first attempt.
|
|
|
b47050 |
+ * Set up to try to connect to the first address.
|
|
|
b47050 |
*/
|
|
|
b47050 |
conn->addrlist = addrs;
|
|
|
b47050 |
conn->addr_cur = addrs;
|
|
|
b47050 |
conn->addrlist_family = hint.ai_family;
|
|
|
b47050 |
- conn->pversion = PG_PROTOCOL(3, 0);
|
|
|
b47050 |
- conn->send_appname = true;
|
|
|
b47050 |
+ conn->try_next_addr = false;
|
|
|
b47050 |
+ conn->is_new_addr = true;
|
|
|
b47050 |
conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
@@ -1546,6 +1597,12 @@ connectDBStart(PGconn *conn)
|
|
|
b47050 |
return 1;
|
|
|
b47050 |
|
|
|
b47050 |
connect_errReturn:
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /*
|
|
|
b47050 |
+ * If we managed to open a socket, close it immediately rather than
|
|
|
b47050 |
+ * waiting till PQfinish. (The application cannot have gotten the socket
|
|
|
b47050 |
+ * from PQsocket yet, so this doesn't risk breaking anything.)
|
|
|
b47050 |
+ */
|
|
|
b47050 |
pqDropConnection(conn, true);
|
|
|
b47050 |
conn->status = CONNECTION_BAD;
|
|
|
b47050 |
return 0;
|
|
|
b47050 |
@@ -1607,6 +1664,7 @@ connectDBComplete(PGconn *conn)
|
|
|
b47050 |
case PGRES_POLLING_READING:
|
|
|
b47050 |
if (pqWaitTimed(1, 0, conn, finish_time))
|
|
|
b47050 |
{
|
|
|
b47050 |
+ /* hard failure, eg select() problem, aborts everything */
|
|
|
b47050 |
conn->status = CONNECTION_BAD;
|
|
|
b47050 |
return 0;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1615,6 +1673,7 @@ connectDBComplete(PGconn *conn)
|
|
|
b47050 |
case PGRES_POLLING_WRITING:
|
|
|
b47050 |
if (pqWaitTimed(0, 1, conn, finish_time))
|
|
|
b47050 |
{
|
|
|
b47050 |
+ /* hard failure, eg select() problem, aborts everything */
|
|
|
b47050 |
conn->status = CONNECTION_BAD;
|
|
|
b47050 |
return 0;
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -1663,6 +1722,7 @@ connectDBComplete(PGconn *conn)
|
|
|
b47050 |
PostgresPollingStatusType
|
|
|
b47050 |
PQconnectPoll(PGconn *conn)
|
|
|
b47050 |
{
|
|
|
b47050 |
+ bool need_new_connection = false;
|
|
|
b47050 |
PGresult *res;
|
|
|
b47050 |
char sebuf[256];
|
|
|
b47050 |
int optval;
|
|
|
b47050 |
@@ -1723,6 +1783,69 @@ PQconnectPoll(PGconn *conn)
|
|
|
b47050 |
|
|
|
b47050 |
keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* nothing left to do. */
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Time to advance to next address? */
|
|
|
b47050 |
+ if (conn->try_next_addr)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ if (conn->addr_cur && conn->addr_cur->ai_next)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ conn->addr_cur = conn->addr_cur->ai_next;
|
|
|
b47050 |
+ conn->is_new_addr = true;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ else
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ /*
|
|
|
b47050 |
+ * Oops, no more addresses. An appropriate error message is
|
|
|
b47050 |
+ * already set up, so just set the right status.
|
|
|
b47050 |
+ */
|
|
|
b47050 |
+ goto error_return;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+ conn->try_next_addr = false;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Reset connection state machine? */
|
|
|
b47050 |
+ if (conn->is_new_addr)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ /*
|
|
|
b47050 |
+ * (Re) initialize our connection control variables for a set of
|
|
|
b47050 |
+ * connection attempts to a single server address. These variables
|
|
|
b47050 |
+ * must persist across individual connection attempts, but we must
|
|
|
b47050 |
+ * reset them when we start to consider a new address (since it might
|
|
|
b47050 |
+ * not be the same server).
|
|
|
b47050 |
+ */
|
|
|
b47050 |
+ conn->pversion = PG_PROTOCOL(3, 0);
|
|
|
b47050 |
+ conn->send_appname = true;
|
|
|
b47050 |
+#ifdef USE_SSL
|
|
|
b47050 |
+ /* initialize these values based on SSL mode */
|
|
|
b47050 |
+ conn->allow_ssl_try = (conn->sslmode[0] != 'd'); /* "disable" */
|
|
|
b47050 |
+ conn->wait_ssl_try = (conn->sslmode[0] == 'a'); /* "allow" */
|
|
|
b47050 |
+#endif
|
|
|
b47050 |
+
|
|
|
b47050 |
+ conn->is_new_addr = false;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Force a new connection (perhaps to the same server as before)? */
|
|
|
b47050 |
+ if (need_new_connection)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ /* Drop any existing connection */
|
|
|
b47050 |
+ pqDropConnection(conn, true);
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Reset all state obtained from old server */
|
|
|
b47050 |
+ pqDropServerData(conn);
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Drop any PGresult we might have, too */
|
|
|
b47050 |
+ conn->asyncStatus = PGASYNC_IDLE;
|
|
|
b47050 |
+ conn->xactStatus = PQTRANS_IDLE;
|
|
|
b47050 |
+ pqClearAsyncResult(conn);
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Reset conn->status to put the state machine in the right state */
|
|
|
b47050 |
+ conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+
|
|
|
b47050 |
+ need_new_connection = false;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+
|
|
|
b47050 |
+ /* Now try to advance the state machine for this connection */
|
|
|
b47050 |
switch (conn->status)
|
|
|
b47050 |
{
|
|
|
b47050 |
case CONNECTION_NEEDED:
|
|
|
b47050 |
@@ -1730,12 +1853,24 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Try to initiate a connection to one of the addresses
|
|
|
b47050 |
* returned by pg_getaddrinfo_all(). conn->addr_cur is the
|
|
|
b47050 |
- * next one to try. We fail when we run out of addresses.
|
|
|
b47050 |
+ * next one to try.
|
|
|
b47050 |
+ *
|
|
|
b47050 |
+ * The extra level of braces here is historical. It's not
|
|
|
b47050 |
+ * worth reindenting this whole switch case to remove 'em.
|
|
|
b47050 |
*/
|
|
|
b47050 |
- while (conn->addr_cur != NULL)
|
|
|
b47050 |
{
|
|
|
b47050 |
struct addrinfo *addr_cur = conn->addr_cur;
|
|
|
b47050 |
|
|
|
b47050 |
+ if (addr_cur == NULL)
|
|
|
b47050 |
+ {
|
|
|
b47050 |
+ /*
|
|
|
b47050 |
+ * Ooops, no more addresses. An appropriate error
|
|
|
b47050 |
+ * message is already set up, so just set the right
|
|
|
b47050 |
+ * status.
|
|
|
b47050 |
+ */
|
|
|
b47050 |
+ goto error_return;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
+
|
|
|
b47050 |
/* Remember current address for possible error msg */
|
|
|
b47050 |
memcpy(&conn->raddr.addr, addr_cur->ai_addr,
|
|
|
b47050 |
addr_cur->ai_addrlen);
|
|
|
b47050 |
@@ -1761,32 +1896,34 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
if (conn->sock == -1)
|
|
|
b47050 |
{
|
|
|
b47050 |
/*
|
|
|
b47050 |
- * ignore socket() failure if we have more addresses
|
|
|
b47050 |
- * to try
|
|
|
b47050 |
+ * Silently ignore socket() failure if we have more
|
|
|
b47050 |
+ * addresses to try; this reduces useless chatter in
|
|
|
b47050 |
+ * cases where the address list includes both IPv4 and
|
|
|
b47050 |
+ * IPv6 but kernel only accepts one family.
|
|
|
b47050 |
*/
|
|
|
b47050 |
if (addr_cur->ai_next != NULL)
|
|
|
b47050 |
{
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- continue;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not create socket: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- break;
|
|
|
b47050 |
+ goto error_return;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* Select socket options: no delay of outgoing data for
|
|
|
b47050 |
- * TCP sockets, nonblock mode, close-on-exec. Fail if any
|
|
|
b47050 |
- * of this fails.
|
|
|
b47050 |
+ * TCP sockets, nonblock mode, close-on-exec. Try the
|
|
|
b47050 |
+ * next address if any of this fails.
|
|
|
b47050 |
*/
|
|
|
b47050 |
if (!IS_AF_UNIX(addr_cur->ai_family))
|
|
|
b47050 |
{
|
|
|
b47050 |
if (!connectNoDelay(conn))
|
|
|
b47050 |
{
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- continue;
|
|
|
b47050 |
+ /* error message already created */
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
}
|
|
|
b47050 |
if (!pg_set_noblock(conn->sock))
|
|
|
b47050 |
@@ -1794,9 +1931,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- continue;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
#ifdef F_SETFD
|
|
|
b47050 |
@@ -1805,9 +1941,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
appendPQExpBuffer(&conn->errorMessage,
|
|
|
b47050 |
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
|
|
|
b47050 |
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- continue;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
#endif /* F_SETFD */
|
|
|
b47050 |
|
|
|
b47050 |
@@ -1853,9 +1988,8 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
|
|
|
b47050 |
if (err)
|
|
|
b47050 |
{
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- continue;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -1934,25 +2068,13 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
- * This connection failed --- set up error report, then
|
|
|
b47050 |
- * close socket (do it this way in case close() affects
|
|
|
b47050 |
- * the value of errno...). We will ignore the connect()
|
|
|
b47050 |
- * failure and keep going if there are more addresses.
|
|
|
b47050 |
+ * This connection failed. Add the error report to
|
|
|
b47050 |
+ * conn->errorMessage, then try the next address if any.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, SOCK_ERRNO);
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
-
|
|
|
b47050 |
- /*
|
|
|
b47050 |
- * Try the next address, if any.
|
|
|
b47050 |
- */
|
|
|
b47050 |
- conn->addr_cur = addr_cur->ai_next;
|
|
|
b47050 |
- } /* loop over addresses */
|
|
|
b47050 |
-
|
|
|
b47050 |
- /*
|
|
|
b47050 |
- * Ooops, no more addresses. An appropriate error message is
|
|
|
b47050 |
- * already set up, so just set the right status.
|
|
|
b47050 |
- */
|
|
|
b47050 |
- goto error_return;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
+ }
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
case CONNECTION_STARTED:
|
|
|
b47050 |
@@ -1985,19 +2107,13 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* error message.
|
|
|
b47050 |
*/
|
|
|
b47050 |
connectFailureMessage(conn, optval);
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
- * If more addresses remain, keep trying, just as in the
|
|
|
b47050 |
- * case where connect() returned failure immediately.
|
|
|
b47050 |
+ * Try the next address if any, just as in the case where
|
|
|
b47050 |
+ * connect() returned failure immediately.
|
|
|
b47050 |
*/
|
|
|
b47050 |
- if (conn->addr_cur->ai_next != NULL)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- conn->addr_cur = conn->addr_cur->ai_next;
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
- goto keep_going;
|
|
|
b47050 |
- }
|
|
|
b47050 |
- goto error_return;
|
|
|
b47050 |
+ conn->try_next_addr = true;
|
|
|
b47050 |
+ goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
/* Fill in the client address */
|
|
|
b47050 |
@@ -2266,12 +2382,13 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
- /* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
+ /* Else it's a hard failure */
|
|
|
b47050 |
+ goto error_return;
|
|
|
b47050 |
}
|
|
|
b47050 |
+ /* Else, return POLLING_READING or POLLING_WRITING status */
|
|
|
b47050 |
return pollres;
|
|
|
b47050 |
#else /* !USE_SSL */
|
|
|
b47050 |
/* can't get here */
|
|
|
b47050 |
@@ -2377,9 +2494,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
|
|
|
b47050 |
{
|
|
|
b47050 |
conn->pversion = PG_PROTOCOL(2, 0);
|
|
|
b47050 |
- /* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -2430,6 +2545,9 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
/* OK, we read the message; mark data consumed */
|
|
|
b47050 |
conn->inStart = conn->inCursor;
|
|
|
b47050 |
|
|
|
b47050 |
+ /* Check to see if we should mention pgpassfile */
|
|
|
b47050 |
+ dot_pg_pass_warning(conn);
|
|
|
b47050 |
+
|
|
|
b47050 |
#ifdef USE_SSL
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
@@ -2443,9 +2561,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->wait_ssl_try = false;
|
|
|
b47050 |
- /* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
@@ -2454,14 +2570,13 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
* then do a non-SSL retry
|
|
|
b47050 |
*/
|
|
|
b47050 |
if (conn->sslmode[0] == 'p' /* "prefer" */
|
|
|
b47050 |
- && conn->allow_ssl_try
|
|
|
b47050 |
+ && conn->ssl != NULL
|
|
|
b47050 |
+ && conn->allow_ssl_try /* redundant? */
|
|
|
b47050 |
&& !conn->wait_ssl_try) /* redundant? */
|
|
|
b47050 |
{
|
|
|
b47050 |
/* only retry once */
|
|
|
b47050 |
conn->allow_ssl_try = false;
|
|
|
b47050 |
- /* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
#endif
|
|
|
b47050 |
@@ -2620,9 +2735,7 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
{
|
|
|
b47050 |
PQclear(res);
|
|
|
b47050 |
conn->send_appname = false;
|
|
|
b47050 |
- /* Must drop the old connection */
|
|
|
b47050 |
- pqDropConnection(conn, true);
|
|
|
b47050 |
- conn->status = CONNECTION_NEEDED;
|
|
|
b47050 |
+ need_new_connection = true;
|
|
|
b47050 |
goto keep_going;
|
|
|
b47050 |
}
|
|
|
b47050 |
}
|
|
|
b47050 |
@@ -2702,8 +2815,6 @@ keep_going: /* We will come back to here until there is
|
|
|
b47050 |
|
|
|
b47050 |
error_return:
|
|
|
b47050 |
|
|
|
b47050 |
- dot_pg_pass_warning(conn);
|
|
|
b47050 |
-
|
|
|
b47050 |
/*
|
|
|
b47050 |
* We used to close the socket at this point, but that makes it awkward
|
|
|
b47050 |
* for those above us if they wish to remove this socket from their own
|
|
|
b47050 |
@@ -2830,13 +2941,7 @@ makeEmptyPGconn(void)
|
|
|
b47050 |
conn->std_strings = false; /* unless server says differently */
|
|
|
b47050 |
conn->verbosity = PQERRORS_DEFAULT;
|
|
|
b47050 |
conn->sock = -1;
|
|
|
b47050 |
- conn->auth_req_received = false;
|
|
|
b47050 |
- conn->password_needed = false;
|
|
|
b47050 |
conn->dot_pgpass_used = false;
|
|
|
b47050 |
-#ifdef USE_SSL
|
|
|
b47050 |
- conn->allow_ssl_try = true;
|
|
|
b47050 |
- conn->wait_ssl_try = false;
|
|
|
b47050 |
-#endif
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
* We try to send at least 8K at a time, which is the usual size of pipe
|
|
|
b47050 |
@@ -2987,10 +3092,9 @@ freePGconn(PGconn *conn)
|
|
|
b47050 |
static void
|
|
|
b47050 |
closePGconn(PGconn *conn)
|
|
|
b47050 |
{
|
|
|
b47050 |
- PGnotify *notify;
|
|
|
b47050 |
- pgParameterStatus *pstatus;
|
|
|
b47050 |
-
|
|
|
b47050 |
/*
|
|
|
b47050 |
+ * If possible, send Terminate message to close the connection politely.
|
|
|
b47050 |
+ *
|
|
|
b47050 |
* Note that the protocol doesn't allow us to send Terminate messages
|
|
|
b47050 |
* during the startup phase.
|
|
|
b47050 |
*/
|
|
|
b47050 |
@@ -3020,32 +3124,15 @@ closePGconn(PGconn *conn)
|
|
|
b47050 |
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
|
|
|
b47050 |
* absent */
|
|
|
b47050 |
conn->asyncStatus = PGASYNC_IDLE;
|
|
|
b47050 |
+ conn->xactStatus = PQTRANS_IDLE;
|
|
|
b47050 |
pqClearAsyncResult(conn); /* deallocate result */
|
|
|
b47050 |
resetPQExpBuffer(&conn->errorMessage);
|
|
|
b47050 |
pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
|
|
|
b47050 |
conn->addrlist = NULL;
|
|
|
b47050 |
conn->addr_cur = NULL;
|
|
|
b47050 |
- notify = conn->notifyHead;
|
|
|
b47050 |
- while (notify != NULL)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- PGnotify *prev = notify;
|
|
|
b47050 |
|
|
|
b47050 |
- notify = notify->next;
|
|
|
b47050 |
- free(prev);
|
|
|
b47050 |
- }
|
|
|
b47050 |
- conn->notifyHead = conn->notifyTail = NULL;
|
|
|
b47050 |
- pstatus = conn->pstatus;
|
|
|
b47050 |
- while (pstatus != NULL)
|
|
|
b47050 |
- {
|
|
|
b47050 |
- pgParameterStatus *prev = pstatus;
|
|
|
b47050 |
-
|
|
|
b47050 |
- pstatus = pstatus->next;
|
|
|
b47050 |
- free(prev);
|
|
|
b47050 |
- }
|
|
|
b47050 |
- conn->pstatus = NULL;
|
|
|
b47050 |
- if (conn->lobjfuncs)
|
|
|
b47050 |
- free(conn->lobjfuncs);
|
|
|
b47050 |
- conn->lobjfuncs = NULL;
|
|
|
b47050 |
+ /* Reset all state obtained from server, too */
|
|
|
b47050 |
+ pqDropServerData(conn);
|
|
|
b47050 |
}
|
|
|
b47050 |
|
|
|
b47050 |
/*
|
|
|
b47050 |
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
index 8843ccb..eaa80b6 100644
|
|
|
b47050 |
--- a/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
+++ b/src/interfaces/libpq/libpq-int.h
|
|
|
b47050 |
@@ -375,6 +375,8 @@ struct pg_conn
|
|
|
b47050 |
bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */
|
|
|
b47050 |
|
|
|
b47050 |
/* Transient state needed while establishing connection */
|
|
|
b47050 |
+ bool try_next_addr; /* time to advance to next address? */
|
|
|
b47050 |
+ bool is_new_addr; /* need to (re)initialize for new address? */
|
|
|
b47050 |
struct addrinfo *addrlist; /* list of possible backend addresses */
|
|
|
b47050 |
struct addrinfo *addr_cur; /* the one currently being tried */
|
|
|
b47050 |
int addrlist_family; /* needed to know how to free addrlist */
|
|
|
b47050 |
--
|
|
|
b47050 |
2.17.1
|
|
|
b47050 |
|