Fix watchdog receive socket creation without IPv6.
authorTatsuo Ishii <ishii@postgresql.org>
Tue, 27 May 2025 10:15:54 +0000 (19:15 +0900)
committerTatsuo Ishii <ishii@postgresql.org>
Tue, 27 May 2025 10:15:54 +0000 (19:15 +0900)
When IPv6 network is not available, it was possible that watchdog
process won't start.  Previously wd_create_recv_socket() issued
elog(ERROR) if creation or handling IPv6 socket failed. Unfortunately
at the time when wd_create_recv_socket() is called, the exception
stack is not established, and elog happily converts ERROR to FATAL,
which causes exiting watchdog process, thus exiting pgpool process.

To fix this, the elog(ERROR) calls are changed to elog(LOG).

Reported-by: Bo Peng (pengbo@sraoss.co.jp)
Discussion: https://github.com/pgpool/pgpool2/issues/99
Backpatch-through: v4.6

src/watchdog/watchdog.c

index faab4e6e5b8cd07c20226f3ed81b6cff7901740d..6937934445663f859fe46be8b1582e8784e45e44 100644 (file)
@@ -862,7 +862,6 @@ wd_create_recv_socket(int port)
 {
        int                     one = 1;
        int                     sock = -1;
-       int                     saved_errno;
        int                     gai_ret,
                                n = 0,
                                target_n = n;
@@ -909,12 +908,10 @@ wd_create_recv_socket(int port)
                if ((sock = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol)) < 0)
                {
                        /* socket create failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("create socket failed with reason: \"%m\"")));
+                       continue;
                }
 
                socket_set_nonblock(sock);
@@ -922,77 +919,72 @@ wd_create_recv_socket(int port)
                if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1)
                {
                        /* setsockopt(SO_REUSEADDR) failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       close(sock);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("setsockopt(SO_REUSEADDR) failed with reason: \"%m\"")));
+                       close(sock);
+                       continue;
                }
                if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) == -1)
                {
                        /* setsockopt(TCP_NODELAY) failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       close(sock);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("setsockopt(TCP_NODELAY) failed with reason: \"%m\"")));
+                       close(sock);
+                       continue;
                }
                if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)) == -1)
                {
                        /* setsockopt(SO_KEEPALIVE) failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       close(sock);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("setsockopt(SO_KEEPALIVE) failed with reason: \"%m\"")));
+                       close(sock);
+                       continue;
                }
                if (walk->ai_family == AF_INET6)
                {
                        if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) == -1)
                        {
-                               saved_errno = errno;
-                               freeaddrinfo(res);
-                               close(sock);
-                               errno = saved_errno;
-                               ereport(ERROR,
+                               ereport(LOG,
                                                (errmsg("failed to set IPPROTO_IPV6 option to watchdog receive socket"),
                                                 errdetail("setsockopt(IPV6_V6ONLY) failed with reason: \"%m\"")));
+                               close(sock);
+                               continue;
                        }
                }
                if (bind(sock, walk->ai_addr, walk->ai_addrlen) < 0)
                {
                        /* bind failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       close(sock);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("bind on \"TCP:%d\" failed with reason: \"%m\"", port)));
+                       close(sock);
+                       continue;
                }
 
                if (listen(sock, MAX_WATCHDOG_NUM * 2) < 0)
                {
                        /* listen failed */
-                       saved_errno = errno;
-                       freeaddrinfo(res);
-                       close(sock);
-                       errno = saved_errno;
-                       ereport(ERROR,
+                       ereport(LOG,
                                        (errmsg("failed to create watchdog receive socket"),
                                         errdetail("listen failed with reason: \"%m\"")));
+                       close(sock);
+                       continue;
                }
 
                socks = lappend_int(socks, sock);
                n++;
        }
 
+       /*
+        * Fatal error. No recevive sockets were created.
+        */
+       if (n == 0)
+               ereport(FATAL,
+                               (errmsg("failed to create any of watchdog receive sockets")));
+
        if (target_n != n)
                ereport(WARNING,
                                (errmsg("failed to create watchdog receive socket as much intended"),