Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5b6b587

Browse files
committed
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.
1 parent 472d972 commit 5b6b587

File tree

1 file changed

+64
-39
lines changed

1 file changed

+64
-39
lines changed

src/backend/postmaster/pgstat.c

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
1515
*
16-
* $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.46 2003/11/07 21:55:50 tgl Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/postmaster/pgstat.c,v 1.47 2003/11/15 17:24:07 tgl Exp $
1717
* ----------
1818
*/
1919
#include "postgres.h"
@@ -203,60 +203,83 @@ pgstat_init(void)
203203
goto startup_failed;
204204
}
205205

206+
/*
207+
* On some platforms, getaddrinfo_all() may return multiple addresses
208+
* only one of which will actually work (eg, both IPv6 and IPv4 addresses
209+
* when kernel will reject IPv6). Worse, the failure may occur at the
210+
* bind() or perhaps even connect() stage. So we must loop through the
211+
* results till we find a working combination. We will generate LOG
212+
* messages, but no error, for bogus combinations.
213+
*/
206214
for (addr = addrs; addr; addr = addr->ai_next)
207215
{
208216
#ifdef HAVE_UNIX_SOCKETS
209217
/* Ignore AF_UNIX sockets, if any are returned. */
210218
if (addr->ai_family == AF_UNIX)
211219
continue;
212220
#endif
213-
if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) >= 0)
214-
break;
215-
}
221+
/*
222+
* Create the socket.
223+
*/
224+
if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) < 0)
225+
{
226+
ereport(LOG,
227+
(errcode_for_socket_access(),
228+
errmsg("could not create socket for statistics collector: %m")));
229+
continue;
230+
}
216231

217-
if (!addr || pgStatSock < 0)
218-
{
219-
ereport(LOG,
220-
(errcode_for_socket_access(),
221-
errmsg("could not create socket for statistics collector: %m")));
222-
goto startup_failed;
223-
}
232+
/*
233+
* Bind it to a kernel assigned port on localhost and get the assigned
234+
* port via getsockname().
235+
*/
236+
if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
237+
{
238+
ereport(LOG,
239+
(errcode_for_socket_access(),
240+
errmsg("could not bind socket for statistics collector: %m")));
241+
closesocket(pgStatSock);
242+
pgStatSock = -1;
243+
continue;
244+
}
224245

225-
/*
226-
* Bind it to a kernel assigned port on localhost and get the assigned
227-
* port via getsockname().
228-
*/
229-
if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0)
230-
{
231-
ereport(LOG,
232-
(errcode_for_socket_access(),
233-
errmsg("could not bind socket for statistics collector: %m")));
234-
goto startup_failed;
235-
}
246+
alen = sizeof(pgStatAddr);
247+
if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0)
248+
{
249+
ereport(LOG,
250+
(errcode_for_socket_access(),
251+
errmsg("could not get address of socket for statistics collector: %m")));
252+
closesocket(pgStatSock);
253+
pgStatSock = -1;
254+
continue;
255+
}
236256

237-
freeaddrinfo_all(hints.ai_family, addrs);
238-
addrs = NULL;
257+
/*
258+
* Connect the socket to its own address. This saves a few cycles by
259+
* not having to respecify the target address on every send. This also
260+
* provides a kernel-level check that only packets from this same
261+
* address will be received.
262+
*/
263+
if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0)
264+
{
265+
ereport(LOG,
266+
(errcode_for_socket_access(),
267+
errmsg("could not connect socket for statistics collector: %m")));
268+
closesocket(pgStatSock);
269+
pgStatSock = -1;
270+
continue;
271+
}
239272

240-
alen = sizeof(pgStatAddr);
241-
if (getsockname(pgStatSock, (struct sockaddr *) & pgStatAddr, &alen) < 0)
242-
{
243-
ereport(LOG,
244-
(errcode_for_socket_access(),
245-
errmsg("could not get address of socket for statistics collector: %m")));
246-
goto startup_failed;
273+
/* If we get here, we have a working socket */
274+
break;
247275
}
248276

249-
/*
250-
* Connect the socket to its own address. This saves a few cycles by
251-
* not having to respecify the target address on every send. This also
252-
* provides a kernel-level check that only packets from this same
253-
* address will be received.
254-
*/
255-
if (connect(pgStatSock, (struct sockaddr *) & pgStatAddr, alen) < 0)
277+
/* Did we find a working address? */
278+
if (!addr || pgStatSock < 0)
256279
{
257280
ereport(LOG,
258281
(errcode_for_socket_access(),
259-
errmsg("could not connect socket for statistics collector: %m")));
282+
errmsg("disabling statistics collector for lack of working socket")));
260283
goto startup_failed;
261284
}
262285

@@ -285,6 +308,8 @@ pgstat_init(void)
285308
goto startup_failed;
286309
}
287310

311+
freeaddrinfo_all(hints.ai_family, addrs);
312+
288313
return;
289314

290315
startup_failed:

0 commit comments

Comments
 (0)