Implement comma separated multiple pcp listen addresses.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Sat, 5 Mar 2022 02:59:08 +0000 (11:59 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Sat, 5 Mar 2022 02:59:08 +0000 (11:59 +0900)
Pgpool-II only allowed to set single hostname, IP or '*' in
pcp_listen_addresses parameter. Now we can set multiple listen
addresses to the parameter like listen_addresses.  Note that the
documentations for pcp_listen_addresses are shamelessly stolen from
PostgreSQL.

Discussion: https://www.pgpool.net/pipermail/pgpool-hackers/2022-February/004131.html

doc.ja/src/sgml/connection-settings.sgml
doc/src/sgml/connection-settings.sgml
src/config/pool_config_variables.c
src/include/pool.h
src/include/pool_config.h
src/main/pgpool_main.c
src/pcp_con/pcp_child.c
src/utils/pool_process_reporting.c

index 504c54f235f923d5f819fa1bf2c8b54b969f700d..53b7dbbd2ffb80c106f53a24385f796c0cf6d9b6 100644 (file)
     <listitem>
      <para>
       <!--
-      Specifies the hostname or IP address, on which PCP process
-      will accept TCP/IP connections. <literal>*</literal>
-      accepts all incoming connections. <literal>''</literal>
-      disables TCP/IP connections. Default
-      is <literal>localhost</literal>. Connections via UNIX domain
-      socket are always accepted.
-      -->
-      PCPプロセスがTCP/IP接続を受け付けるホスト名またはIPアドレスを指定します。
-      <literal>*</literal>を指定すると入ってくる全ての接続を受け付けます。
-      <literal>''</literal>を指定するとTCP/IP接続を受け付けません。
-      デフォルト値は<literal>localhost</literal>です。
-      UNIXドメインソケット経由のコネクションは常に受け付けます。
+      Specifies the TCP/IP address(es) on which the pcp server is
+      to listen for connections from client applications.
+      The value takes the form of a comma-separated list of host names
+      and/or numeric IP addresses.  The special entry <literal>*</literal>
+      corresponds to all available IP interfaces.  The entry
+      <literal>0.0.0.0</literal> allows listening for all IPv4 addresses and
+      <literal>::</literal> allows listening for all IPv6 addresses.
+      If the list is empty, the server does not listen on any IP interface
+      at all, in which case only Unix-domain sockets can be used to connect
+      to it.
+      The default value
+      is <systemitem class="systemname">localhost</systemitem>, which
+      allows only local TCP/IP <quote>loopback</quote> connections to
+      be made.  While client authentication
+      (<xref linkend="auth-pool-hba-conf">) allows fine-grained
+      control over who can access the
+      server, <varname>pcp_listen_addresses</varname> controls which
+      interfaces accept connection attempts, which can help prevent
+      repeated malicious connection requests on insecure network
+      interfaces.  This parameter can only be set at server start.
+      -->
+      クライアントアプリケーションからの接続をPCPサーバが監視する TCP/IP アドレスを指定します。
+      この値は、ホスト名をコンマで区切ったリスト、そして/もしくは、数値によるIPアドレスです。
+      <literal>*</literal>という特別なエントリは利用可能な全てのIPインタフェースに対応します。
+      エントリ<literal>0.0.0.0</literal>は全てのIPv4アドレスの監視を、そしてエントリ<literal>::</literal>は全てのIPv6アドレスの監視を許容します。
+      リストが空の場合、サーバはいかなるIPインタフェースも全く監視しないで、Unixドメインソケットのみを使用して接続が行われます。
+      デフォルトの値は<systemitem class="systemname">localhost</systemitem>で、ローカルなTCP/IP <quote>loopback</quote>接続のみ許可します。
+      クライアント認証(<xref linkend="auth-pool-hba-conf">)は誰がサーバにアクセス可能かをきめ細かく制御するのに対し、<varname>pcp_listen_addresses</varname>はどのインタフェースが接続を試みるかを制御します。
+      これにより、安全でないネットワークインタフェース上において繰り返して行われる悪意のある接続要求の防止に役立ちます。
      </para>
      <para>
       <!--
index 1a767b17b498c6da905902d51664f1d3258ba961..41c4b631cee237b3ba209b1db6cf0c86de4505c1 100644 (file)
     </term>
     <listitem>
      <para>
-      Specifies the hostname or IP address, on which pcp process
-      will accept TCP/IP connections. <literal>*</literal>
-      accepts all incoming connections. <literal>"" </literal>
-      disables TCP/IP connections. Default
-      is <literal>localhost</literal>. Connections via UNIX domain
-      socket are always accepted.
-     </para>
-     <para>
-      This parameter can only be set at server start.
+      Specifies the TCP/IP address(es) on which the pcp server is
+      to listen for connections from client applications.
+      The value takes the form of a comma-separated list of host names
+      and/or numeric IP addresses.  The special entry <literal>*</literal>
+      corresponds to all available IP interfaces.  The entry
+      <literal>0.0.0.0</literal> allows listening for all IPv4 addresses and
+      <literal>::</literal> allows listening for all IPv6 addresses.
+      If the list is empty, the server does not listen on any IP interface
+      at all, in which case only Unix-domain sockets can be used to connect
+      to it.
+      The default value
+      is <systemitem class="systemname">localhost</systemitem>, which
+      allows only local TCP/IP <quote>loopback</quote> connections to
+      be made.  While client authentication
+      (<xref linkend="auth-pool-hba-conf">) allows fine-grained
+      control over who can access the
+      server, <varname>pcp_listen_addresses</varname> controls which
+      interfaces accept connection attempts, which can help prevent
+      repeated malicious connection requests on insecure network
+      interfaces.  This parameter can only be set at server start.
      </para>
     </listitem>
    </varlistentry>
index 7bed727a45bc19bbc31d17acd43baa258635ea15..a138e382ecaff70983839ddcb79a320be4805653 100644 (file)
@@ -50,6 +50,7 @@
 
 #define default_reset_query_list       "ABORT;DISCARD ALL"
 #define default_listen_addresses_list  "localhost"
+#define default_pcp_listen_addresses_list      "localhost"
 #define default_read_only_function_list ""
 #define default_write_function_list ""
 
@@ -812,16 +813,6 @@ static struct config_string ConfigureNamesString[] =
                MakeDMLAdaptiveObjectRelationList, NULL
        },
 
-       {
-               {"pcp_listen_addresses", CFGCXT_INIT, CONNECTION_CONFIG,
-                       "hostname(s) or IP address(es) on which pcp will listen on.",
-                       CONFIG_VAR_TYPE_STRING, false, 0
-               },
-               &g_pool_config.pcp_listen_addresses,
-               "localhost",
-               NULL, NULL, NULL, NULL
-       },
-
        {
                {"socket_dir", CFGCXT_INIT, CONNECTION_CONFIG,
                        "The directory to create the UNIX domain socket for accepting pgpool-II client connections.",
@@ -1338,6 +1329,19 @@ static struct config_string_list ConfigureNamesStringList[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"pcp_listen_addresses", CFGCXT_INIT, CONNECTION_CONFIG,
+                       "hostname(s) or IP address(es) on which pcp will listen on.",
+                       CONFIG_VAR_TYPE_STRING_LIST, false, 0
+               },
+               &g_pool_config.pcp_listen_addresses,
+               &g_pool_config.num_pcp_listen_addresses,
+               (const char *) default_pcp_listen_addresses_list,
+               ",",
+               false,
+               NULL, NULL, NULL
+       },
+
        {
                {"read_only_function_list", CFGCXT_RELOAD, CONNECTION_POOL_CONFIG,
                        "list of functions that does not writes to database.",
index 940ba399ec67ff5c12218354ccbd8ca397d2c675..1a892fc613e960959344d5236b1d6b39a07b5a6f 100644 (file)
@@ -4,7 +4,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2020     PgPool Global Development Group
+ * Copyright (c) 2003-2022     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -603,7 +603,7 @@ extern char *get_pool_key(void);
 
 
 /*pcp_child.c*/
-extern void pcp_main(int unix_fd, int inet_fd);
+extern void pcp_main(int *fds);
 
 
 
index dada252a04bcf0e3258bc3a0ec41919dc4ea46a4..32f841b6fbe193009f03621873abe8d19c41ecfb 100644 (file)
@@ -205,7 +205,7 @@ typedef struct
        ClusteringModes backend_clustering_mode;        /* Backend clustering mode */
        char       **listen_addresses;  /* hostnames/IP addresses to listen on */
        int                     port;                   /* port # to bind */
-       char       *pcp_listen_addresses;       /* PCP listen address to listen on */
+       char       **pcp_listen_addresses;      /* PCP listen address to listen on */
        int                     pcp_port;               /* PCP port # to bind */
        char       *socket_dir;         /* pgpool socket directory */
        char       *wd_ipc_socket_dir;  /* watchdog command IPC socket directory */
@@ -392,6 +392,7 @@ typedef struct
        /* followings till syslog, does not exist in the configuration file */
        int                     num_reset_queries;      /* number of queries in reset_query_list */
        int                     num_listen_addresses;   /* number of entries in listen_addresses */
+       int                     num_pcp_listen_addresses;       /* number of entries in pcp_listen_addresses */
        int                     num_read_only_function_list;    /* number of functions in
                                                                                         * read_only_function_list */
        int                     num_write_function_list;        /* number of functions in
index 078b108c7d902188dfce991b3282609e58721d79..a3c6a4d33b17b8e8f0fc9af2ac5772dacd5f5efb 100644 (file)
@@ -142,11 +142,10 @@ typedef struct
 static void signal_user1_to_parent_with_reason(User1SignalReason reason);
 
 static void FileUnlink(int code, Datum path);
-static pid_t pcp_fork_a_child(int unix_fd, int inet_fd, char *pcp_conf_file);
+static pid_t pcp_fork_a_child(int *fds, char *pcp_conf_file);
 static pid_t fork_a_child(int *fds, int id);
 static pid_t worker_fork_a_child(ProcessType type, void (*func) (), void *params);
 static int     create_unix_domain_socket(struct sockaddr_un un_addr_tmp);
-static int     create_inet_domain_socket(const char *hostname, const int port);
 static int *create_inet_domain_sockets(const char *hostname, const int port);
 static int *create_inet_domain_sockets_by_list(char **listen_addresses, int n_listen_addresses, int port, int *n_sockets);
 static void failover(void);
@@ -218,8 +217,9 @@ ConnectionInfo *con_info;
 static int *fds = NULL;                                /* listening file descriptors (UNIX socket,
                                                                 * inet domain sockets) */
 
-static int     pcp_unix_fd;            /* unix domain socket fd for PCP (not used) */
-static int     pcp_inet_fd;            /* inet domain socket fd for PCP */
+static int *pcp_fds = NULL;            /* listening file descriptors for pcp (UNIX socket,
+                                                                * inet domain sockets) */
+
 extern char *pcp_conf_file;            /* path for pcp.conf */
 extern char *conf_file;
 extern char *hba_file;
@@ -272,6 +272,7 @@ PgpoolMain(bool discard_status, bool clear_memcache_oidmaps)
 {
        int                     num_fds = 0;
        int                     *inet_fds;
+       int                     *pcp_inet_fds;
        int                     i;
 
        sigjmp_buf      local_sigjmp_buf;
@@ -457,16 +458,29 @@ PgpoolMain(bool discard_status, bool clear_memcache_oidmaps)
                Req_info->primary_node_id = find_primary_node_repeatedly();
        }
 
-       /* fork a child for PCP handling */
-       pcp_unix_fd = create_unix_domain_socket(pcp_un_addr);
-       /* Add onproc exit to clean up the unix domain socket at exit */
+       /* create pcp unix domain socket */
+       num_fds = 0;
+       pcp_fds = malloc(sizeof(int) * (num_fds + 2));
+       if (pcp_fds == NULL)
+               ereport(FATAL,
+                               (errmsg("failed to allocate memory in startup process")));
+
+       pcp_fds[0] = create_unix_domain_socket(pcp_un_addr);
+       fds[1] = -1;
        on_proc_exit(FileUnlink, (Datum) pcp_un_addr.sun_path);
 
-       if (pool_config->pcp_listen_addresses[0])
+       /* create inet domain socket if any */
+       pcp_inet_fds = create_inet_domain_sockets_by_list(pool_config->pcp_listen_addresses, pool_config->num_pcp_listen_addresses,
+                                                                                                         pool_config->pcp_port, &num_fds);
+
+       if (num_fds > 0)
        {
-               pcp_inet_fd = create_inet_domain_socket(pool_config->pcp_listen_addresses, pool_config->pcp_port);
+               memcpy(&pcp_fds[1], pcp_inet_fds, sizeof(int) * num_fds);
+               pcp_fds[num_fds + 1] = -1;
+               free(pcp_inet_fds);
        }
-       pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
+
+       pcp_pid = pcp_fork_a_child(pcp_fds, pcp_conf_file);
 
        /* Fork worker process */
        worker_pid = worker_fork_a_child(PT_WORKER, do_worker_child, NULL);
@@ -643,7 +657,7 @@ signal_user1_to_parent_with_reason(User1SignalReason reason)
  * fork a child for PCP
  */
 static pid_t
-pcp_fork_a_child(int unix_fd, int inet_fd, char *pcp_conf_file)
+pcp_fork_a_child(int *fds, char *pcp_conf_file)
 {
        pid_t           pid;
 
@@ -661,7 +675,7 @@ pcp_fork_a_child(int unix_fd, int inet_fd, char *pcp_conf_file)
                POOL_SETMASK(&UnBlockSig);
                health_check_timer_expired = 0;
                reload_config_request = 0;
-               pcp_main(unix_fd, inet_fd);
+               pcp_main(fds);
        }
        else if (pid == -1)
        {
@@ -925,94 +939,6 @@ create_inet_domain_sockets(const char *hostname, const int port)
        return sockfds;
 }
 
-/*
-* create inet domain socket
-*/
-static int
-create_inet_domain_socket(const char *hostname, const int port)
-{
-       struct sockaddr_in addr;
-       int                     fd;
-       int                     status;
-       int                     one = 1;
-       int                     len;
-       int                     backlog;
-
-       fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (fd == -1)
-       {
-               ereport(FATAL,
-                               (errmsg("failed to create INET domain socket"),
-                                errdetail("%m")));
-       }
-       if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
-                                       sizeof(one))) == -1)
-       {
-               ereport(FATAL,
-                               (errmsg("failed to create INET domain socket"),
-                                errdetail("%m")));
-       }
-
-       memset((char *) &addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-
-       if (strcmp(hostname, "*") == 0)
-       {
-               addr.sin_addr.s_addr = htonl(INADDR_ANY);
-       }
-       else
-       {
-               struct hostent *hostinfo;
-
-               hostinfo = gethostbyname(hostname);
-               if (!hostinfo)
-               {
-                       ereport(FATAL,
-                                       (errmsg("failed to create INET domain socket"),
-                                        errdetail("could not resolve hostname \"%s\": error \"%s\"", hostname, hstrerror(h_errno))));
-
-               }
-               addr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
-       }
-
-       addr.sin_port = htons(port);
-       len = sizeof(struct sockaddr_in);
-
-       status = bind(fd, (struct sockaddr *) &addr, len);
-       if (status == -1)
-       {
-               int                     saved_errno = errno;
-               char            host[NI_MAXHOST],
-                                       servname[NI_MAXSERV];
-
-               if ((status = getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host), servname, sizeof(servname), 0)))
-               {
-                       ereport(NOTICE,
-                                       (errmsg("getnameinfo failed while creating INET domain socket"),
-                                        errdetail("getnameinfo failed with reason: \"%s\"", gai_strerror(status))));
-
-                       snprintf(servname, sizeof(servname), "%d", port);
-                       snprintf(host, sizeof(host), "%s", hostname);
-               }
-               ereport(FATAL,
-                               (errmsg("failed to create INET domain socket"),
-                                errdetail("bind on host:\"%s\" server:\"%s\" failed with error \"%s\"", host, servname, strerror(saved_errno))));
-       }
-
-       backlog = pool_config->num_init_children * pool_config->listen_backlog_multiplier;
-
-       if (backlog > PGPOOLMAXLITSENQUEUELENGTH)
-               backlog = PGPOOLMAXLITSENQUEUELENGTH;
-
-       status = listen(fd, backlog);
-       if (status < 0)
-               ereport(FATAL,
-                               (errmsg("failed to create INET domain socket"),
-                                errdetail("listen on socket failed with error \"%m\"")));
-
-       return fd;
-}
-
 /*
 * create UNIX domain socket
 */
@@ -1791,7 +1717,7 @@ reaper(void)
                        found = true;
                        if (restart_child)
                        {
-                               pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
+                               pcp_pid = pcp_fork_a_child(pcp_fds, pcp_conf_file);
                                new_pid = pcp_pid;
                        }
                        else
@@ -4623,7 +4549,7 @@ exec_notice_pcp_child(FAILOVER_CONTEXT *failover_context)
                        ereport(LOG,
                                        (errmsg("PCP child %d exits with status %d in failover()", pcp_pid, status)));
 
-               pcp_pid = pcp_fork_a_child(pcp_unix_fd, pcp_inet_fd, pcp_conf_file);
+               pcp_pid = pcp_fork_a_child(pcp_fds, pcp_conf_file);
                ereport(LOG,
                                (errmsg("fork a new PCP child pid %d in failover()", pcp_pid)));
        }
index 0103360fc40e7ce117833376c1c648e1c823d116..1b81f703019f1a1fd0d0938fa748167387b8050c 100644 (file)
@@ -5,7 +5,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2021     PgPool Global Development Group
+ * Copyright (c) 2003-2022     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -81,8 +81,8 @@ static RETSIGTYPE reload_config_handler(int sig);
 static RETSIGTYPE restart_handler(int sig);
 static RETSIGTYPE reap_handler(int sig);
 
-static int     pcp_do_accept(int unix_fd, int inet_fd);
-static void start_pcp_command_processor_process(int port);
+static int     pcp_do_accept(int *fds);
+static void start_pcp_command_processor_process(int port, int *fds);
 static void pcp_child_will_die(int code, Datum arg);
 static void pcp_kill_all_children(int sig);
 static void reaper(void);
@@ -106,7 +106,7 @@ static void reaper(void);
  * main entry point for pcp child process
  */
 void
-pcp_main(int unix_fd, int inet_fd)
+pcp_main(int *fds)
 {
        sigjmp_buf      local_sigjmp_buf;
        struct timeval uptime;
@@ -115,8 +115,6 @@ pcp_main(int unix_fd, int inet_fd)
        init_ps_display("", "", "", "");
 
        gettimeofday(&uptime, NULL);
-       pcp_unix_fd = unix_fd;
-       pcp_inet_fd = inet_fd;
 
        pcp_recovery_in_progress = pool_shared_memory_create(sizeof(bool));
        *pcp_recovery_in_progress = false;
@@ -168,34 +166,44 @@ pcp_main(int unix_fd, int inet_fd)
                errno = 0;
                CHECK_RESTART_REQUEST;
 
-               port = pcp_do_accept(unix_fd, inet_fd);
+               port = pcp_do_accept(fds);
                if (port > 0)
                {
-                       start_pcp_command_processor_process(port);
+                       start_pcp_command_processor_process(port, fds);
                }
        }
 }
 
+/*
+ * Accept connection to pcp port
+ */
 static int
-pcp_do_accept(int unix_fd, int inet_fd)
+pcp_do_accept(int *fds)
 {
        fd_set          readmask;
-       int                     fds;
-       struct sockaddr addr;
-       socklen_t       addrlen;
+       fd_set          rmask;
+       int                     rfds;
        int                     fd = 0;
        int                     afd;
-       int inet = 0;
+       int                     *walk;
+       int                     nsocks = 0;
+       SockAddr        saddr;
 
        set_ps_display("PCP: wait for connection request", false);
 
+       for (walk = fds; *walk != -1; walk++)
+       {
+               if (*walk > nsocks)
+                       nsocks = *walk;
+       }
+       nsocks++;
        FD_ZERO(&readmask);
-       FD_SET(unix_fd, &readmask);
-       if (inet_fd)
-               FD_SET(inet_fd, &readmask);
+       for (walk = fds; *walk != -1; walk++)
+               FD_SET(*walk, &readmask);
 
-       fds = select(Max(unix_fd, inet_fd) + 1, &readmask, NULL, NULL, NULL);
-       if (fds == -1)
+       memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
+       rfds = select(nsocks, &rmask, NULL, NULL, NULL);
+       if (rfds == -1)
        {
                if (errno == EAGAIN || errno == EINTR)
                        return -1;
@@ -203,19 +211,19 @@ pcp_do_accept(int unix_fd, int inet_fd)
                                (errmsg("unable to accept new pcp connection"),
                                 errdetail("select system call failed with error : \"%m\"")));
        }
-       if (FD_ISSET(unix_fd, &readmask))
+       for (walk = fds; *walk != -1; walk++)
        {
-               fd = unix_fd;
-       }
-       if (FD_ISSET(inet_fd, &readmask))
-       {
-               fd = inet_fd;
-               inet      ++;
+               if (FD_ISSET(*walk, &rmask))
+               {
+                       fd = *walk;
+                       break;
+               }
        }
 
-       addrlen = sizeof(addr);
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.salen = sizeof(saddr.addr);
 
-       afd = accept(fd, &addr, &addrlen);
+       afd = accept(fd, (struct sockaddr *) &saddr.addr, &saddr.salen);
        if (afd < 0)
        {
                /*
@@ -237,29 +245,27 @@ pcp_do_accept(int unix_fd, int inet_fd)
        }
        ereport(DEBUG2,
                        (errmsg("I am PCP child with PID:%d and accept fd:%d", getpid(), afd)));
-       if (inet)
+
+       /*
+        * Set no delay if AF_INET socket. Not sure if this is really necessary
+        * but PostgreSQL does this.
+        */
+       if (!FD_ISSET(fds[0], &rmask))  /* fds[0] is UNIX domain socket */
        {
-               int                     on = 1;
+               int     on;
 
+               on = 1;
                if (setsockopt(afd, IPPROTO_TCP, TCP_NODELAY,
                                           (char *) &on,
                                           sizeof(on)) < 0)
                {
+                       ereport(WARNING,
+                                       (errmsg("wait_for_new_connections: setsockopt failed with error \"%m\"")));
                        close(afd);
-                       ereport(ERROR,
-                                       (errmsg("unable to accept new pcp connection"),
-                                        errdetail("setsockopt system call failed with error : \"%m\"")));
-               }
-               if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE,
-                                          (char *) &on,
-                                          sizeof(on)) < 0)
-               {
-                       close(afd);
-                       ereport(ERROR,
-                                       (errmsg("unable to accept new pcp connection"),
-                                        errdetail("setsockopt system call failed with error : \"%m\"")));
+                       return -1;
                }
        }
+
        return afd;
 }
 
@@ -267,18 +273,21 @@ pcp_do_accept(int unix_fd, int inet_fd)
  * forks a new pcp worker child
  */
 static void
-start_pcp_command_processor_process(int port)
+start_pcp_command_processor_process(int port, int *fds)
 {
        pid_t           pid = fork();
+       int                     *walk;
 
        if (pid == 0)                           /* child */
        {
                SetProcessGlobalVariables(PT_PCP_WORKER);
 
                on_exit_reset();
+
                /* Close the listen sockets sockets */
-               close(pcp_unix_fd);
-               close(pcp_inet_fd);
+               for (walk = fds; *walk != -1; walk++)
+                       close(*walk);
+
                /* call PCP child main */
                if (pcp_worker_children)
                        list_free(pcp_worker_children);
index 825e4847aa95336d70d43b25c056ecd378a0052e..5f2e40c3041184c5ed6ab6ef6ecd5a0b63295d3e 100644 (file)
@@ -215,10 +215,19 @@ get_config(int *nrows)
        i++;
 
        StrNCpy(status[i].name, "pcp_listen_addresses", POOLCONFIG_MAXNAMELEN);
-       snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_listen_addresses);
+       *(status[i].value) = '\0';
+       for (j = 0; j < pool_config->num_pcp_listen_addresses; j++)
+       {
+               len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
+               strncat(status[i].value, pool_config->pcp_listen_addresses[j], len);
+               len = POOLCONFIG_MAXVALLEN - strlen(status[i].value);
+               if (j != pool_config->num_pcp_listen_addresses - 1)
+                       strncat(status[i].value, ",", len);
+       }
        StrNCpy(status[i].desc, "host name(s) or IP address(es) for pcp process to listen on", POOLCONFIG_MAXDESCLEN);
        i++;
 
+
        StrNCpy(status[i].name, "pcp_port", POOLCONFIG_MAXNAMELEN);
        snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->pcp_port);
        StrNCpy(status[i].desc, "PCP port # to bind", POOLCONFIG_MAXDESCLEN);