Re: [HACKERS] listening addresses - Mailing list pgsql-patches

From Tom Lane
Subject Re: [HACKERS] listening addresses
Date
Msg-id 12662.1080000007@sss.pgh.pa.us
Whole thread Raw
In response to Re: [HACKERS] listening addresses  (Andrew Dunstan <andrew@dunslane.net>)
List pgsql-patches
Andrew Dunstan <andrew@dunslane.net> writes:
>> A small problem with it was reported to me a couple of days ago -
>> user had firewalled off all IP6 traffic. The stats collector happily
>> bound and connected to the socket, but all the packets fell in the
>> bit bucket. They found it quite hard to diagnose the problem.

> Revised patch attached. I think this is about as much trouble as this
> problem is worth ;-)

I thought the messages were a bit sloppy, which made the patch much less
useful than it should be: we are testing for a very specific failure
mode and we can give a very specific message.  Patch as-applied is
attached.

I don't have any real convenient way to set up a situation where this
failure can actually occur.  Anyone want to verify that the patch
acts as intended?

            regards, tom lane

*** src/backend/postmaster/pgstat.c.orig    Mon Mar 15 15:01:57 2004
--- src/backend/postmaster/pgstat.c    Mon Mar 22 18:55:29 2004
***************
*** 191,196 ****
--- 191,202 ----
                 *addr,
                  hints;
      int            ret;
+     fd_set      rset;
+     struct timeval tv;
+     char        test_byte;
+     int         sel_res;
+
+ #define TESTBYTEVAL ((char) 199)

      /*
       * Force start of collector daemon if something to collect
***************
*** 303,308 ****
--- 309,393 ----
              ereport(LOG,
                      (errcode_for_socket_access(),
                       errmsg("could not connect socket for statistics collector: %m")));
+             closesocket(pgStatSock);
+             pgStatSock = -1;
+             continue;
+         }
+
+         /*
+          * Try to send and receive a one-byte test message on the socket.
+          * This is to catch situations where the socket can be created but
+          * will not actually pass data (for instance, because kernel packet
+          * filtering rules prevent it).
+          */
+         test_byte = TESTBYTEVAL;
+         if (send(pgStatSock, &test_byte, 1, 0) != 1)
+         {
+             ereport(LOG,
+                     (errcode_for_socket_access(),
+                      errmsg("could not send test message on socket for statistics collector: %m")));
+             closesocket(pgStatSock);
+             pgStatSock = -1;
+             continue;
+         }
+
+         /*
+          * There could possibly be a little delay before the message can be
+          * received.  We arbitrarily allow up to half a second before deciding
+          * it's broken.
+          */
+         for (;;)                /* need a loop to handle EINTR */
+         {
+             FD_ZERO(&rset);
+             FD_SET(pgStatSock, &rset);
+             tv.tv_sec = 0;
+             tv.tv_usec = 500000;
+             sel_res = select(pgStatSock+1, &rset, NULL, NULL, &tv);
+             if (sel_res >= 0 || errno != EINTR)
+                 break;
+         }
+         if (sel_res < 0)
+         {
+             ereport(LOG,
+                     (errcode_for_socket_access(),
+                      errmsg("select() failed in statistics collector: %m")));
+             closesocket(pgStatSock);
+             pgStatSock = -1;
+             continue;
+         }
+         if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset))
+         {
+             /*
+              * This is the case we actually think is likely, so take pains to
+              * give a specific message for it.
+              *
+              * errno will not be set meaningfully here, so don't use it.
+              */
+             ereport(LOG,
+                     (ERRCODE_CONNECTION_FAILURE,
+                      errmsg("test message did not get through on socket for statistics collector")));
+             closesocket(pgStatSock);
+             pgStatSock = -1;
+             continue;
+         }
+
+         test_byte++;            /* just make sure variable is changed */
+
+         if (recv(pgStatSock, &test_byte, 1, 0) != 1)
+         {
+             ereport(LOG,
+                     (errcode_for_socket_access(),
+                      errmsg("could not receive test message on socket for statistics collector: %m")));
+             closesocket(pgStatSock);
+             pgStatSock = -1;
+             continue;
+         }
+
+         if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */
+         {
+             ereport(LOG,
+                     (ERRCODE_INTERNAL_ERROR,
+                      errmsg("incorrect test message transmission on socket for statistics collector")));
              closesocket(pgStatSock);
              pgStatSock = -1;
              continue;

pgsql-patches by date:

Previous
From: Claudio Natoli
Date:
Subject: Re: Patch for select and APC on win32
Next
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] listening addresses