/*
* HTTP address list routines for CUPS.
*
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2018 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
- * These coded instructions, statements, and computer programs are the
- * 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/".
- *
- * This file is subject to the Apple OS-Developed Software exception.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
*/
/*
*/
#include "cups-private.h"
+#include "debug-internal.h"
#ifdef HAVE_RESOLV_H
# include <resolv.h>
#endif /* HAVE_RESOLV_H */
#ifdef HAVE_POLL
# include <poll.h>
#endif /* HAVE_POLL */
-#ifndef WIN32
+#ifndef _WIN32
# include <fcntl.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* 'httpAddrConnect()' - Connect to any of the addresses in the list.
*
- * @since CUPS 1.2/macOS 10.5@
+ * @since CUPS 1.2/macOS 10.5@ @exclude all@
*/
http_addrlist_t * /* O - Connected address or NULL on failure */
int *cancel) /* I - Pointer to "cancel" variable */
{
int val; /* Socket option value */
-#ifndef WIN32
- int flags; /* Socket flags */
-#endif /* !WIN32 */
- int remaining; /* Remaining timeout */
- int i, /* Looping var */
- nfds, /* Number of file descriptors */
- fds[100], /* Socket file descriptors */
+#ifndef _WIN32
+ int i, j, /* Looping vars */
+ flags, /* Socket flags */
result; /* Result from select() or poll() */
+#endif /* !_WIN32 */
+ int remaining; /* Remaining timeout */
+ int nfds, /* Number of file descriptors */
+ fds[100]; /* Socket file descriptors */
http_addrlist_t *addrs[100]; /* Addresses */
#ifndef HAVE_POLL
int max_fd = -1; /* Highest file descriptor */
# endif /* HAVE_POLL */
#endif /* O_NONBLOCK */
#ifdef DEBUG
+# ifndef _WIN32
socklen_t len; /* Length of value */
http_addr_t peer; /* Peer address */
+# endif /* !_WIN32 */
char temp[256]; /* Temporary address string */
#endif /* DEBUG */
return (addrlist);
}
-#ifdef WIN32
+#ifdef _WIN32
if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
#else
if (errno != EINPROGRESS && errno != EWOULDBLOCK)
-#endif /* WIN32 */
+#endif /* _WIN32 */
{
DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno)));
httpAddrClose(NULL, fds[nfds]);
continue;
}
-#ifndef WIN32
+#ifndef _WIN32
fcntl(fds[nfds], F_SETFL, flags);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
#ifndef HAVE_POLL
if (fds[nfds] > max_fd)
addrlist = addrlist->next;
}
+ if (!addrlist && nfds == 0)
+ break;
+
/*
* See if we can connect to any of the addresses so far...
*/
DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno));
# endif /* HAVE_POLL */
}
-# ifdef WIN32
+# ifdef _WIN32
while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK));
# else
while (result < 0 && (errno == EINTR || errno == EAGAIN));
-# endif /* WIN32 */
+# endif /* _WIN32 */
if (result > 0)
{
+ http_addrlist_t *connaddr = NULL; /* Connected address, if any */
+
for (i = 0; i < nfds; i ++)
{
# ifdef HAVE_POLL
DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
# else
- if (FD_ISSET(fds[i], &input) && !FD_ISSET(fds[i], &error))
+ if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set))
# endif /* HAVE_POLL */
{
*sock = fds[i];
- addrlist = addrs[i];
+ connaddr = addrs[i];
# ifdef DEBUG
len = sizeof(peer);
if (!getpeername(fds[i], (struct sockaddr *)&peer, &len))
DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer)));
# endif /* DEBUG */
+
+ break;
}
- else
+# ifdef HAVE_POLL
+ else if (pfds[i].revents & (POLLERR | POLLHUP))
+# else
+ else if (FD_ISSET(fds[i], &error_set))
+# endif /* HAVE_POLL */
+ {
+ /*
+ * Error on socket, remove from the "pool"...
+ */
+
httpAddrClose(NULL, fds[i]);
+ nfds --;
+ if (i < nfds)
+ {
+ memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0])));
+ memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0])));
+ }
+ i --;
+ }
}
- return (addrlist);
+ if (connaddr)
+ {
+ /*
+ * Connected on one address, close all of the other sockets we have so
+ * far and return...
+ */
+
+ for (j = 0; j < i; j ++)
+ httpAddrClose(NULL, fds[j]);
+
+ for (j ++; j < nfds; j ++)
+ httpAddrClose(NULL, fds[j]);
+
+ return (connaddr);
+ }
}
#endif /* O_NONBLOCK */
httpAddrClose(NULL, fds[nfds]);
}
-#ifdef WIN32
+#ifdef _WIN32
_cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0);
#else
_cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0);
-#endif /* WIN32 */
+#endif /* _WIN32 */
return (NULL);
}
if (!temp)
{
httpAddrFreeList(first);
+ freeaddrinfo(results);
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
return (NULL);
}
if (error == EAI_FAIL)
cg->need_res_init = 1;
+# ifdef _WIN32 /* Really, Microsoft?!? */
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerrorA(error), 0);
+# else
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
+# endif /* _WIN32 */
}
#else
temp->addr.ipv6.sin6_family = AF_INET6;
temp->addr.ipv6.sin6_port = htons(portnum);
-# ifdef WIN32
+# ifdef _WIN32
temp->addr.ipv6.sin6_addr.u.Byte[15] = 1;
# else
temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1);
-# endif /* WIN32 */
+# endif /* _WIN32 */
if (!first)
first = temp;