Re: libpq should not look up all host addresses at once - Mailing list pgsql-hackers

From Tom Lane
Subject Re: libpq should not look up all host addresses at once
Date
Msg-id 27728.1534189594@sss.pgh.pa.us
Whole thread Raw
In response to Re: libpq should not look up all host addresses at once  (Fabien COELHO <coelho@cri.ensmp.fr>)
Responses Re: libpq should not look up all host addresses at once
List pgsql-hackers
Fabien COELHO <coelho@cri.ensmp.fr> writes:
> Patch compiles, global "make check" ok, although I'm unsure whether the
> feature is actually tested somewhere. I think not:-(

Yeah, it's hard to test this stuff without either opening up security
hazards or making unwarranted assumptions about the local network setup.
I think that the standard regression tests only use Unix-socket
communication (except on Windows) for exactly that reason, and that makes
it hard to do anything much about regression-testing this feature.

> As you noted in another message, a small doc update should be needed.

Check.  Proposed doc patch attached.  (Only the last hunk is actually
specific to this patch, the rest is cleanup that I noticed while looking
around for possibly-relevant text.)

> I'd consider wrapping some of the logic. I'd check the port first, then 
> move the host resolution stuff into a function.

Don't really see the value of either ...

            regards, tom lane

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 80e55f5..7c150f3 100644
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
*************** PostgresPollingStatusType PQconnectPoll(
*** 303,311 ****
         <itemizedlist>
          <listitem>
           <para>
!           The <literal>hostaddr</literal> and <literal>host</literal> parameters are used appropriately to ensure
that
!           name and reverse name queries are not made. See the documentation of
!           these parameters in <xref linkend="libpq-paramkeywords"/> for details.
           </para>
          </listitem>

--- 303,311 ----
         <itemizedlist>
          <listitem>
           <para>
!           The <literal>hostaddr</literal> parameter must be used appropriately
!           to prevent DNS queries from being made.  See the documentation of
!           this parameter in <xref linkend="libpq-paramkeywords"/> for details.
           </para>
          </listitem>

*************** PostgresPollingStatusType PQconnectPoll(
*** 318,324 ****

          <listitem>
           <para>
!           You ensure that the socket is in the appropriate state
            before calling <function>PQconnectPoll</function>, as described below.
           </para>
          </listitem>
--- 318,324 ----

          <listitem>
           <para>
!           You must ensure that the socket is in the appropriate state
            before calling <function>PQconnectPoll</function>, as described below.
           </para>
          </listitem>
*************** PostgresPollingStatusType PQconnectPoll(
*** 326,349 ****
        </para>

        <para>
!        Note: use of <function>PQconnectStartParams</function> is analogous to
!        <function>PQconnectStart</function> shown below.
!       </para>
!
!       <para>
!        To begin a nonblocking connection request, call <literal>conn =
PQconnectStart("<replaceable>connection_info_string</replaceable>")</literal>.
!        If <varname>conn</varname> is null, then <application>libpq</application> has been unable to allocate a new
<structname>PGconn</structname>
!        structure. Otherwise, a valid <structname>PGconn</structname> pointer is returned (though not yet
!        representing a valid connection to the database). On return from
!        <function>PQconnectStart</function>, call <literal>status = PQstatus(conn)</literal>. If
<varname>status</varname>equals 
!        <symbol>CONNECTION_BAD</symbol>, <function>PQconnectStart</function> has failed.
        </para>

        <para>
!        If <function>PQconnectStart</function> succeeds, the next stage is to poll
!        <application>libpq</application> so that it can proceed with the connection sequence.
         Use <function>PQsocket(conn)</function> to obtain the descriptor of the
         socket underlying the database connection.
         Loop thus: If <function>PQconnectPoll(conn)</function> last returned
         <symbol>PGRES_POLLING_READING</symbol>, wait until the socket is ready to
         read (as indicated by <function>select()</function>, <function>poll()</function>, or
--- 326,352 ----
        </para>

        <para>
!        To begin a nonblocking connection request,
!        call <function>PQconnectStart</function>
!        or <function>PQconnectStartParams</function>.  If the result is null,
!        then <application>libpq</application> has been unable to allocate a
!        new <structname>PGconn</structname> structure.  Otherwise, a
!        valid <structname>PGconn</structname> pointer is returned (though not
!        yet representing a valid connection to the database).  Next
!        call <literal>PQstatus(conn)</literal>.  If the result
!        is <symbol>CONNECTION_BAD</symbol>, the connection attempt has already
!        failed, typically because of invalid connection parameters.
        </para>

        <para>
!        If <function>PQconnectStart</function>
!        or <function>PQconnectStartParams</function> succeeds, the next stage
!        is to poll <application>libpq</application> so that it can proceed with
!        the connection sequence.
         Use <function>PQsocket(conn)</function> to obtain the descriptor of the
         socket underlying the database connection.
+        (Caution: do not assume that the socket remains the same
+        across <function>PQconnectPoll</function> calls.)
         Loop thus: If <function>PQconnectPoll(conn)</function> last returned
         <symbol>PGRES_POLLING_READING</symbol>, wait until the socket is ready to
         read (as indicated by <function>select()</function>, <function>poll()</function>, or
*************** PostgresPollingStatusType PQconnectPoll(
*** 352,360 ****
         Conversely, if <function>PQconnectPoll(conn)</function> last returned
         <symbol>PGRES_POLLING_WRITING</symbol>, wait until the socket is ready
         to write, then call <function>PQconnectPoll(conn)</function> again.
!        If you have yet to call
!        <function>PQconnectPoll</function>, i.e., just after the call to
!        <function>PQconnectStart</function>, behave as if it last returned
         <symbol>PGRES_POLLING_WRITING</symbol>.  Continue this loop until
         <function>PQconnectPoll(conn)</function> returns
         <symbol>PGRES_POLLING_FAILED</symbol>, indicating the connection procedure
--- 355,362 ----
         Conversely, if <function>PQconnectPoll(conn)</function> last returned
         <symbol>PGRES_POLLING_WRITING</symbol>, wait until the socket is ready
         to write, then call <function>PQconnectPoll(conn)</function> again.
!        On the first iteration, i.e. if you have yet to call
!        <function>PQconnectPoll</function>, behave as if it last returned
         <symbol>PGRES_POLLING_WRITING</symbol>.  Continue this loop until
         <function>PQconnectPoll(conn)</function> returns
         <symbol>PGRES_POLLING_FAILED</symbol>, indicating the connection procedure
*************** switch(PQstatus(conn))
*** 479,488 ****
        </para>

        <para>
!        Note that if <function>PQconnectStart</function> returns a non-null pointer, you must call
!        <function>PQfinish</function> when you are finished with it, in order to dispose of
!        the structure and any associated memory blocks. This must be done even if
!        the connection attempt fails or is abandoned.
        </para>
       </listitem>
      </varlistentry>
--- 481,492 ----
        </para>

        <para>
!        Note that when <function>PQconnectStart</function>
!        or <function>PQconnectStartParams</function> returns a non-null
!        pointer, you must call <function>PQfinish</function> when you are
!        finished with it, in order to dispose of the structure and any
!        associated memory blocks.  This must be done even if the connection
!        attempt fails or is abandoned.
        </para>
       </listitem>
      </varlistentry>
*************** postgresql://%2Fvar%2Flib%2Fpostgresql/d
*** 913,919 ****
         It is possible to specify multiple hosts to connect to, so that they are
         tried in the given order. In the Keyword/Value format, the <literal>host</literal>,
         <literal>hostaddr</literal>, and <literal>port</literal> options accept a comma-separated
!        list of values. The same number of elements must be given in each option, such
         that e.g. the first <literal>hostaddr</literal> corresponds to the first host name,
         the second <literal>hostaddr</literal> corresponds to the second host name, and so
         forth. As an exception, if only one <literal>port</literal> is specified, it
--- 917,924 ----
         It is possible to specify multiple hosts to connect to, so that they are
         tried in the given order. In the Keyword/Value format, the <literal>host</literal>,
         <literal>hostaddr</literal>, and <literal>port</literal> options accept a comma-separated
!        list of values. The same number of elements must be given in each
!        option that is specified, such
         that e.g. the first <literal>hostaddr</literal> corresponds to the first host name,
         the second <literal>hostaddr</literal> corresponds to the second host name, and so
         forth. As an exception, if only one <literal>port</literal> is specified, it
*************** postgresql://%2Fvar%2Flib%2Fpostgresql/d
*** 922,930 ****

       <para>
         In the connection URI format, you can list multiple <literal>host:port</literal> pairs
!        separated by commas, in the <literal>host</literal> component of the URI. In either
!        format, a single host name can also translate to multiple network addresses. A
!        common example of this is a host that has both an IPv4 and an IPv6 address.
       </para>

       <para>
--- 927,939 ----

       <para>
         In the connection URI format, you can list multiple <literal>host:port</literal> pairs
!        separated by commas, in the <literal>host</literal> component of the URI.
!      </para>
!
!      <para>
!        In either format, a single host name can translate to multiple network
!        addresses. A common example of this is a host that has both an IPv4 and
!        an IPv6 address.
       </para>

       <para>
*************** postgresql://%2Fvar%2Flib%2Fpostgresql/d
*** 958,966 ****
          Name of host to connect to.<indexterm><primary>host name</primary></indexterm>
          If a host name begins with a slash, it specifies Unix-domain
          communication rather than TCP/IP communication; the value is the
!         name of the directory in which the socket file is stored.  If
!         multiple host names are specified, each will be tried in turn in
!         the order given.  The default behavior when <literal>host</literal> is
          not specified, or is empty, is to connect to a Unix-domain
          socket<indexterm><primary>Unix domain socket</primary></indexterm> in
          <filename>/tmp</filename> (or whatever socket directory was specified
--- 967,974 ----
          Name of host to connect to.<indexterm><primary>host name</primary></indexterm>
          If a host name begins with a slash, it specifies Unix-domain
          communication rather than TCP/IP communication; the value is the
!         name of the directory in which the socket file is stored.
!         The default behavior when <literal>host</literal> is
          not specified, or is empty, is to connect to a Unix-domain
          socket<indexterm><primary>Unix domain socket</primary></indexterm> in
          <filename>/tmp</filename> (or whatever socket directory was specified
*************** postgresql://%2Fvar%2Flib%2Fpostgresql/d
*** 997,1004 ****
          <itemizedlist>
           <listitem>
            <para>
!            If <literal>host</literal> is specified without <literal>hostaddr</literal>,
!            a host name lookup occurs.
            </para>
           </listitem>
           <listitem>
--- 1005,1016 ----
          <itemizedlist>
           <listitem>
            <para>
!            If <literal>host</literal> is specified
!            without <literal>hostaddr</literal>, a host name lookup occurs.
!            (When using <function>PQconnectPoll</function>, the lookup occurs
!            when <function>PQconnectPoll</function> first considers this host
!            name, and it may cause <function>PQconnectPoll</function> to block
!            for a significant amount of time.)
            </para>
           </listitem>
           <listitem>

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: FailedAssertion on partprune
Next
From: Andrew Dunstan
Date:
Subject: Re: libpq compression