]> granicus.if.org Git - postgresql/commitdiff
Make creation of statistics collection socket more robust, by allowing it
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 15 Nov 2003 17:24:07 +0000 (17:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 15 Nov 2003 17:24:07 +0000 (17:24 +0000)
to try additional addresses returned from getaddrinfo() if the first one
fails at the bind() or connect() steps.  Per yesterday's discussion.

src/backend/postmaster/pgstat.c

index 2539c32d6542fb6a3a4904ca185115ef38a88b86..590bdd675dc94f659f298b832f20f7d4e752b7b5 100644 (file)
@@ -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: