aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-11-15 17:24:07 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-11-15 17:24:07 +0000
commit5b6b587a95b70528ac402ad9fda8215709d9636f (patch)
tree4cf49d28048e8628642134cd0e625fcd96c5071b /src
parent472d9726dd30ee25382297abcb93bdf728b826da (diff)
downloadpostgresql-5b6b587a95b70528ac402ad9fda8215709d9636f.tar.gz
postgresql-5b6b587a95b70528ac402ad9fda8215709d9636f.zip
Make creation of statistics collection socket more robust, by allowing it
to try additional addresses returned from getaddrinfo() if the first one fails at the bind() or connect() steps. Per yesterday's discussion.
Diffstat (limited to 'src')
-rw-r--r--src/backend/postmaster/pgstat.c103
1 files changed, 64 insertions, 39 deletions
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 2539c32d654..590bdd675dc 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.46 2003/11/07 21:55:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.47 2003/11/15 17:24:07 tgl Exp $
* ----------
*/
#include "postgres.h"
@@ -203,6 +203,14 @@ pgstat_init(void)
goto startup_failed;
}
+ /*
+ * On some platforms, getaddrinfo_all() may return multiple addresses
+ * only one of which will actually work (eg, both IPv6 and IPv4 addresses
+ * when kernel will reject IPv6). Worse, the failure may occur at the
+ * bind() or perhaps even connect() stage. So we must loop through the
+ * results till we find a working combination. We will generate LOG
+ * messages, but no error, for bogus combinations.
+ */
for (addr = addrs; addr; addr = addr->ai_next)
{
#ifdef HAVE_UNIX_SOCKETS
@@ -210,53 +218,68 @@ pgstat_init(void)
if (addr->ai_family == AF_UNIX)
continue;
#endif
- if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) >= 0)
- break;
- }
+ /*
+ * Create the socket.
+ */
+ if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_socket_access(),
+ errmsg("could not create socket for statistics collector: %m")));
+ continue;
+ }
- if (!addr || pgStatSock < 0)
- {
- ereport(LOG,
- (errcode_for_socket_access(),
- errmsg("could not create socket for statistics collector: %m")));
- goto startup_failed;
- }
+ /*
+ * Bind it to a kernel assigned port on localhost and get the assigned
+ * port via getsockname().
+ */
+ if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_socket_access(),
+ errmsg("could not bind socket for statistics collector: %m")));
+ closesocket(pgStatSock);
+ pgStatSock = -1;
+ continue;
+ }
- /*
- * Bind it to a kernel assigned port on localhost and get the assigned
- * port via getsockname().
- */
- if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
- {
- ereport(LOG,
- (errcode_for_socket_access(),
- errmsg("could not bind socket for statistics collector: %m")));
- goto startup_failed;
- }
+ alen = sizeof(pgStatAddr);
+ if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_socket_access(),
+ errmsg("could not get address of socket for statistics collector: %m")));
+ closesocket(pgStatSock);
+ pgStatSock = -1;
+ continue;
+ }
- freeaddrinfo_all(hints.ai_family, addrs);
- addrs = NULL;
+ /*
+ * Connect the socket to its own address. This saves a few cycles by
+ * not having to respecify the target address on every send. This also
+ * provides a kernel-level check that only packets from this same
+ * address will be received.
+ */
+ if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0)
+ {
+ ereport(LOG,
+ (errcode_for_socket_access(),
+ errmsg("could not connect socket for statistics collector: %m")));
+ closesocket(pgStatSock);
+ pgStatSock = -1;
+ continue;
+ }
- alen = sizeof(pgStatAddr);
- if (getsockname(pgStatSock, (struct sockaddr *) & pgStatAddr, &alen) < 0)
- {
- ereport(LOG,
- (errcode_for_socket_access(),
- errmsg("could not get address of socket for statistics collector: %m")));
- goto startup_failed;
+ /* If we get here, we have a working socket */
+ break;
}
- /*
- * Connect the socket to its own address. This saves a few cycles by
- * not having to respecify the target address on every send. This also
- * provides a kernel-level check that only packets from this same
- * address will be received.
- */
- if (connect(pgStatSock, (struct sockaddr *) & pgStatAddr, alen) < 0)
+ /* Did we find a working address? */
+ if (!addr || pgStatSock < 0)
{
ereport(LOG,
(errcode_for_socket_access(),
- errmsg("could not connect socket for statistics collector: %m")));
+ errmsg("disabling statistics collector for lack of working socket")));
goto startup_failed;
}
@@ -285,6 +308,8 @@ pgstat_init(void)
goto startup_failed;
}
+ freeaddrinfo_all(hints.ai_family, addrs);
+
return;
startup_failed: