Skip to content

Commit 0d88dd1

Browse files
committed
Before deciding we can use a socket for statistics collection, test to
ensure that it actually passes data. This catches cases such as a kernel packet filter rule that makes the socket useless. Andrew Dunstan
1 parent 6b198d6 commit 0d88dd1

File tree

1 file changed

+86
-1
lines changed

1 file changed

+86
-1
lines changed

src/backend/postmaster/pgstat.c

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
1515
*
16-
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.61 2004/03/15 16:21:37 momjian Exp $
16+
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.62 2004/03/22 23:55:29 tgl Exp $
1717
* ----------
1818
*/
1919
#include "postgres.h"
@@ -191,6 +191,12 @@ pgstat_init(void)
191191
*addr,
192192
hints;
193193
int ret;
194+
fd_set rset;
195+
struct timeval tv;
196+
char test_byte;
197+
int sel_res;
198+
199+
#define TESTBYTEVAL ((char) 199)
194200

195201
/*
196202
* Force start of collector daemon if something to collect
@@ -308,6 +314,85 @@ pgstat_init(void)
308314
continue;
309315
}
310316

317+
/*
318+
* Try to send and receive a one-byte test message on the socket.
319+
* This is to catch situations where the socket can be created but
320+
* will not actually pass data (for instance, because kernel packet
321+
* filtering rules prevent it).
322+
*/
323+
test_byte = TESTBYTEVAL;
324+
if (send(pgStatSock, &test_byte, 1, 0) != 1)
325+
{
326+
ereport(LOG,
327+
(errcode_for_socket_access(),
328+
errmsg("could not send test message on socket for statistics collector: %m")));
329+
closesocket(pgStatSock);
330+
pgStatSock = -1;
331+
continue;
332+
}
333+
334+
/*
335+
* There could possibly be a little delay before the message can be
336+
* received. We arbitrarily allow up to half a second before deciding
337+
* it's broken.
338+
*/
339+
for (;;) /* need a loop to handle EINTR */
340+
{
341+
FD_ZERO(&rset);
342+
FD_SET(pgStatSock, &rset);
343+
tv.tv_sec = 0;
344+
tv.tv_usec = 500000;
345+
sel_res = select(pgStatSock+1, &rset, NULL, NULL, &tv);
346+
if (sel_res >= 0 || errno != EINTR)
347+
break;
348+
}
349+
if (sel_res < 0)
350+
{
351+
ereport(LOG,
352+
(errcode_for_socket_access(),
353+
errmsg("select() failed in statistics collector: %m")));
354+
closesocket(pgStatSock);
355+
pgStatSock = -1;
356+
continue;
357+
}
358+
if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset))
359+
{
360+
/*
361+
* This is the case we actually think is likely, so take pains to
362+
* give a specific message for it.
363+
*
364+
* errno will not be set meaningfully here, so don't use it.
365+
*/
366+
ereport(LOG,
367+
(ERRCODE_CONNECTION_FAILURE,
368+
errmsg("test message did not get through on socket for statistics collector")));
369+
closesocket(pgStatSock);
370+
pgStatSock = -1;
371+
continue;
372+
}
373+
374+
test_byte++; /* just make sure variable is changed */
375+
376+
if (recv(pgStatSock, &test_byte, 1, 0) != 1)
377+
{
378+
ereport(LOG,
379+
(errcode_for_socket_access(),
380+
errmsg("could not receive test message on socket for statistics collector: %m")));
381+
closesocket(pgStatSock);
382+
pgStatSock = -1;
383+
continue;
384+
}
385+
386+
if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */
387+
{
388+
ereport(LOG,
389+
(ERRCODE_INTERNAL_ERROR,
390+
errmsg("incorrect test message transmission on socket for statistics collector")));
391+
closesocket(pgStatSock);
392+
pgStatSock = -1;
393+
continue;
394+
}
395+
311396
/* If we get here, we have a working socket */
312397
break;
313398
}

0 commit comments

Comments
 (0)