X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;ds=sidebyside;f=cups%2Fhttp-addrlist.c;h=485c6f43da2012f67d09b35440fdf8d11a44c419;hb=87030afb3aa8735848c66a0526d06af69d7010c6;hp=f74d9ed7a659d2998a3b03f2acb65ed763ea72c5;hpb=681399ba79554f9c209661a8ca55937d798091c1;p=thirdparty%2Fcups.git diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c index f74d9ed7a..485c6f43d 100644 --- a/cups/http-addrlist.c +++ b/cups/http-addrlist.c @@ -1,16 +1,11 @@ /* * 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. */ /* @@ -18,21 +13,22 @@ */ #include "cups-private.h" +#include "debug-internal.h" #ifdef HAVE_RESOLV_H # include #endif /* HAVE_RESOLV_H */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ -#ifndef WIN32 +#ifndef _WIN32 # include -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * 'httpAddrConnect()' - Connect to any of the addresses in the list. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ @exclude all@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ @@ -50,7 +46,7 @@ httpAddrConnect( * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a * timeout and optional cancel. * - * @since CUPS 1.7/OS X 10.9@ + * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ @@ -61,26 +57,33 @@ httpAddrConnect2( int *cancel) /* I - Pointer to "cancel" variable */ { int val; /* Socket option value */ -#ifdef O_NONBLOCK - int flags, /* Socket flags */ - 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 */ +#ifdef O_NONBLOCK # ifdef HAVE_POLL struct pollfd pfds[100]; /* Polled file descriptors */ # else - int max_fd = -1; /* Highest file descriptor */ fd_set input_set, /* select() input set */ - output_set; /* select() output set */ + output_set, /* select() output set */ + error_set; /* select() error set */ struct timeval timeout; /* Timeout */ # 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 */ @@ -208,11 +211,11 @@ httpAddrConnect2( 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]); @@ -220,7 +223,9 @@ httpAddrConnect2( continue; } +#ifndef _WIN32 fcntl(fds[nfds], F_SETFL, flags); +#endif /* !_WIN32 */ #ifndef HAVE_POLL if (fds[nfds] > max_fd) @@ -232,6 +237,9 @@ httpAddrConnect2( addrlist = addrlist->next; } + if (!addrlist && nfds == 0) + break; + /* * See if we can connect to any of the addresses so far... */ @@ -276,46 +284,82 @@ httpAddrConnect2( for (i = 0; i < nfds; i ++) FD_SET(fds[i], &input_set); output_set = input_set; + error_set = input_set; timeout.tv_sec = 0; timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000; - result = select(max_fd + 1, &input_set, &output_set, NULL, &timeout); + result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout); 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) + if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP))) # else - if (FD_ISSET(fds[i], &input)) + 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 */ @@ -331,11 +375,11 @@ httpAddrConnect2( 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); } @@ -344,7 +388,7 @@ httpAddrConnect2( /* * 'httpAddrCopyList()' - Copy an address list. * - * @since CUPS 1.7/OS X 10.9@ + * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - New address list or @code NULL@ on error */ @@ -393,7 +437,7 @@ httpAddrCopyList( /* * 'httpAddrFreeList()' - Free an address list. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ void @@ -421,7 +465,7 @@ httpAddrFreeList( /* * 'httpAddrGetList()' - Get a list of addresses for a hostname. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ http_addrlist_t * /* O - List of addresses or NULL */ @@ -572,6 +616,7 @@ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for p if (!temp) { httpAddrFreeList(first); + freeaddrinfo(results); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } @@ -607,7 +652,11 @@ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for p 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 @@ -802,11 +851,11 @@ 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); -# 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;