*
* 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"
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
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;
}
goto startup_failed;
}
+ freeaddrinfo_all(hints.ai_family, addrs);
+
return;
startup_failed: