]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-addrlist.c
Merge changes from CUPS 1.5svn-r9313.
[thirdparty/cups.git] / cups / http-addrlist.c
index a6f06133ea0f9e8c37bf3cdd1d446e14f0f2281c..14406427dde3cfd2fa6986271d3ec6045bc03f06 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: http-addrlist.c 5103 2006-02-14 19:27:42Z mike $"
+ * "$Id: http-addrlist.c 7910 2008-09-06 00:25:17Z mike $"
  *
- *   HTTP address list routines for the Common UNIX Printing System (CUPS).
+ *   HTTP address list routines for CUPS.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2010 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
  * Include necessary headers...
  */
 
-#include "http-private.h"
-#include "globals.h"
-#include "debug.h"
-#include <stdlib.h>
+#include "cups-private.h"
+#ifdef HAVE_RESOLV_H
+#  include <resolv.h>
+#endif /* HAVE_RESOLV_H */
 
 
 /*
  * 'httpAddrConnect()' - Connect to any of the addresses in the list.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_addrlist_t *                      /* O - Connected address or NULL on failure */
@@ -50,7 +41,18 @@ httpAddrConnect(
     int             *sock)             /* O - Socket */
 {
   int  val;                            /* Socket option value */
+#ifdef DEBUG
+  char temp[256];                      /* Temporary address string */
+#endif /* DEBUG */
+
 
+  DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist, sock));
+
+  if (!sock)
+  {
+    errno = EINVAL;
+    return (NULL);
+  }
 
  /*
   * Loop through each address until we connect or run out of addresses...
@@ -62,7 +64,12 @@ httpAddrConnect(
     * Create the socket...
     */
 
-    if ((*sock = socket(addrlist->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
+    DEBUG_printf(("2httpAddrConnect: Trying %s:%d...",
+                 httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                 _httpAddrPort(&(addrlist->addr))));
+
+    if ((*sock = (int)socket(addrlist->addr.addr.sa_family, SOCK_STREAM,
+                             0)) < 0)
     {
      /*
       * Don't abort yet, as this could just be an issue with the local
@@ -95,6 +102,16 @@ httpAddrConnect(
     setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
 #endif /* SO_NOSIGPIPE */
 
+#ifdef __APPLE__
+   /*
+    * Use a 30-second read timeout when connecting to limit the amount of time
+    * we block...
+    */
+
+    val = 30;
+    setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val));
+#endif /* __APPLE__ */
+
    /*
     * Using TCP_NODELAY improves responsiveness, especially on systems
     * with a slow loopback interface...
@@ -122,7 +139,16 @@ httpAddrConnect(
 
     if (!connect(*sock, &(addrlist->addr.addr),
                  httpAddrLength(&(addrlist->addr))))
+    {
+      DEBUG_printf(("1httpAddrConnect: Connected to %s:%d...",
+                   httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                   _httpAddrPort(&(addrlist->addr))));
       break;
+    }
+
+    DEBUG_printf(("1httpAddrConnect: Unable to connect to %s:%d: %s",
+                 httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                 _httpAddrPort(&(addrlist->addr)), strerror(errno)));
 
    /*
     * Close this socket and move to the next address...
@@ -134,9 +160,13 @@ httpAddrConnect(
     close(*sock);
 #endif /* WIN32 */
 
+    *sock    = -1;
     addrlist = addrlist->next;
   }
 
+  if (!addrlist)
+    _cupsSetError(HTTP_SERVICE_UNAVAILABLE, _("Unable to connect to server"), 1);
+
   return (addrlist);
 }
 
@@ -144,7 +174,7 @@ httpAddrConnect(
 /*
  * 'httpAddrFreeList()' - Free an address list.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 void
@@ -172,7 +202,7 @@ httpAddrFreeList(
 /*
  * 'httpAddrGetList()' - Get a list of addresses for a hostname.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/Mac OS X 10.5@
  */
 
 http_addrlist_t        *                       /* O - List of addresses or NULL */
@@ -183,21 +213,46 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
   http_addrlist_t      *first,         /* First address in list */
                        *addr,          /* Current address in list */
                        *temp;          /* New address */
+  _cups_globals_t      *cg = _cupsGlobals();
+                                       /* Global data */
 
 
 #ifdef DEBUG
-  printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n",
-         hostname ? hostname : "(nil)",
-        family == AF_UNSPEC ? "UNSPEC" :
+  _cups_debug_printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, "
+                     "service=\"%s\")\n",
+                    hostname ? hostname : "(nil)",
+                    family == AF_UNSPEC ? "UNSPEC" :
 #  ifdef AF_LOCAL
-            family == AF_LOCAL ? "LOCAL" :
+                        family == AF_LOCAL ? "LOCAL" :
 #  endif /* AF_LOCAL */
 #  ifdef AF_INET6
-            family == AF_INET6 ? "INET6" :
+                        family == AF_INET6 ? "INET6" :
 #  endif /* AF_INET6 */
-            family == AF_INET ? "INET" : "???", service);
+                        family == AF_INET ? "INET" : "???", service);
 #endif /* DEBUG */
 
+#ifdef HAVE_RES_INIT
+ /*
+  * STR #2920: Initialize resolver after failure in cups-polld
+  *
+  * If the previous lookup failed, re-initialize the resolver to prevent
+  * temporary network errors from persisting.  This *should* be handled by
+  * the resolver libraries, but apparently the glibc folks do not agree.
+  *
+  * We set a flag at the end of this function if we encounter an error that
+  * requires reinitialization of the resolver functions.  We then call
+  * res_init() if the flag is set on the next call here or in httpAddrLookup().
+  */
+
+  if (cg->need_res_init)
+  {
+    res_init();
+
+    cg->need_res_init = 0;
+  }
+#endif /* HAVE_RES_INIT */
+
+
  /*
   * Lookup the address the best way we can...
   */
@@ -211,12 +266,15 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
     * Domain socket address...
     */
 
-    first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
-    first->addr.un.sun_family = AF_LOCAL;
-    strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
+    if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL)
+    {
+      first->addr.un.sun_family = AF_LOCAL;
+      strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path));
+    }
   }
   else
 #endif /* AF_LOCAL */
+  if (!hostname || strcasecmp(hostname, "localhost"))
   {
 #ifdef HAVE_GETADDRINFO
     struct addrinfo    hints,          /* Address lookup hints */
@@ -225,6 +283,8 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
     char               ipv6[1024],     /* IPv6 address */
                        *ipv6zone;      /* Pointer to zone separator */
     int                        ipv6len;        /* Length of IPv6 address */
+    int                        error;          /* getaddrinfo() error */
+
 
    /*
     * Lookup the address as needed...
@@ -248,7 +308,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        */
 
        strlcpy(ipv6, hostname + 4, sizeof(ipv6));
-       if ((ipv6len = strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
+       if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
        {
           ipv6[ipv6len] = '\0';
          hostname      = ipv6;
@@ -268,7 +328,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        */
 
        strlcpy(ipv6, hostname + 1, sizeof(ipv6));
-       if ((ipv6len = strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
+       if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']')
        {
           ipv6[ipv6len] = '\0';
          hostname      = ipv6;
@@ -276,7 +336,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
       }
     }
 
-    if (!getaddrinfo(hostname, service, &hints, &results))
+    if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0)
     {
      /*
       * Copy the results to our own address list structure...
@@ -322,6 +382,9 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
 
       freeaddrinfo(results);
     }
+    else if (error == EAI_FAIL)
+      cg->need_res_init = 1;
+
 #else
     if (hostname)
     {
@@ -411,16 +474,16 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
 #  ifdef AF_INET6
           if (host->h_addrtype == AF_INET6)
          {
-            first->addr.ipv6.sin6_family = AF_INET6;
-           memcpy(&(temp->addr.ipv6), host->h_addr_list[i],
+            temp->addr.ipv6.sin6_family = AF_INET6;
+           memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i],
                   sizeof(temp->addr.ipv6));
             temp->addr.ipv6.sin6_port = htons(portnum);
          }
          else
 #  endif /* AF_INET6 */
          {
-            first->addr.ipv4.sin_family = AF_INET;
-           memcpy(&(temp->addr.ipv4), host->h_addr_list[i],
+            temp->addr.ipv4.sin_family = AF_INET;
+           memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i],
                   sizeof(temp->addr.ipv4));
             temp->addr.ipv4.sin_port = htons(portnum);
           }
@@ -438,6 +501,8 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
          addr = temp;
        }
       }
+      else if (h_errno == NO_RECOVERY)
+        cg->need_res_init = 1;
     }
 #endif /* HAVE_GETADDRINFO */
   }
@@ -446,7 +511,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
   * Detect some common errors and handle them sanely...
   */
 
-  if (!addr && (!hostname || !strcmp(hostname, "localhost")))
+  if (!addr && (!hostname || !strcasecmp(hostname, "localhost")))
   {
     struct servent     *port;          /* Port number for service */
     int                        portnum;        /* Port number */
@@ -475,7 +540,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
     else
       return (NULL);
 
-    if (hostname && !strcmp(hostname, "localhost"))
+    if (hostname && !strcasecmp(hostname, "localhost"))
     {
      /*
       * Unfortunately, some users ignore all of the warnings in the
@@ -506,6 +571,9 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
 #  endif /* WIN32 */
 
+        if (!first)
+          first = temp;
+
         addr = temp;
       }
 
@@ -527,10 +595,11 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
        temp->addr.ipv4.sin_port        = htons(portnum);
        temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001);
 
+        if (!first)
+          first = temp;
+
         if (addr)
          addr->next = temp;
-       else
-          addr = temp;
       }
     }
     else if (!hostname)
@@ -556,6 +625,9 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
         temp->addr.ipv6.sin6_family = AF_INET6;
        temp->addr.ipv6.sin6_port   = htons(portnum);
 
+        if (!first)
+          first = temp;
+
         addr = temp;
       }
 
@@ -576,10 +648,11 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
         temp->addr.ipv4.sin_family = AF_INET;
        temp->addr.ipv4.sin_port   = htons(portnum);
 
+        if (!first)
+          first = temp;
+
         if (addr)
          addr->next = temp;
-       else
-          addr = temp;
       }
     }
   }
@@ -593,5 +666,5 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
 
 
 /*
- * End of "$Id: http-addrlist.c 5103 2006-02-14 19:27:42Z mike $".
+ * End of "$Id: http-addrlist.c 7910 2008-09-06 00:25:17Z mike $".
  */