When reporting the server as not responding, if the hostname was
authorBruce Momjian
Wed, 24 Nov 2010 22:04:19 +0000 (17:04 -0500)
committerBruce Momjian
Wed, 24 Nov 2010 22:04:19 +0000 (17:04 -0500)
supplied, also print the IP address.  This allows IPv4 and IPv6 failures
to be distinguished.  Also useful when a hostname resolves to multiple
IP addresses.

Also, remove use of inet_ntoa() and use our own inet_net_ntop() in all
places, including in libpq, because it is thread-safe.

doc/src/sgml/libpq.sgml
src/backend/utils/adt/Makefile
src/backend/utils/adt/inet_cidr_ntop.c [moved from src/backend/utils/adt/inet_net_ntop.c with 55% similarity]
src/include/port.h
src/include/utils/builtins.h
src/interfaces/libpq/fe-connect.c
src/port/Makefile
src/port/getaddrinfo.c
src/port/inet_net_ntop.c [new file with mode: 0644]

index 5cc81bbe2690bd4bb6a4e22fb1099c5daf3981f5..c95fc4fd64d75ab54599bb8722c56537971585f1 100644 (file)
@@ -170,11 +170,11 @@ PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand
            If host is specified without hostaddr,
            a host name lookup occurs.
            If hostaddr is specified without host,
-           the value for hostaddr gives the server address.
+           the value for hostaddr gives the server network address.
            The connection attempt will fail in any of the cases where a
            host name is required.
            If both host and hostaddr are specified,
-           the value for hostaddr gives the server address.
+           the value for hostaddr gives the server network address.
            The value for host is ignored unless needed for
            authentication or verification purposes, in which case it will be
            used as the host name.  Note that authentication is likely to fail
index be272b51d97260a02e444bd48b55b60503e99c45..ce28abd9fe1e5d725c52a236c507f5fd731552d3 100644 (file)
@@ -23,7 +23,7 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
    oid.o oracle_compat.o pseudotypes.o rowtypes.o \
    regexp.o regproc.o ruleutils.o selfuncs.o \
    tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
-   network.o mac.o inet_net_ntop.o inet_net_pton.o \
+   network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
    ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
    ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o trigfuncs.o \
    tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \
similarity index 55%
rename from src/backend/utils/adt/inet_net_ntop.c
rename to src/backend/utils/adt/inet_cidr_ntop.c
index 3d7fb658897afa67fed226f43cf22e480a72fbd4..5f2a3d361d945b7bb7a2ad524e7edec706c010a2 100644 (file)
@@ -32,21 +32,14 @@ static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 m
 #include "utils/inet.h"
 
 
-#define NS_IN6ADDRSZ 16
-#define NS_INT16SZ 2
-
 #ifdef SPRINTF_CHAR
 #define SPRINTF(x) strlen(sprintf/**/x)
 #else
 #define SPRINTF(x) ((size_t)sprintf x)
 #endif
 
-static char *inet_net_ntop_ipv4(const u_char *src, int bits,
-                  char *dst, size_t size);
 static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
                    char *dst, size_t size);
-static char *inet_net_ntop_ipv6(const u_char *src, int bits,
-                  char *dst, size_t size);
 static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
                    char *dst, size_t size);
 
@@ -300,231 +293,3 @@ emsgsize:
    errno = EMSGSIZE;
    return (NULL);
 }
-
-
-/*
- * char *
- * inet_net_ntop(af, src, bits, dst, size)
- * convert host/network address from network to presentation format.
- * "src"'s size is determined from its "af".
- * return:
- * pointer to dst, or NULL if an error occurred (check errno).
- * note:
- * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
- * as called for by inet_net_pton() but it can be a host address with
- * an included netmask.
- * author:
- * Paul Vixie (ISC), October 1998
- */
-char *
-inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
-{
-   switch (af)
-   {
-       case PGSQL_AF_INET:
-           return (inet_net_ntop_ipv4(src, bits, dst, size));
-       case PGSQL_AF_INET6:
-           return (inet_net_ntop_ipv6(src, bits, dst, size));
-       default:
-           errno = EAFNOSUPPORT;
-           return (NULL);
-   }
-}
-
-/*
- * static char *
- * inet_net_ntop_ipv4(src, bits, dst, size)
- * convert IPv4 network address from network to presentation format.
- * "src"'s size is determined from its "af".
- * return:
- * pointer to dst, or NULL if an error occurred (check errno).
- * note:
- * network byte order assumed.  this means 192.5.5.240/28 has
- * 0b11110000 in its fourth octet.
- * author:
- * Paul Vixie (ISC), October 1998
- */
-static char *
-inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
-{
-   char       *odst = dst;
-   char       *t;
-   int         len = 4;
-   int         b;
-
-   if (bits < 0 || bits > 32)
-   {
-       errno = EINVAL;
-       return (NULL);
-   }
-
-   /* Always format all four octets, regardless of mask length. */
-   for (b = len; b > 0; b--)
-   {
-       if (size <= sizeof ".255")
-           goto emsgsize;
-       t = dst;
-       if (dst != odst)
-           *dst++ = '.';
-       dst += SPRINTF((dst, "%u", *src++));
-       size -= (size_t) (dst - t);
-   }
-
-   /* don't print masklen if 32 bits */
-   if (bits != 32)
-   {
-       if (size <= sizeof "/32")
-           goto emsgsize;
-       dst += SPRINTF((dst, "/%u", bits));
-   }
-
-   return (odst);
-
-emsgsize:
-   errno = EMSGSIZE;
-   return (NULL);
-}
-
-static int
-decoct(const u_char *src, int bytes, char *dst, size_t size)
-{
-   char       *odst = dst;
-   char       *t;
-   int         b;
-
-   for (b = 1; b <= bytes; b++)
-   {
-       if (size <= sizeof "255.")
-           return (0);
-       t = dst;
-       dst += SPRINTF((dst, "%u", *src++));
-       if (b != bytes)
-       {
-           *dst++ = '.';
-           *dst = '\0';
-       }
-       size -= (size_t) (dst - t);
-   }
-   return (dst - odst);
-}
-
-static char *
-inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
-{
-   /*
-    * Note that int32_t and int16_t need only be "at least" large enough to
-    * contain a value of the specified size.  On some systems, like Crays,
-    * there is no such thing as an integer variable with 16 bits. Keep this
-    * in mind if you think this function should have been coded to use
-    * pointer overlays.  All the world's not a VAX.
-    */
-   char        tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
-   char       *tp;
-   struct
-   {
-       int         base,
-                   len;
-   }           best, cur;
-   u_int       words[NS_IN6ADDRSZ / NS_INT16SZ];
-   int         i;
-
-   if ((bits < -1) || (bits > 128))
-   {
-       errno = EINVAL;
-       return (NULL);
-   }
-
-   /*
-    * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
-    * the longest run of 0x00's in src[] for :: shorthanding.
-    */
-   memset(words, '\0', sizeof words);
-   for (i = 0; i < NS_IN6ADDRSZ; i++)
-       words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
-   best.base = -1;
-   cur.base = -1;
-   best.len = 0;
-   cur.len = 0;
-   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
-   {
-       if (words[i] == 0)
-       {
-           if (cur.base == -1)
-               cur.base = i, cur.len = 1;
-           else
-               cur.len++;
-       }
-       else
-       {
-           if (cur.base != -1)
-           {
-               if (best.base == -1 || cur.len > best.len)
-                   best = cur;
-               cur.base = -1;
-           }
-       }
-   }
-   if (cur.base != -1)
-   {
-       if (best.base == -1 || cur.len > best.len)
-           best = cur;
-   }
-   if (best.base != -1 && best.len < 2)
-       best.base = -1;
-
-   /*
-    * Format the result.
-    */
-   tp = tmp;
-   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
-   {
-       /* Are we inside the best run of 0x00's? */
-       if (best.base != -1 && i >= best.base &&
-           i < (best.base + best.len))
-       {
-           if (i == best.base)
-               *tp++ = ':';
-           continue;
-       }
-       /* Are we following an initial run of 0x00s or any real hex? */
-       if (i != 0)
-           *tp++ = ':';
-       /* Is this address an encapsulated IPv4? */
-       if (i == 6 && best.base == 0 && (best.len == 6 ||
-                                    (best.len == 7 && words[7] != 0x0001) ||
-                                     (best.len == 5 && words[5] == 0xffff)))
-       {
-           int         n;
-
-           n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
-           if (n == 0)
-           {
-               errno = EMSGSIZE;
-               return (NULL);
-           }
-           tp += strlen(tp);
-           break;
-       }
-       tp += SPRINTF((tp, "%x", words[i]));
-   }
-
-   /* Was it a trailing run of 0x00's? */
-   if (best.base != -1 && (best.base + best.len) ==
-       (NS_IN6ADDRSZ / NS_INT16SZ))
-       *tp++ = ':';
-   *tp = '\0';
-
-   if (bits != -1 && bits != 128)
-       tp += SPRINTF((tp, "/%u", bits));
-
-   /*
-    * Check for overflow, copy, and we're done.
-    */
-   if ((size_t) (tp - tmp) > size)
-   {
-       errno = EMSGSIZE;
-       return (NULL);
-   }
-   strcpy(dst, tmp);
-   return (dst);
-}
index 204876888aca605fea395af71f9f99d113fbc37e..0cfbed83d45ef0f17cf00750ea8e36d9db26b566 100644 (file)
@@ -437,4 +437,8 @@ extern void qsort_arg(void *base, size_t nel, size_t elsize,
 /* port/chklocale.c */
 extern int pg_get_encoding_from_locale(const char *ctype);
 
+/* port/inet_net_ntop.c */
+extern char *inet_net_ntop(int af, const void *src, int bits,
+             char *dst, size_t size);
+
 #endif   /* PG_PORT_H */
index bad0a8ebdf26e59a02f5b824e8d31bfdb7f0100c..a2fb7494cb4cb28ec9fc21fc34762ec989778151 100644 (file)
@@ -795,9 +795,7 @@ extern Datum chr (PG_FUNCTION_ARGS);
 extern Datum repeat(PG_FUNCTION_ARGS);
 extern Datum ascii(PG_FUNCTION_ARGS);
 
-/* inet_net_ntop.c */
-extern char *inet_net_ntop(int af, const void *src, int bits,
-             char *dst, size_t size);
+/* inet_cidr_ntop.c */
 extern char *inet_cidr_ntop(int af, const void *src, int bits,
               char *dst, size_t size);
 
index 8f318a1a8cc5bf2d49b2605dd76581609cf9be32..8011604e5cd1ad92cd2e0cca5f1980a813a318cd 100644 (file)
@@ -960,9 +960,28 @@ connectFailureMessage(PGconn *conn, int errorno)
    else
 #endif   /* HAVE_UNIX_SOCKETS */
    {
+       char    host_addr[NI_MAXHOST];
+       bool    display_host_addr;
+       struct sockaddr_in *host_addr_struct = (struct sockaddr_in *)
+                                               &conn->raddr.addr;
+
+       /*
+        *  Optionally display the network address with the hostname.
+        *  This is useful to distinguish between IPv4 and IPv6 connections.
+        */
+       if (conn->pghostaddr != NULL)
+           strlcpy(host_addr, conn->pghostaddr, NI_MAXHOST);
+       else if (inet_net_ntop(conn->addr_cur->ai_family, &host_addr_struct->sin_addr,
+                host_addr_struct->sin_family == AF_INET ? 32 : 128,
+                host_addr, sizeof(host_addr)) == NULL)
+           strcpy(host_addr, "???");
+
+       display_host_addr = !conn->pghostaddr &&
+                           strcmp(conn->pghost, host_addr) != 0;
+       
        appendPQExpBuffer(&conn->errorMessage,
                          libpq_gettext("could not connect to server: %s\n"
-                    "\tIs the server running on host \"%s\" and accepting\n"
+                    "\tIs the server running on host \"%s\" %s%s%sand accepting\n"
                                        "\tTCP/IP connections on port %s?\n"),
                          SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
                          conn->pghostaddr
@@ -970,6 +989,10 @@ connectFailureMessage(PGconn *conn, int errorno)
                          : (conn->pghost
                             ? conn->pghost
                             : "???"),
+                         /* display the IP address only if not already output */
+                         display_host_addr ? "(" : "",
+                         display_host_addr ? host_addr : "",
+                         display_host_addr ? ") " : "",
                          conn->pgport);
    }
 }
index 327ec7246c296ae80d75e538c28ec44ce611ec8e..711f63308925e9f036afc1b25035816dad4bd93c 100644 (file)
@@ -30,7 +30,7 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)
 
-OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o noblock.o path.o \
+OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o path.o \
    pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
 ifneq (,$(filter $(PORTNAME),cygwin win32))
 OBJS += pipe.o
index f867744eee27c087a1b8ad3ac676e61739c1b78a..807f5bd56d7e7e05136f22e2960ec5a5706176cf 100644 (file)
@@ -388,16 +388,14 @@ getnameinfo(const struct sockaddr * sa, int salen,
 
    if (node)
    {
-       int         ret = -1;
-
        if (sa->sa_family == AF_INET)
        {
-           char       *p;
-
-           p = inet_ntoa(((struct sockaddr_in *) sa)->sin_addr);
-           ret = snprintf(node, nodelen, "%s", p);
+           if (inet_net_ntop(AF_INET, ((struct sockaddr_in *) sa)->sin_addr,
+               sa->sa_family == AF_INET ? 32 : 128,
+               node, nodelen) == NULL)
+           return EAI_MEMORY;
        }
-       if (ret == -1 || ret > nodelen)
+       else
            return EAI_MEMORY;
    }
 
diff --git a/src/port/inet_net_ntop.c b/src/port/inet_net_ntop.c
new file mode 100644 (file)
index 0000000..02d3a7c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *   src/backend/utils/adt/inet_net_ntop.c
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
+#endif
+
+#include "postgres.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "utils/inet.h"
+
+
+#define NS_IN6ADDRSZ 16
+#define NS_INT16SZ 2
+
+#ifdef SPRINTF_CHAR
+#define SPRINTF(x) strlen(sprintf/**/x)
+#else
+#define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *inet_net_ntop_ipv4(const u_char *src, int bits,
+                  char *dst, size_t size);
+static char *inet_net_ntop_ipv6(const u_char *src, int bits,
+                  char *dst, size_t size);
+
+
+/*
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ * convert host/network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
+ * as called for by inet_net_pton() but it can be a host address with
+ * an included netmask.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+char *
+inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
+{
+   switch (af)
+   {
+       case PGSQL_AF_INET:
+           return (inet_net_ntop_ipv4(src, bits, dst, size));
+       case PGSQL_AF_INET6:
+           return (inet_net_ntop_ipv6(src, bits, dst, size));
+       default:
+           errno = EAFNOSUPPORT;
+           return (NULL);
+   }
+}
+
+/*
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network address from network to presentation format.
+ * "src"'s size is determined from its "af".
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed.  this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), October 1998
+ */
+static char *
+inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
+{
+   char       *odst = dst;
+   char       *t;
+   int         len = 4;
+   int         b;
+
+   if (bits < 0 || bits > 32)
+   {
+       errno = EINVAL;
+       return (NULL);
+   }
+
+   /* Always format all four octets, regardless of mask length. */
+   for (b = len; b > 0; b--)
+   {
+       if (size <= sizeof ".255")
+           goto emsgsize;
+       t = dst;
+       if (dst != odst)
+           *dst++ = '.';
+       dst += SPRINTF((dst, "%u", *src++));
+       size -= (size_t) (dst - t);
+   }
+
+   /* don't print masklen if 32 bits */
+   if (bits != 32)
+   {
+       if (size <= sizeof "/32")
+           goto emsgsize;
+       dst += SPRINTF((dst, "/%u", bits));
+   }
+
+   return (odst);
+
+emsgsize:
+   errno = EMSGSIZE;
+   return (NULL);
+}
+
+static int
+decoct(const u_char *src, int bytes, char *dst, size_t size)
+{
+   char       *odst = dst;
+   char       *t;
+   int         b;
+
+   for (b = 1; b <= bytes; b++)
+   {
+       if (size <= sizeof "255.")
+           return (0);
+       t = dst;
+       dst += SPRINTF((dst, "%u", *src++));
+       if (b != bytes)
+       {
+           *dst++ = '.';
+           *dst = '\0';
+       }
+       size -= (size_t) (dst - t);
+   }
+   return (dst - odst);
+}
+
+static char *
+inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
+{
+   /*
+    * Note that int32_t and int16_t need only be "at least" large enough to
+    * contain a value of the specified size.  On some systems, like Crays,
+    * there is no such thing as an integer variable with 16 bits. Keep this
+    * in mind if you think this function should have been coded to use
+    * pointer overlays.  All the world's not a VAX.
+    */
+   char        tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
+   char       *tp;
+   struct
+   {
+       int         base,
+                   len;
+   }           best, cur;
+   u_int       words[NS_IN6ADDRSZ / NS_INT16SZ];
+   int         i;
+
+   if ((bits < -1) || (bits > 128))
+   {
+       errno = EINVAL;
+       return (NULL);
+   }
+
+   /*
+    * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
+    * the longest run of 0x00's in src[] for :: shorthanding.
+    */
+   memset(words, '\0', sizeof words);
+   for (i = 0; i < NS_IN6ADDRSZ; i++)
+       words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+   best.base = -1;
+   cur.base = -1;
+   best.len = 0;
+   cur.len = 0;
+   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
+   {
+       if (words[i] == 0)
+       {
+           if (cur.base == -1)
+               cur.base = i, cur.len = 1;
+           else
+               cur.len++;
+       }
+       else
+       {
+           if (cur.base != -1)
+           {
+               if (best.base == -1 || cur.len > best.len)
+                   best = cur;
+               cur.base = -1;
+           }
+       }
+   }
+   if (cur.base != -1)
+   {
+       if (best.base == -1 || cur.len > best.len)
+           best = cur;
+   }
+   if (best.base != -1 && best.len < 2)
+       best.base = -1;
+
+   /*
+    * Format the result.
+    */
+   tp = tmp;
+   for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
+   {
+       /* Are we inside the best run of 0x00's? */
+       if (best.base != -1 && i >= best.base &&
+           i < (best.base + best.len))
+       {
+           if (i == best.base)
+               *tp++ = ':';
+           continue;
+       }
+       /* Are we following an initial run of 0x00s or any real hex? */
+       if (i != 0)
+           *tp++ = ':';
+       /* Is this address an encapsulated IPv4? */
+       if (i == 6 && best.base == 0 && (best.len == 6 ||
+                                    (best.len == 7 && words[7] != 0x0001) ||
+                                     (best.len == 5 && words[5] == 0xffff)))
+       {
+           int         n;
+
+           n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
+           if (n == 0)
+           {
+               errno = EMSGSIZE;
+               return (NULL);
+           }
+           tp += strlen(tp);
+           break;
+       }
+       tp += SPRINTF((tp, "%x", words[i]));
+   }
+
+   /* Was it a trailing run of 0x00's? */
+   if (best.base != -1 && (best.base + best.len) ==
+       (NS_IN6ADDRSZ / NS_INT16SZ))
+       *tp++ = ':';
+   *tp = '\0';
+
+   if (bits != -1 && bits != 128)
+       tp += SPRINTF((tp, "/%u", bits));
+
+   /*
+    * Check for overflow, copy, and we're done.
+    */
+   if ((size_t) (tp - tmp) > size)
+   {
+       errno = EMSGSIZE;
+       return (NULL);
+   }
+   strcpy(dst, tmp);
+   return (dst);
+}
+