OSDN Git Service

Tweak the existing special case for AIX in pg_getaddrinfo_all() to handle
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Jan 2009 19:58:06 +0000 (19:58 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Jan 2009 19:58:06 +0000 (19:58 +0000)
yet another failure case in AIX's getaddrinfo().  Per report and patch
by Andrew Chernow.

src/backend/libpq/ip.c

index ef3ef04..67e9265 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/libpq/ip.c,v 1.43 2009/01/01 17:23:42 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/libpq/ip.c,v 1.44 2009/01/23 19:58:06 tgl Exp $
  *
  * This file and the IPV6 implementation were initially provided by
  * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
@@ -74,36 +74,46 @@ pg_getaddrinfo_all(const char *hostname, const char *servname,
                return getaddrinfo_unix(servname, hintp, result);
 #endif
 
+#ifndef _AIX
        /* NULL has special meaning to getaddrinfo(). */
        rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
                                         servname, hintp, result);
 
-#ifdef _AIX
+#else /* _AIX */
 
        /*
-        * It seems some versions of AIX's getaddrinfo don't reliably zero
-        * sin_port when servname is NULL, so clean up after it.
+        * Various versions of AIX have various bugs in getaddrinfo()'s handling
+        * of the servname parameter, including failing entirely if it's not NULL
+        * and failing to zero sin_port when it is NULL :-(.  Avoid these by
+        * always passing NULL and handling the port number for ourselves.
         */
-       if (servname == NULL && rc == 0)
+       rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
+                                        NULL, hintp, result);
+
+       if (rc == 0)
        {
                struct addrinfo *addr;
+               unsigned short port = 0;
+
+               if (servname && *servname)
+                       port = atoi(servname);
 
                for (addr = *result; addr; addr = addr->ai_next)
                {
                        switch (addr->ai_family)
                        {
                                case AF_INET:
-                                       ((struct sockaddr_in *) addr->ai_addr)->sin_port = htons(0);
+                                       ((struct sockaddr_in *) addr->ai_addr)->sin_port = htons(port);
                                        break;
 #ifdef HAVE_IPV6
                                case AF_INET6:
-                                       ((struct sockaddr_in6 *) addr->ai_addr)->sin6_port = htons(0);
+                                       ((struct sockaddr_in6 *) addr->ai_addr)->sin6_port = htons(port);
                                        break;
 #endif
                        }
                }
        }
-#endif
+#endif /* _AIX */
 
        return rc;
 }