|
13 | 13 | *
|
14 | 14 | * Copyright (c) 2001-2003, PostgreSQL Global Development Group
|
15 | 15 | *
|
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 $ |
17 | 17 | * ----------
|
18 | 18 | */
|
19 | 19 | #include "postgres.h"
|
@@ -191,6 +191,12 @@ pgstat_init(void)
|
191 | 191 | *addr,
|
192 | 192 | hints;
|
193 | 193 | int ret;
|
| 194 | + fd_set rset; |
| 195 | + struct timeval tv; |
| 196 | + char test_byte; |
| 197 | + int sel_res; |
| 198 | + |
| 199 | +#define TESTBYTEVAL ((char) 199) |
194 | 200 |
|
195 | 201 | /*
|
196 | 202 | * Force start of collector daemon if something to collect
|
@@ -308,6 +314,85 @@ pgstat_init(void)
|
308 | 314 | continue;
|
309 | 315 | }
|
310 | 316 |
|
| 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 | + |
311 | 396 | /* If we get here, we have a working socket */
|
312 | 397 | break;
|
313 | 398 | }
|
|
0 commit comments