]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http-addrlist.c
Update svn:keyword properties.
[thirdparty/cups.git] / cups / http-addrlist.c
index 0a77b7ea6c111251d373ff1d7ffed580bca4287d..4943b5867ea69d59f0e38fe982a612d8769758bd 100644 (file)
@@ -1,47 +1,47 @@
 /*
- * "$Id: http-addrlist.c 4976 2006-01-25 15:07:40Z mike $"
+ * "$Id$"
  *
- *   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-2013 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:
  *
- *   httpAddrConnect()  - Connect to any of the addresses in the list.
+ *   httpAddrConnect() - Connect to any of the addresses in the list.
+ *   httpAddrConnect2() - Connect to any of the addresses in the list with a
+ *                       timeout and optional cancel.
+ *   httpAddrCopyList() - Copy an address list.
  *   httpAddrFreeList() - Free an address list.
- *   httpAddrGetList()  - Get a list of addresses for a hostname.
+ *   httpAddrGetList() - Get a list of addresses for a hostname.
  */
 
 /*
  * 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 */
+#ifdef HAVE_POLL
+#  include <poll.h>
+#endif /* HAVE_POLL */
+#ifndef WIN32
+#  include <fcntl.h>
+#endif /* WIN32 */
 
 
 /*
  * 'httpAddrConnect()' - Connect to any of the addresses in the list.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/OS X 10.5@
  */
 
 http_addrlist_t *                      /* O - Connected address or NULL on failure */
@@ -49,8 +49,61 @@ httpAddrConnect(
     http_addrlist_t *addrlist,         /* I - List of potential addresses */
     int             *sock)             /* O - Socket */
 {
-  int  val;                            /* Socket option value */
+  DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist, sock));
+
+  return (httpAddrConnect2(addrlist, sock, 30000, NULL));
+}
+
+
+/*
+ * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a
+ *                        timeout and optional cancel.
+ *
+ * @since CUPS 1.7@
+ */
+
+http_addrlist_t *                      /* O - Connected address or NULL on failure */
+httpAddrConnect2(
+    http_addrlist_t *addrlist,         /* I - List of potential addresses */
+    int             *sock,             /* O - Socket */
+    int             msec,              /* I - Timeout in milliseconds */
+    int             *cancel)           /* I - Pointer to "cancel" variable */
+{
+  int                  val;            /* Socket option value */
+#ifdef O_NONBLOCK
+  socklen_t            len;            /* Length of value */
+  http_addr_t          peer;           /* Peer address */
+  int                  flags,          /* Socket flags */
+                       remaining;      /* Remaining timeout */
+#  ifdef HAVE_POLL
+  struct pollfd                pfd;            /* Polled file descriptor */
+#  else
+  fd_set               input_set,      /* select() input set */
+                       output_set;     /* select() output set */
+  struct timeval       timeout;        /* Timeout */
+#  endif /* HAVE_POLL */
+  int                  nfds;           /* Result from select()/poll() */
+#endif /* O_NONBLOCK */
+#ifdef DEBUG
+  char                 temp[256];      /* Temporary address string */
+#endif /* DEBUG */
+
 
+  DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)",
+                addrlist, sock, msec, cancel));
+
+  if (!sock)
+  {
+    errno = EINVAL;
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+    return (NULL);
+  }
+
+  if (cancel && *cancel)
+    return (NULL);
+
+  if (msec <= 0 || getenv("CUPS_DISABLE_ASYNC_CONNECT"))
+    msec = INT_MAX;
 
  /*
   * Loop through each address until we connect or run out of addresses...
@@ -58,11 +111,19 @@ httpAddrConnect(
 
   while (addrlist)
   {
+    if (cancel && *cancel)
+      return (NULL);
+
    /*
     * Create the socket...
     */
 
-    if ((*sock = socket(addrlist->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
+    DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...",
+                 httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                 httpAddrPort(&(addrlist->addr))));
+
+    if ((*sock = (int)socket(_httpAddrFamily(&(addrlist->addr)), SOCK_STREAM,
+                             0)) < 0)
     {
      /*
       * Don't abort yet, as this could just be an issue with the local
@@ -78,21 +139,16 @@ httpAddrConnect(
     */
 
     val = 1;
-#ifdef WIN32
-    setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&val,
-               sizeof(val));
-#else
-    setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-#endif /* WIN32 */
+    setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
 
 #ifdef SO_REUSEPORT
     val = 1;
-    setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
+    setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val));
 #endif /* SO_REUSEPORT */
 
 #ifdef SO_NOSIGPIPE
     val = 1;
-    setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
+    setsockopt(*sock, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
 #endif /* SO_NOSIGPIPE */
 
    /*
@@ -101,12 +157,7 @@ httpAddrConnect(
     */
 
     val = 1;
-#ifdef WIN32
-    setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&val,
-               sizeof(val)); 
-#else
-    setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 
-#endif /* WIN32 */
+    setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
 
 #ifdef FD_CLOEXEC
    /*
@@ -116,31 +167,211 @@ httpAddrConnect(
     fcntl(*sock, F_SETFD, FD_CLOEXEC);
 #endif /* FD_CLOEXEC */
 
+#ifdef O_NONBLOCK
+   /*
+    * Do an asynchronous connect by setting the socket non-blocking...
+    */
+
+    DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()"));
+
+    flags = fcntl(*sock, F_GETFL, 0);
+    if (msec != INT_MAX)
+    {
+      DEBUG_puts("httpAddrConnect2: Setting non-blocking connect()");
+
+      fcntl(*sock, F_SETFL, flags | O_NONBLOCK);
+    }
+#endif /* O_NONBLOCK */
+
    /*
     * Then connect...
     */
 
     if (!connect(*sock, &(addrlist->addr.addr),
                  httpAddrLength(&(addrlist->addr))))
-      break;
+    {
+      DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
+                   httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                   httpAddrPort(&(addrlist->addr))));
+
+#ifdef O_NONBLOCK
+      fcntl(*sock, F_SETFL, flags);
+#endif /* O_NONBLOCK */
+
+      return (addrlist);
+    }
+
+#ifdef O_NONBLOCK
+#  ifdef WIN32
+    if (WSAGetLastError() == WSAEINPROGRESS ||
+        WSAGetLastError() == WSAEWOULDBLOCK)
+#  else
+    if (errno == EINPROGRESS || errno == EWOULDBLOCK)
+#  endif /* WIN32 */
+    {
+      DEBUG_puts("1httpAddrConnect2: Finishing async connect()");
+
+      fcntl(*sock, F_SETFL, flags);
+
+      for (remaining = msec; remaining > 0; remaining -= 250)
+      {
+       do
+        {
+          if (cancel && *cancel)
+          {
+          /*
+           * Close this socket and return...
+           */
+
+            DEBUG_puts("1httpAddrConnect2: Canceled connect()");
+
+#    ifdef WIN32
+           closesocket(*sock);
+#    else
+           close(*sock);
+#    endif /* WIN32 */
+
+           *sock = -1;
+
+           return (NULL);
+          }
+
+#  ifdef HAVE_POLL
+         pfd.fd     = *sock;
+         pfd.events = POLLIN | POLLOUT;
+
+          nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
+
+         DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", nfds,
+                       errno));
+
+#  else
+         FD_ZERO(&input_set);
+         FD_SET(*sock, &input_set);
+         output_set = input_set;
+
+         timeout.tv_sec  = 0;
+         timeout.tv_usec = (remaining > 250 ? 250 : remaining) * 1000;
+
+         nfds = select(*sock + 1, &input_set, &output_set, NULL, &timeout);
+
+         DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", nfds,
+                       errno));
+#  endif /* HAVE_POLL */
+       }
+#  ifdef WIN32
+       while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
+                           WSAGetLastError() == WSAEWOULDBLOCK));
+#  else
+       while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
+#  endif /* WIN32 */
+
+        if (nfds > 0)
+        {
+          len = sizeof(peer);
+          if (!getpeername(*sock, (struct sockaddr *)&peer, &len))
+          {
+           DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...",
+                         httpAddrString(&peer, temp, sizeof(temp)),
+                         httpAddrPort(&peer)));
+
+           return (addrlist);
+         }
+
+          break;
+        }
+      }
+    }
+#endif /* O_NONBLOCK */
+
+    DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s",
+                 httpAddrString(&(addrlist->addr), temp, sizeof(temp)),
+                 httpAddrPort(&(addrlist->addr)), strerror(errno)));
+
+#ifndef WIN32
+    if (errno == EINPROGRESS)
+      errno = ETIMEDOUT;
+#endif /* !WIN32 */
 
    /*
     * Close this socket and move to the next address...
     */
 
+#ifdef WIN32
     closesocket(*sock);
+#else
+    close(*sock);
+#endif /* WIN32 */
 
+    *sock    = -1;
     addrlist = addrlist->next;
   }
 
+  if (!addrlist)
+#ifdef WIN32
+    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
+#else
+    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
+#endif /* WIN32 */
+
   return (addrlist);
 }
 
 
+
+/*
+ * 'httpAddrCopyList()' - Copy an address list.
+ *
+ * @since CUPS 1.7@
+ */
+
+http_addrlist_t        *                       /* O - New address list or @code NULL@ on error */
+httpAddrCopyList(
+    http_addrlist_t *src)              /* I - Source address list */
+{
+  http_addrlist_t      *dst = NULL,    /* First list entry */
+                       *prev = NULL,   /* Previous list entry */
+                       *current = NULL;/* Current list entry */
+
+
+  while (src)
+  {
+    if ((current = malloc(sizeof(http_addrlist_t))) == NULL)
+    {
+      current = dst;
+
+      while (current)
+      {
+        prev    = current;
+        current = current->next;
+
+        free(prev);
+      }
+
+      return (NULL);
+    }
+
+    memcpy(current, src, sizeof(http_addrlist_t));
+
+    current->next = NULL;
+
+    if (prev)
+      prev->next = current;
+    else
+      dst = current;
+
+    prev = current;
+    src  = src->next;
+  }
+
+  return (dst);
+}
+
+
 /*
  * 'httpAddrFreeList()' - Free an address list.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/OS X 10.5@
  */
 
 void
@@ -168,7 +399,7 @@ httpAddrFreeList(
 /*
  * 'httpAddrGetList()' - Get a list of addresses for a hostname.
  *
- * @since CUPS 1.2@
+ * @since CUPS 1.2/OS X 10.5@
  */
 
 http_addrlist_t        *                       /* O - List of addresses or NULL */
@@ -179,21 +410,45 @@ 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...
   */
@@ -207,20 +462,25 @@ 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 || _cups_strcasecmp(hostname, "localhost"))
   {
 #ifdef HAVE_GETADDRINFO
     struct addrinfo    hints,          /* Address lookup hints */
                        *results,       /* Address lookup results */
                        *current;       /* Current result */
-    char               ipv6[1024],     /* IPv6 address */
+    char               ipv6[64],       /* IPv6 address */
                        *ipv6zone;      /* Pointer to zone separator */
     int                        ipv6len;        /* Length of IPv6 address */
+    int                        error;          /* getaddrinfo() error */
+
 
    /*
     * Lookup the address as needed...
@@ -244,7 +504,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;
@@ -264,7 +524,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;
@@ -272,7 +532,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...
@@ -289,6 +549,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
          if (!temp)
          {
            httpAddrFreeList(first);
+           _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
            return (NULL);
          }
 
@@ -318,6 +579,14 @@ httpAddrGetList(const char *hostname,      /* I - Hostname, IP address, or NULL for p
 
       freeaddrinfo(results);
     }
+    else
+    {
+      if (error == EAI_FAIL)
+        cg->need_res_init = 1;
+
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
+    }
+
 #else
     if (hostname)
     {
@@ -343,7 +612,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
         portnum = 80;
       else if (!strcmp(service, "https"))
         portnum = 443;
-      else if (!strcmp(service, "ipp"))
+      else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
         portnum = 631;
       else if (!strcmp(service, "lpd"))
         portnum = 515;
@@ -407,16 +676,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);
           }
@@ -434,6 +703,13 @@ 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;
+
+       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0);
+      }
     }
 #endif /* HAVE_GETADDRINFO */
   }
@@ -442,7 +718,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 || !_cups_strcasecmp(hostname, "localhost")))
   {
     struct servent     *port;          /* Port number for service */
     int                        portnum;        /* Port number */
@@ -462,16 +738,21 @@ httpAddrGetList(const char *hostname,     /* I - Hostname, IP address, or NULL for p
       portnum = 80;
     else if (!strcmp(service, "https"))
       portnum = 443;
-    else if (!strcmp(service, "ipp"))
+    else if (!strcmp(service, "ipp") || !strcmp(service, "ipps"))
       portnum = 631;
     else if (!strcmp(service, "lpd"))
       portnum = 515;
     else if (!strcmp(service, "socket"))
       portnum = 9100;
     else
+    {
+      httpAddrFreeList(first);
+
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1);
       return (NULL);
+    }
 
-    if (hostname && !strcmp(hostname, "localhost"))
+    if (hostname && !_cups_strcasecmp(hostname, "localhost"))
     {
      /*
       * Unfortunately, some users ignore all of the warnings in the
@@ -490,6 +771,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
        if (!temp)
        {
+         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
          httpAddrFreeList(first);
          return (NULL);
        }
@@ -502,6 +784,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;
       }
 
@@ -515,6 +800,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
        if (!temp)
        {
+         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
          httpAddrFreeList(first);
          return (NULL);
        }
@@ -523,10 +809,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)
@@ -545,6 +832,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
        if (!temp)
        {
+         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
          httpAddrFreeList(first);
          return (NULL);
        }
@@ -552,6 +840,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;
       }
 
@@ -565,6 +856,7 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
        temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t));
        if (!temp)
        {
+         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
          httpAddrFreeList(first);
          return (NULL);
        }
@@ -572,10 +864,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;
       }
     }
   }
@@ -589,5 +882,5 @@ httpAddrGetList(const char *hostname,       /* I - Hostname, IP address, or NULL for p
 
 
 /*
- * End of "$Id: http-addrlist.c 4976 2006-01-25 15:07:40Z mike $".
+ * End of "$Id$".
  */