From: mike Date: Sat, 8 Oct 2005 10:10:46 +0000 (+0000) Subject: New IPv6-capable address list stuff for STR #1313. Basically, this X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=086c584d2a23b20e4f7346ac202afe5216dbd599;p=thirdparty%2Fcups.git New IPv6-capable address list stuff for STR #1313. Basically, this change deprecates the old httpGetHostByName() interface and adds a new address list interface which supports mixed address types. backend/lpd.c: - lpd_queue(): Use new httpAddrGetList() and httpAddrFreeList() functions. backend/socket.c: - main(): Use new httpAddrConnect(), httpAddrGetList() and httpAddrFreeList() functions. cups/auth.c: - cups_local_auth(): Fix address check for new hostaddr pointer. cups/file.c: - cupsFileOpen(): Use new httpAddrConnect(), httpAddrGetList() and httpAddrFreeList() functions. cups/globals.h: - Drop ip_addrs from and add ip_addr and domain_socket members to _cups_globals_s structure. cups/http-addr.c: - httpAddrLoad(): Deleted. - httpGetHostByName(): Remove IPv6 and getaddrinfo() handling code. cups/http-addrlist.c: - Added. cups/http.c: - httpClose(): Free address list. - httpConnectEncrypt(): Use new httpAddrFreeList() and httpAddrGetList() functions. - httpReconnect(): Use new httpAddrConnect() function. cups/http.h: - Change hostaddr member of http_t structure to be a http_addr_t *. - Add addrlist member to the http_t structure. - Add httpAddrConnect(), httpAddrFreeList(), and httpAddrGetList() functions. - Remove httpAddrLoad() function. cups/http-private.h: - Add common headers. cups/util.c: - cupsGetPPD2(): Fix hostaddr references. scheduler/auth.c: - cupsdIsAuthorized(): Fix hostaddr references. scheduler/client.c: - cupsdAcceptClient(): Use httpAddrFreeList() and httpAddrGetList(), and fix hostaddr references. - pipe_command(): Fix hostaddr references. scheduler/client.h: - Add clientaddr member to cups_client_t structure. - Change ServerAddr to ServerAddrs list. scheduler/conf.c: - get_address(): Use httpAddrFreeList() and httpAddrGetList(). scheduler/listen.c: - cupsdStartListening(): Use httpAddrFreeList() and httpAddrGetList(). scheduler/network.c: - cupsdNetIFUpdate(): Use ServerAddrs list. git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@4757 7a7537e8-13f0-0310-91df-b6672ffda945 --- diff --git a/backend/lpd.c b/backend/lpd.c index e00a206fd..642cc513b 100644 --- a/backend/lpd.c +++ b/backend/lpd.c @@ -536,7 +536,6 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ int manual_copies, /* I - Do copies by hand... */ int timeout) /* I - Timeout... */ { - int i; /* Looping var */ FILE *fp; /* Job file */ char localhost[255]; /* Local host name */ int error; /* Error number */ @@ -546,8 +545,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ char control[10240], /* LPD control 'file' */ *cptr; /* Pointer into control file string */ char status; /* Status byte from command */ - http_addr_t addr; /* Socket address */ - struct hostent *hostaddr; /* Host address */ + char portname[255]; /* Port name */ + http_addrlist_t *addrlist, /* Address list */ + *addr; /* Socket address */ int copy; /* Copies written */ size_t nbytes; /* Number of bytes written */ off_t tbytes; /* Total bytes written */ @@ -573,6 +573,19 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ signal(SIGALRM, lpd_timeout); #endif /* HAVE_SIGSET */ + /* + * Find the printer... + */ + + sprintf(portname, "%d", port); + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", + hostname); + return (CUPS_BACKEND_STOP); + } + /* * Loop forever trying to print the file... */ @@ -583,29 +596,30 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * First try to reserve a port for this connection... */ - if ((hostaddr = httpGetHostByName(hostname)) == NULL) - { - fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n", - hostname, hstrerror(h_errno)); - return (CUPS_BACKEND_STOP); - } - fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n", hostname, printer); - for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024;;) + for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist;; + addr = addr->next) { /* * Stop if this job has been cancelled... */ if (abort_job) + { + httpAddrFreeList(addrlist); + return (CUPS_BACKEND_FAILED); + } /* * Choose the next priviledged port... */ + if (!addr) + addr = addrlist; + lport --; if (lport < 721 && reserve == RESERVE_RFC1179) @@ -623,10 +637,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * Just create a regular socket... */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0) { perror("ERROR: Unable to create socket"); - return (CUPS_BACKEND_FAILED); + sleep(1); + + continue; } lport = 0; @@ -638,7 +654,7 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * priviledged lport between 721 and 731... */ - if ((fd = rresvport_af(&lport, hostaddr->h_addrtype)) < 0) + if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0) { perror("ERROR: Unable to reserve port"); sleep(1); @@ -651,70 +667,68 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ * Connect to the printer or server... */ - for (i = 0; hostaddr->h_addr_list[i]; i ++) + if (abort_job) { - if (abort_job) - { - close(fd); - return (CUPS_BACKEND_FAILED); - } + httpAddrFreeList(addrlist); - httpAddrLoad(hostaddr, port, i, &addr); + close(fd); - if (!connect(fd, (struct sockaddr *)&addr, sizeof(addr))) - break; + return (CUPS_BACKEND_FAILED); } - if (!hostaddr->h_addr_list[i]) + if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr)))) + break; + + error = errno; + close(fd); + fd = -1; + + if (addr->next) + continue; + + if (getenv("CLASS") != NULL) { - error = errno; - close(fd); - fd = -1; + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ - if (getenv("CLASS") != NULL) - { - /* - * If the CLASS environment variable is set, the job was submitted - * to a class and not to a specific queue. In this case, we want - * to abort immediately so that the job can be requeued on the next - * available printer in the class. - */ + fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n", + hostname); - fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n", - hostname); + httpAddrFreeList(addrlist); - /* - * Sleep 5 seconds to keep the job from requeuing too rapidly... - */ + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ - sleep(5); + sleep(5); - return (CUPS_BACKEND_FAILED); - } + return (CUPS_BACKEND_FAILED); + } - if (error == ECONNREFUSED || error == EHOSTDOWN || - error == EHOSTUNREACH) - { - fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n", - hostname); - sleep(30); - } - else if (error == EADDRINUSE) - { - /* - * Try on another port... - */ + if (error == ECONNREFUSED || error == EHOSTDOWN || + error == EHOSTUNREACH) + { + fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n", + hostname); + sleep(30); + } + else if (error == EADDRINUSE) + { + /* + * Try on another port... + */ - sleep(1); - } - else - { - perror("ERROR: Unable to connect to printer; will retry in 30 seconds..."); - sleep(30); - } + sleep(1); } else - break; + { + perror("ERROR: Unable to connect to printer; will retry in 30 seconds..."); + sleep(30); + } } fprintf(stderr, "INFO: Connected to %s...\n", hostname); @@ -727,6 +741,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (stat(filename, &filestats)) { + httpAddrFreeList(addrlist); + close(fd); + perror("ERROR: unable to stat print file"); return (CUPS_BACKEND_FAILED); } @@ -735,6 +752,9 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if ((fp = fopen(filename, "rb")) == NULL) { + httpAddrFreeList(addrlist); + close(fd); + perror("ERROR: unable to open print file for reading"); return (CUPS_BACKEND_FAILED); } @@ -746,9 +766,13 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (lpd_command(fd, timeout, "\002%s\n", printer)) /* Receive print job(s) */ + { + httpAddrFreeList(addrlist); + close(fd); return (CUPS_BACKEND_FAILED); + } - gethostname(localhost, sizeof(localhost)); + httpGetHostname(localhost, sizeof(localhost)); localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */ snprintf(control, sizeof(control), "H%s\nP%s\nJ%s\n", localhost, user, @@ -780,7 +804,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ { if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), getpid() % 1000, localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + return (CUPS_BACKEND_FAILED); + } fprintf(stderr, "INFO: Sending control file (%u bytes)\n", (unsigned)strlen(control)); @@ -822,7 +851,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n", CUPS_LLCAST filestats.st_size, getpid() % 1000, localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + return (CUPS_BACKEND_FAILED); + } fprintf(stderr, "INFO: Sending data file (" CUPS_LLFMT " bytes)\n", CUPS_LLCAST filestats.st_size); @@ -886,7 +920,12 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ { if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), getpid() % 1000, localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + return (CUPS_BACKEND_FAILED); + } fprintf(stderr, "INFO: Sending control file (%lu bytes)\n", (unsigned long)strlen(control)); @@ -925,7 +964,11 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ fclose(fp); if (status == 0) + { + httpAddrFreeList(addrlist); + return (CUPS_BACKEND_OK); + } /* * Waiting for a retry... @@ -934,6 +977,8 @@ lpd_queue(const char *hostname, /* I - Host to connect to */ sleep(30); } + httpAddrFreeList(addrlist); + /* * If we get here, then the job has been cancelled... */ diff --git a/backend/socket.c b/backend/socket.c index cf4928453..bc27af316 100644 --- a/backend/socket.c +++ b/backend/socket.c @@ -68,7 +68,6 @@ int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments (6 or 7) */ char *argv[]) /* I - Command-line arguments */ { - int i; /* Looping var */ char method[255], /* Method in URI */ hostname[1024], /* Hostname */ username[255], /* Username info (not used) */ @@ -76,11 +75,11 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ int fp; /* Print file */ int copies; /* Number of copies to print */ int port; /* Port number */ + char portname[255]; /* Port name */ int delay; /* Delay for retries... */ int fd; /* AppSocket */ int error; /* Error code (if any) */ - http_addr_t addr; /* Socket address */ - struct hostent *hostaddr; /* Host address */ + http_addrlist_t *addrlist; /* Address list */ int rbytes; /* Number of bytes read */ int wbytes; /* Number of bytes written */ int nbytes; /* Number of bytes read */ @@ -169,10 +168,11 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ * Then try to connect to the remote host... */ - if ((hostaddr = httpGetHostByName(hostname)) == NULL) + sprintf(portname, "%d", port); + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) { - fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n", - hostname, hstrerror(h_errno)); + fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", hostname); return (CUPS_BACKEND_STOP); } @@ -185,25 +185,10 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ { for (delay = 5;;) { - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - perror("ERROR: Unable to create socket"); - return (CUPS_BACKEND_FAILED); - } - - for (i = 0; hostaddr->h_addr_list[i]; i ++) - { - httpAddrLoad(hostaddr, port, i, &addr); - - if (!connect(fd, (struct sockaddr *)&addr, sizeof(addr))) - break; - } - - if (!hostaddr->h_addr_list[i]) + if (!httpAddrConnect(addrlist, &fd)) { error = errno; - close(fd); - fd = -1; + fd = -1; if (getenv("CLASS") != NULL) { @@ -410,6 +395,8 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */ close(fd); } + httpAddrFreeList(addrlist); + /* * Close the input file and return... */ diff --git a/cups/Makefile b/cups/Makefile index 25ed0fa62..87cd7206f 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -44,6 +44,7 @@ LIBOBJS = \ globals.o \ http.o \ http-addr.o \ + http-addrlist.o \ http-support.o \ ipp.o \ ipp-support.o \ diff --git a/cups/auth.c b/cups/auth.c index 3c72a5762..c9aac4538 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -190,7 +190,7 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * See if we are accessing localhost... */ - if (!httpAddrLocalhost(&http->hostaddr) && + if (!httpAddrLocalhost(http->hostaddr) && strcasecmp(http->hostname, "localhost") != 0) { DEBUG_puts("cups_local_auth: Not a local connection!"); diff --git a/cups/file.c b/cups/file.c index 81f43a97d..c7c0b2cd5 100644 --- a/cups/file.c +++ b/cups/file.c @@ -67,16 +67,6 @@ #include #include -#ifdef WIN32 -# include -# include -#else -# include -# include -# include -# define closesocket(f) close(f) -#endif /* WIN32 */ - #include "file.h" #ifdef HAVE_LIBZ # include @@ -577,12 +567,7 @@ cupsFileOpen(const char *filename, /* I - Name of file */ int fd; /* File descriptor */ char hostname[1024], /* Hostname */ *portname; /* Port "name" (number or service) */ - int port; /* Port number */ - struct servent *service; /* Service */ - int i; /* Looping var */ - int val; /* Socket value */ - struct hostent *hostaddr; /* Host address data */ - http_addr_t sockaddr; /* Socket address */ + http_addrlist_t *addrlist; /* Host address list */ /* @@ -618,72 +603,24 @@ cupsFileOpen(const char *filename, /* I - Name of file */ else return (NULL); - if ((hostaddr = httpGetHostByName(hostname)) == NULL) - return (NULL); + /* + * Lookup the hostname and service... + */ - if (isdigit(portname[0] & 255)) - port = atoi(portname); - else if ((service = getservbyname(portname, NULL)) != NULL) - port = ntohs(service->s_port); - else + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) return (NULL); - for (i = 0, fd = -1; hostaddr->h_addr_list[i]; i ++) - { - /* - * Load the address... - */ - - httpAddrLoad(hostaddr, port, i, &sockaddr); - - /* - * Create a socket... - */ - - if ((fd = socket(sockaddr.addr.sa_family, SOCK_STREAM, 0)) < 0) - continue; - - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); - -#ifdef SO_REUSEPORT - val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); -#endif /* SO_REUSEPORT */ - - /* - * Using TCP_NODELAY improves responsiveness, especially on systems - * with a slow loopback interface... Since we write large buffers - * when sending print files and requests, there shouldn't be any - * performance penalty for this... - */ - - val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); - - /* - * Connect to the server... - */ + /* + * Connect to the server... + */ -#ifdef AF_INET6 - if (sockaddr.addr.sa_family == AF_INET6) - { - if (connect(fd, (struct sockaddr *)&sockaddr, - sizeof(sockaddr.ipv6)) < 0) - { - fd = -1; - continue; - } - } - else -#endif /* AF_INET6 */ - if (connect(fd, (struct sockaddr *)&sockaddr, - sizeof(sockaddr.ipv4)) < 0) - { - fd = -1; - continue; - } + if (!httpAddrConnect(addrlist, &fd)) + { + httpAddrFreeList(addrlist); + return (NULL); } + + httpAddrFreeList(addrlist); break; default : /* Remove bogus compiler warning... */ diff --git a/cups/globals.h b/cups/globals.h index 0cabe56b8..f5ec97de2 100644 --- a/cups/globals.h +++ b/cups/globals.h @@ -51,13 +51,6 @@ extern "C" { # endif /* __cplusplus */ -/* - * Constants/limits... - */ - -# define CUPS_MAX_ADDRS 100 /* Limit on number of addresses... */ - - /* * To make libcups thread safe, define thread safe globals (aka thread- * specific data) for the static variables used in the library. @@ -69,10 +62,8 @@ typedef struct _cups_globals_s /**** CUPS global state data ****/ char http_date[256]; /* Date+time buffer */ /* http-addr.c */ - unsigned ip_addrs[CUPS_MAX_ADDRS][4]; - /* Packed IPv4/6 addresses */ - char *ip_ptrs[CUPS_MAX_ADDRS + 1]; - /* Pointer to packed address */ + unsigned ip_addr; /* Packed IPv4 address */ + char *ip_ptrs[2]; /* Pointer to packed address */ struct hostent hostent; /* Host entry for IP address */ # ifdef HAVE_GETADDRINFO char hostname[1024]; /* Hostname */ @@ -118,7 +109,9 @@ typedef struct _cups_globals_s /**** CUPS global state data ****/ /* usersys.c */ http_encryption_t encryption; /* Encryption setting */ char user[65], /* User name */ - server[256]; /* Server address */ + server[256], /* Server address */ + domain_socket[256]; + /* Domain socket address */ const char *(*password_cb)(const char *); /* Password callback */ diff --git a/cups/http-addr.c b/cups/http-addr.c index 121b47ddb..a0bb744a1 100644 --- a/cups/http-addr.c +++ b/cups/http-addr.c @@ -25,12 +25,12 @@ * * httpAddrAny() - Check for the "any" address. * httpAddrEqual() - Compare two addresses. - * httpAddrLoad() - Load a host entry address into an HTTP address. * httpAddrLocalhost() - Check for the local loopback address. * httpAddrLookup() - Lookup the hostname associated with the address. * httpAddrString() - Convert an IP address to a dotted string. * httpGetHostByName() - Lookup a hostname or IP address, and return * address records for the specified name. + * httpGetHostname() - Get the FQDN for the local system. */ /* @@ -44,6 +44,8 @@ /* * 'httpAddrAny()' - Check for the "any" address. + * + * @since CUPS 1.2@ */ int /* O - 1 if "any", 0 otherwise */ @@ -65,6 +67,8 @@ httpAddrAny(const http_addr_t *addr) /* I - Address to check */ /* * 'httpAddrEqual()' - Compare two addresses. + * + * @since CUPS 1.2@ */ int /* O - 1 if equal, 0 if != */ @@ -90,6 +94,8 @@ httpAddrEqual(const http_addr_t *addr1, /* I - First address */ /* * 'httpAddrLength()' - Return the length of the address in bytes. + * + * @since CUPS 1.2@ */ int /* O - Length in bytes */ @@ -113,61 +119,15 @@ httpAddrLength(const http_addr_t *addr) /* I - Address */ } -/* - * 'httpAddrLoad()' - Load a host entry address into an HTTP address. - */ - -void -httpAddrLoad(const struct hostent *host, /* I - Host entry */ - int port, /* I - Port number */ - int n, /* I - Index into host entry */ - http_addr_t *addr) /* O - Address to load */ -{ -#ifdef AF_INET6 - if (host->h_addrtype == AF_INET6) - { -# ifdef WIN32 - addr->ipv6.sin6_port = htons((u_short)port); -# else - addr->ipv6.sin6_port = htons(port); -# endif /* WIN32 */ - - memcpy((char *)&(addr->ipv6.sin6_addr), host->h_addr_list[n], - host->h_length); - addr->ipv6.sin6_family = AF_INET6; - } - else -#endif /* AF_INET6 */ -#ifdef AF_LOCAL - if (host->h_addrtype == AF_LOCAL) - { - addr->un.sun_family = AF_LOCAL; - strlcpy(addr->un.sun_path, host->h_addr_list[n], sizeof(addr->un.sun_path)); - } - else -#endif /* AF_LOCAL */ - if (host->h_addrtype == AF_INET) - { -# ifdef WIN32 - addr->ipv4.sin_port = htons((u_short)port); -# else - addr->ipv4.sin_port = htons(port); -# endif /* WIN32 */ - - memcpy((char *)&(addr->ipv4.sin_addr), host->h_addr_list[n], - host->h_length); - addr->ipv4.sin_family = AF_INET; - } -} - - /* * 'httpAddrLocalhost()' - Check for the local loopback address. + * + * @since CUPS 1.2@ */ int /* O - 1 if local host, 0 otherwise */ -httpAddrLocalhost(const http_addr_t *addr) - /* I - Address to check */ +httpAddrLocalhost( + const http_addr_t *addr) /* I - Address to check */ { #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6 && @@ -198,6 +158,8 @@ httpAddrLocalhost(const http_addr_t *addr) /* * 'httpAddrLookup()' - Lookup the hostname associated with the address. + * + * @since CUPS 1.2@ */ char * /* O - Host name */ @@ -245,6 +207,8 @@ httpAddrLookup(const http_addr_t *addr, /* I - Address to lookup */ /* * 'httpAddrString()' - Convert an IP address to a dotted string. + * + * @since CUPS 1.2@ */ char * /* O - IP string */ @@ -289,14 +253,15 @@ httpAddrString(const http_addr_t *addr, /* I - Address to convert */ /* - * 'httpGetHostByName()' - Lookup a hostname or IP address, and return + * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return * address records for the specified name. + * + * @deprecated@ */ struct hostent * /* O - Host entry */ httpGetHostByName(const char *name) /* I - Hostname or IP address */ { - int i; /* Looping var */ const char *nameptr; /* Pointer into name */ unsigned ip[4]; /* IP address components */ _cups_globals_t *cg = _cupsGlobals(); @@ -346,48 +311,6 @@ httpGetHostByName(const char *name) /* I - Hostname or IP address */ return (&cg->hostent); } #endif /* AF_LOCAL */ -#ifdef AF_INET6 - if (name[0] == '[') - { - /* - * A raw 128-bit IPv6 address of the form "[xxxx:xxxx:xxxx:xxxx]" - */ - - cg->hostent.h_name = (char *)name; - cg->hostent.h_aliases = NULL; - cg->hostent.h_addrtype = AF_INET6; - cg->hostent.h_length = 16; - cg->hostent.h_addr_list = cg->ip_ptrs; - cg->ip_ptrs[0] = (char *)(cg->ip_addrs[0]); - cg->ip_ptrs[1] = NULL; - - for (i = 0, nameptr = name + 1; *nameptr && i < 4; i ++) - { - if (*nameptr == ']') - break; - else if (*nameptr == ':') - cg->ip_addrs[0][i] = 0; - else - cg->ip_addrs[0][i] = htonl(strtoul(nameptr, (char **)&nameptr, 16)); - - if (*nameptr == ':' || *nameptr == ']') - nameptr ++; - } - - while (i < 4) - { - cg->ip_addrs[0][i] = 0; - i ++; - } - - if (*nameptr) - return (NULL); - - DEBUG_puts("httpGetHostByName: returning IPv6 address..."); - - return (&cg->hostent); - } -#endif /* AF_INET6 */ for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); @@ -404,8 +327,8 @@ httpGetHostByName(const char *name) /* I - Hostname or IP address */ if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) return (NULL); /* Invalid byte ranges! */ - cg->ip_addrs[0][0] = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | - ip[3])); + cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | + ip[3])); /* * Fill in the host entry and return it... @@ -416,117 +339,17 @@ httpGetHostByName(const char *name) /* I - Hostname or IP address */ cg->hostent.h_addrtype = AF_INET; cg->hostent.h_length = 4; cg->hostent.h_addr_list = cg->ip_ptrs; - cg->ip_ptrs[0] = (char *)cg->ip_addrs[0]; - cg->ip_ptrs[1] = NULL; + cg->ip_ptrs[0] = (char *)&(cg->ip_addr); + cg->ip_ptrs[1] = NULL; DEBUG_puts("httpGetHostByName: returning IPv4 address..."); return (&cg->hostent); } else -#ifdef HAVE_GETADDRINFO { /* - * Use the getaddrinfo() function to get the IP address for the - * name... - */ - - struct addrinfo hints, /* Address lookup hints */ - *results, /* Address lookup results */ - *current; /* Current result */ - http_addr_t *address; /* Current address */ - - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_CANONNAME; - - if (getaddrinfo(name, NULL, &hints, &results)) - { - /* - * If getaddrinfo() fails, try gethostbyname()... - */ - - return (gethostbyname(name)); - } - - /* - * Initialize hostent structure, preferring the IPv6 address... - */ - - for (current = results; current; current = current->ai_next) - if (current->ai_family == AF_INET6) - break; - - if (!current) - { - for (current = results; current; current = current->ai_next) - if (current->ai_family == AF_INET) - break; - - if (!current) - { - /* - * No IPv4 or IPv6 addresses, try gethostbyname()... - */ - - freeaddrinfo(results); - - return (gethostbyname(name)); - } - } - - strlcpy(cg->hostname, current->ai_canonname, sizeof(cg->hostname)); - - cg->hostent.h_name = cg->hostname; - cg->hostent.h_aliases = NULL; - cg->hostent.h_addrtype = current->ai_family; - cg->hostent.h_addr_list = cg->ip_ptrs; - - if (current->ai_family == AF_INET6) - cg->hostent.h_length = 16; - else - cg->hostent.h_length = 4; - - /* - * Convert the address info to a hostent structure... - */ - - for (i = 0, current = results; - i < CUPS_MAX_ADDRS && current; - current = current->ai_next) - if (current->ai_family == cg->hostent.h_addrtype) - { - /* - * Copy this address... - */ - - address = (http_addr_t *)(current->ai_addr); - - if (current->ai_family == AF_INET) - memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv4.sin_addr), 4); - else - memcpy((char *)cg->ip_addrs[i], (char *)&(address->ipv6.sin6_addr), 16); - - cg->ip_ptrs[i] = (char *)cg->ip_addrs[i]; - i ++; - } - - cg->ip_ptrs[i] = NULL; - - /* - * Free the getaddrinfo() results and return the hostent structure... - */ - - freeaddrinfo(results); - - return (&cg->hostent); - } -#else - { - /* - * Use the gethostbyname() function to get the IP address for + * Use the gethostbyname() function to get the IPv4 address for * the name... */ @@ -534,7 +357,6 @@ httpGetHostByName(const char *name) /* I - Hostname or IP address */ return (gethostbyname(name)); } -#endif /* HAVE_GETADDRINFO */ } @@ -543,6 +365,8 @@ httpGetHostByName(const char *name) /* I - Hostname or IP address */ * * This function uses both gethostname() and gethostbyname() to * get the local hostname with domain. + * + * @since CUPS 1.2@ */ const char * /* O - FQDN for this system */ diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c new file mode 100644 index 000000000..2e8f8b3da --- /dev/null +++ b/cups/http-addrlist.c @@ -0,0 +1,380 @@ +/* + * "$Id$" + * + * HTTP address list routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 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 + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include "http-private.h" + + +/* + * 'httpAddrConnect()' - Connect to any of the addresses in the list. + * + * @since CUPS 1.2@ + */ + +http_addrlist_t * /* O - Connected address or NULL on failure */ +httpAddrConnect( + http_addrlist_t *addrlist, /* I - List of potential addresses */ + int *sock) /* O - Socket */ +{ + int val; /* Socket option value */ + + + /* + * Loop through each address until we connect or run out of addresses... + */ + + while (addrlist) + { + /* + * Create the socket... + */ + + if ((*sock = socket(addrlist->addr.addr.sa_family, SOCK_STREAM, 0)) < 0) + { + /* + * Don't abort yet, as this could just be an issue with the local + * system not being configured with IPv4/IPv6/domain socket enabled... + */ + + addrlist = addrlist->next; + continue; + } + + /* + * Set options... + */ + + val = 1; + setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + +#ifdef SO_REUSEPORT + val = 1; + setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); +#endif /* SO_REUSEPORT */ + + /* + * Using TCP_NODELAY improves responsiveness, especially on systems + * with a slow loopback interface... + */ + + val = 1; + setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + +#ifdef FD_CLOEXEC + /* + * Close this socket when starting another process... + */ + + fcntl(*sock, F_SETFD, FD_CLOEXEC); +#endif /* FD_CLOEXEC */ + + /* + * Then connect... + */ + + if (!connect(*sock, &(addrlist->addr.addr), + httpAddrLength(&(addrlist->addr)))) + break; + + /* + * Close this socket and move to the next address... + */ + + closesocket(*sock); + + addrlist = addrlist->next; + } + + return (addrlist); +} + + +/* + * 'httpAddrFreeList()' - Free an address list. + * + * @since CUPS 1.2@ + */ + +void +httpAddrFreeList( + http_addrlist_t *addrlist) /* I - Address list to free */ +{ + http_addrlist_t *next; /* Next address in list */ + + + /* + * Free each address in the list... + */ + + while (addrlist) + { + next = addrlist->next; + + free(addrlist); + + addrlist = next; + } +} + + +/* + * 'httpAddrGetList()' - Get a list of address for a hostname. + * + * @since CUPS 1.2@ + */ + +http_addrlist_t * /* O - List of addresses or NULL */ +httpAddrGetList(const char *hostname, /* I - Hostname or IP address */ + int family, /* I - Address family or AF_UNSPEC */ + const char *service) /* I - Service name or port number */ +{ + http_addrlist_t *first, /* First address in list */ + *addr, /* Current address in list */ + *temp; /* New address */ + + + DEBUG_printf(("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n", + hostname, family == AF_UNSPEC ? "UNSPEC" : +#ifdef AF_LOCAL + family == AF_LOCAL ? "LOCAL" : +#endif /* AF_LOCAL */ +#ifdef AF_INET6 + family == AF_INET6 ? "INET6" : +#endif /* AF_INET6 */ + family == AF_INET ? "INET" : "???", service)); + + /* + * Avoid lookup delays and configuration problems when connecting + * to the localhost address... + */ + + if (!strcmp(hostname, "localhost")) + hostname = "127.0.0.1"; + + /* + * Lookup the address the best way we can... + */ + + first = addr = NULL; + + if (hostname[0] == '/') + { + /* + * 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)); + } + else + { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, /* Address lookup hints */ + *results, /* Address lookup results */ + *current; /* Current result */ + + + + /* + * Lookup the address as needed... + */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + + if (!getaddrinfo(hostname, service, &hints, &results)) + { + /* + * Copy the results to our own address list structure... + */ + + for (current = results; current; current = current->ai_next) + if (current->ai_family == AF_INET || current->ai_family == AF_INET6) + { + /* + * Copy the address over... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + if (current->ai_family == AF_INET6) + memcpy(&(temp->addr.ipv6), current->ai_addr, + sizeof(temp->addr.ipv6)); + else + memcpy(&(temp->addr.ipv4), current->ai_addr, + sizeof(temp->addr.ipv4)); + + /* + * Append the address to the list... + */ + + if (!first) + first = temp; + + if (addr) + addr->next = temp; + + addr = temp; + } + + /* + * Free the results from getaddrinfo()... + */ + + freeaddrinfo(results); + } +#else + int i; /* Looping vars */ + unsigned ip[4]; /* IPv4 address components */ + const char *ptr; /* Pointer into hostname */ + struct hostent *host; /* Result of lookup */ + struct servent *port; /* Port number for service */ + int portnum; /* Port number */ + + + /* + * Lookup the service... + */ + + if (!service) + portnum = 0; + else if (isdigit(*service & 255)) + portnum = atoi(service); + else if ((port = getservbyname(service, NULL)) != NULL) + portnum = ntohs(port->s_port); + else + return (NULL); + + /* + * This code is needed because some operating systems have a + * buggy implementation of gethostbyname() that does not support + * IPv4 addresses. If the hostname string is an IPv4 address, then + * sscanf() is used to extract the IPv4 components. We then pack + * the components into an IPv4 address manually, since the + * inet_aton() function is deprecated. We use the htonl() macro + * to get the right byte order for the address. + */ + + for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); + + if (!*nameptr) + { + /* + * We have an IPv4 address; break it up and create an IPv4 address... + */ + + if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && + ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) + { + first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!first) + return (NULL); + + first->addr.ipv4.sin_family = AF_INET; + first->addr.ipv4.sin_addr.s_addr = htonl(((((((ip[0] << 8) | + ip[1]) << 8) | + ip[2]) << 8) | ip[3])); + first->addr.ipv4.sin_port = htons(portnum); + } + } + else if ((host = gethostbyname(hostname)) != NULL && +#ifdef AF_INET6 + (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) +#else + host->h_addrtype == AF_INET) +#endif /* AF_INET6 */ + { + for (i = 0; host->h_addr_list[i]; i ++) + { + /* + * Copy the address over... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + +#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], + 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], + sizeof(temp->addr.ipv4)); + temp->addr.ipv4.sin_port = htons(portnum); + } + + /* + * Append the address to the list... + */ + + if (!first) + first = temp; + + if (addr) + addr->next = temp; + + addr = temp; + } + } +#endif /* HAVE_GETADDRINFO */ + } + + /* + * Return the address list... + */ + + return (first); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/http-private.h b/cups/http-private.h index 1ea15f2ba..c8dc6d432 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -33,6 +33,16 @@ # include "config.h" +# ifdef WIN32 +# include +# include +# else +# include +# include +# include +# define closesocket(f) close(f) +# endif /* WIN32 */ + # ifdef __sun /* * Define FD_SETSIZE to CUPS_MAX_FDS on Solaris to get the correct version of diff --git a/cups/http.c b/cups/http.c index f48dc4081..b6ce8fe8f 100644 --- a/cups/http.c +++ b/cups/http.c @@ -235,6 +235,8 @@ httpClose(http_t *http) /* I - Connection to close */ if (!http) return; + httpAddrFreeList(http->addrlist); + if (http->input_set) free(http->input_set); @@ -290,9 +292,9 @@ httpConnectEncrypt( int port, /* I - Port number */ http_encryption_t encryption) /* I - Type of encryption to use */ { - int i; /* Looping var */ http_t *http; /* New HTTP connection */ - struct hostent *hostaddr; /* Host address data */ + http_addrlist_t *addrlist; /* Host address data */ + char service[255]; /* Service name */ DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)\n", @@ -307,31 +309,9 @@ httpConnectEncrypt( * Lookup the host... */ - if ((hostaddr = httpGetHostByName(host)) == NULL) - { - /* - * This hack to make users that don't have a localhost entry in - * their hosts file or DNS happy... - */ - - if (strcasecmp(host, "localhost") != 0) - return (NULL); - else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL) - return (NULL); - } + sprintf(service, "%d", port); - /* - * Verify that it is an IPv4, IPv6, or domain address... - */ - - if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4) -#ifdef AF_INET6 - && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16) -#endif /* AF_INET6 */ -#ifdef AF_LOCAL - && (hostaddr->h_addrtype != AF_LOCAL) -#endif /* AF_LOCAL */ - ) + if ((addrlist = httpAddrGetList(host, AF_UNSPEC, service)) == NULL) return (NULL); /* @@ -362,27 +342,23 @@ httpConnectEncrypt( strlcpy(http->hostname, host, sizeof(http->hostname)); - for (i = 0; hostaddr->h_addr_list[i]; i ++) - { - /* - * Load the address... - */ - - httpAddrLoad(hostaddr, port, i, &(http->hostaddr)); + /* + * Connect to the remote system... + */ - /* - * Connect to the remote system... - */ + http->addrlist = addrlist; - if (!httpReconnect(http)) - return (http); - } + if (!httpReconnect(http)) + return (http); /* * Could not connect to any known address - bail out! */ + httpAddrFreeList(addrlist); + free(http); + return (NULL); } @@ -1532,8 +1508,7 @@ httpRead(http_t *http, /* I - HTTP data */ int /* O - 0 on success, non-zero on failure */ httpReconnect(http_t *http) /* I - HTTP data */ { - int val; /* Socket option value */ - int status; /* Connect status */ + http_addrlist_t *addr; /* Connected address */ DEBUG_printf(("httpReconnect(http=%p)\n", http)); @@ -1557,69 +1532,16 @@ httpReconnect(http_t *http) /* I - HTTP data */ close(http->fd); #endif /* WIN32 */ - /* - * Create the socket and set options to allow reuse. - */ - - if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0) - { -#ifdef WIN32 - http->error = WSAGetLastError(); -#else - http->error = errno; -#endif /* WIN32 */ - http->status = HTTP_ERROR; - return (-1); - } - -#ifdef FD_CLOEXEC - fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting * - * other processes... */ -#endif /* FD_CLOEXEC */ - - val = 1; - setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); - -#ifdef SO_REUSEPORT - val = 1; - setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); -#endif /* SO_REUSEPORT */ - - /* - * Using TCP_NODELAY improves responsiveness, especially on systems - * with a slow loopback interface... Since we write large buffers - * when sending print files and requests, there shouldn't be any - * performance penalty for this... - */ - - val = 1; -#ifdef WIN32 - setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); -#else - setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); -#endif /* WIN32 */ - /* * Connect to the server... */ -#ifdef AF_INET6 - if (http->hostaddr.addr.sa_family == AF_INET6) - status = connect(http->fd, (struct sockaddr *)&(http->hostaddr), - sizeof(http->hostaddr.ipv6)); - else -#endif /* AF_INET6 */ -#ifdef AF_LOCAL - if (http->hostaddr.addr.sa_family == AF_LOCAL) - status = connect(http->fd, (struct sockaddr *)&(http->hostaddr), - SUN_LEN(&(http->hostaddr.un))); - else -#endif /* AF_LOCAL */ - status = connect(http->fd, (struct sockaddr *)&(http->hostaddr), - sizeof(http->hostaddr.ipv4)); - - if (status < 0) + if ((addr = httpAddrConnect(http->addrlist, &(http->fd))) == NULL) { + /* + * Unable to connect... + */ + #ifdef WIN32 http->error = WSAGetLastError(); #else @@ -1627,19 +1549,12 @@ httpReconnect(http_t *http) /* I - HTTP data */ #endif /* WIN32 */ http->status = HTTP_ERROR; -#ifdef WIN32 - closesocket(http->fd); -#else - close(http->fd); -#endif - - http->fd = -1; - return (-1); } - http->error = 0; - http->status = HTTP_CONTINUE; + http->hostaddr = &(addr->addr); + http->error = 0; + http->status = HTTP_CONTINUE; #ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPT_ALWAYS) diff --git a/cups/http.h b/cups/http.h index 23151a598..6ad56420e 100644 --- a/cups/http.h +++ b/cups/http.h @@ -74,7 +74,7 @@ extern "C" { * core structure and union names, so the same defines or code * can't be used on all platforms. * - * The following will likely need tweeking on new platforms that + * The following will likely need tweaking on new platforms that * support IPv6 - the "s6_addr32" define maps to the 32-bit integer * array in the in6_addr union, which is named differently on various * platforms. @@ -100,186 +100,152 @@ extern "C" { /* - * HTTP state values... + * Types and structures... */ -typedef enum /* States are server-oriented */ +typedef enum http_state_e /**** HTTP state values; states + **** are server-oriented... + ****/ { - HTTP_WAITING, /* Waiting for command */ - HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */ - HTTP_GET, /* GET command, waiting for blank line */ - HTTP_GET_SEND, /* GET command, sending data */ - HTTP_HEAD, /* HEAD command, waiting for blank line */ - HTTP_POST, /* POST command, waiting for blank line */ - HTTP_POST_RECV, /* POST command, receiving data */ - HTTP_POST_SEND, /* POST command, sending data */ - HTTP_PUT, /* PUT command, waiting for blank line */ - HTTP_PUT_RECV, /* PUT command, receiving data */ - HTTP_DELETE, /* DELETE command, waiting for blank line */ - HTTP_TRACE, /* TRACE command, waiting for blank line */ - HTTP_CLOSE, /* CLOSE command, waiting for blank line */ - HTTP_STATUS /* Command complete, sending status */ + HTTP_WAITING, /* Waiting for command */ + HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */ + HTTP_GET, /* GET command, waiting for blank line */ + HTTP_GET_SEND, /* GET command, sending data */ + HTTP_HEAD, /* HEAD command, waiting for blank line */ + HTTP_POST, /* POST command, waiting for blank line */ + HTTP_POST_RECV, /* POST command, receiving data */ + HTTP_POST_SEND, /* POST command, sending data */ + HTTP_PUT, /* PUT command, waiting for blank line */ + HTTP_PUT_RECV, /* PUT command, receiving data */ + HTTP_DELETE, /* DELETE command, waiting for blank line */ + HTTP_TRACE, /* TRACE command, waiting for blank line */ + HTTP_CLOSE, /* CLOSE command, waiting for blank line */ + HTTP_STATUS /* Command complete, sending status */ } http_state_t; - -/* - * HTTP version numbers... - */ - -typedef enum +typedef enum http_version_e /**** HTTP version numbers ****/ { - HTTP_0_9 = 9, /* HTTP/0.9 */ - HTTP_1_0 = 100, /* HTTP/1.0 */ - HTTP_1_1 = 101 /* HTTP/1.1 */ + HTTP_0_9 = 9, /* HTTP/0.9 */ + HTTP_1_0 = 100, /* HTTP/1.0 */ + HTTP_1_1 = 101 /* HTTP/1.1 */ } http_version_t; - -/* - * HTTP keep-alive values... - */ - -typedef enum +typedef enum http_keepalive_e /**** HTTP keep-alive values ****/ { - HTTP_KEEPALIVE_OFF = 0, - HTTP_KEEPALIVE_ON + HTTP_KEEPALIVE_OFF = 0, /* No keep alive support */ + HTTP_KEEPALIVE_ON /* Use keep alive */ } http_keepalive_t; - -/* - * HTTP transfer encoding values... - */ - -typedef enum +typedef enum http_encoding_e /**** HTTP transfer encoding values ****/ { - HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */ - HTTP_ENCODE_CHUNKED /* Data is chunked */ + HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */ + HTTP_ENCODE_CHUNKED /* Data is chunked */ } http_encoding_t; - -/* - * HTTP encryption values... - */ - -typedef enum +typedef enum http_encryption_e /**** HTTP encryption values ****/ { - HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */ - HTTP_ENCRYPT_NEVER, /* Never encrypt */ - HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */ - HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */ + HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */ + HTTP_ENCRYPT_NEVER, /* Never encrypt */ + HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */ + HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */ } http_encryption_t; - -/* - * HTTP authentication types... - */ - -typedef enum +typedef enum http_auth_e /**** HTTP authentication types ****/ { - HTTP_AUTH_NONE, /* No authentication in use */ - HTTP_AUTH_BASIC, /* Basic authentication in use */ - HTTP_AUTH_MD5, /* Digest authentication in use */ - HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ - HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ - HTTP_AUTH_MD5_SESS_INT /* MD5-session authentication in use for body */ + HTTP_AUTH_NONE, /* No authentication in use */ + HTTP_AUTH_BASIC, /* Basic authentication in use */ + HTTP_AUTH_MD5, /* Digest authentication in use */ + HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ + HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ + HTTP_AUTH_MD5_SESS_INT /* MD5-session authentication in use for body */ } http_auth_t; - -/* - * HTTP status codes... - */ - -typedef enum +typedef enum http_status_e /**** HTTP status codes ****/ { - HTTP_ERROR = -1, /* An error response from httpXxxx() */ - - HTTP_CONTINUE = 100, /* Everything OK, keep going... */ - HTTP_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */ - - HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ - HTTP_CREATED, /* PUT command was successful */ - HTTP_ACCEPTED, /* DELETE command was successful */ - HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */ - HTTP_NO_CONTENT, /* Successful command, no new data */ - HTTP_RESET_CONTENT, /* Content was reset/recreated */ - HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */ - - HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */ - HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */ - HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */ - HTTP_SEE_OTHER, /* See this other link... */ - HTTP_NOT_MODIFIED, /* File not modified */ - HTTP_USE_PROXY, /* Must use a proxy to access this URI */ - - HTTP_BAD_REQUEST = 400, /* Bad request */ - HTTP_UNAUTHORIZED, /* Unauthorized to access host */ - HTTP_PAYMENT_REQUIRED, /* Payment required */ - HTTP_FORBIDDEN, /* Forbidden to access this URI */ - HTTP_NOT_FOUND, /* URI was not found */ - HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */ - HTTP_NOT_ACCEPTABLE, /* Not Acceptable */ - HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ - HTTP_REQUEST_TIMEOUT, /* Request timed out */ - HTTP_CONFLICT, /* Request is self-conflicting */ - HTTP_GONE, /* Server has gone away */ - HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */ - HTTP_PRECONDITION, /* Precondition failed */ - HTTP_REQUEST_TOO_LARGE, /* Request entity too large */ - HTTP_URI_TOO_LONG, /* URI too long */ - HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ - HTTP_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */ - - HTTP_SERVER_ERROR = 500, /* Internal server error */ - HTTP_NOT_IMPLEMENTED, /* Feature not implemented */ - HTTP_BAD_GATEWAY, /* Bad gateway */ - HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */ - HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */ - HTTP_NOT_SUPPORTED /* HTTP version not supported */ + HTTP_ERROR = -1, /* An error response from httpXxxx() */ + + HTTP_CONTINUE = 100, /* Everything OK, keep going... */ + HTTP_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */ + + HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ + HTTP_CREATED, /* PUT command was successful */ + HTTP_ACCEPTED, /* DELETE command was successful */ + HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */ + HTTP_NO_CONTENT, /* Successful command, no new data */ + HTTP_RESET_CONTENT, /* Content was reset/recreated */ + HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */ + + HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */ + HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */ + HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */ + HTTP_SEE_OTHER, /* See this other link... */ + HTTP_NOT_MODIFIED, /* File not modified */ + HTTP_USE_PROXY, /* Must use a proxy to access this URI */ + + HTTP_BAD_REQUEST = 400, /* Bad request */ + HTTP_UNAUTHORIZED, /* Unauthorized to access host */ + HTTP_PAYMENT_REQUIRED, /* Payment required */ + HTTP_FORBIDDEN, /* Forbidden to access this URI */ + HTTP_NOT_FOUND, /* URI was not found */ + HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */ + HTTP_NOT_ACCEPTABLE, /* Not Acceptable */ + HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ + HTTP_REQUEST_TIMEOUT, /* Request timed out */ + HTTP_CONFLICT, /* Request is self-conflicting */ + HTTP_GONE, /* Server has gone away */ + HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */ + HTTP_PRECONDITION, /* Precondition failed */ + HTTP_REQUEST_TOO_LARGE, /* Request entity too large */ + HTTP_URI_TOO_LONG, /* URI too long */ + HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ + HTTP_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */ + + HTTP_SERVER_ERROR = 500, /* Internal server error */ + HTTP_NOT_IMPLEMENTED, /* Feature not implemented */ + HTTP_BAD_GATEWAY, /* Bad gateway */ + HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */ + HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */ + HTTP_NOT_SUPPORTED /* HTTP version not supported */ } http_status_t; - -/* - * HTTP field names... - */ - -typedef enum +typedef enum http_field_e /**** HTTP field names ****/ { - HTTP_FIELD_UNKNOWN = -1, - HTTP_FIELD_ACCEPT_LANGUAGE, - HTTP_FIELD_ACCEPT_RANGES, - HTTP_FIELD_AUTHORIZATION, - HTTP_FIELD_CONNECTION, - HTTP_FIELD_CONTENT_ENCODING, - HTTP_FIELD_CONTENT_LANGUAGE, - HTTP_FIELD_CONTENT_LENGTH, - HTTP_FIELD_CONTENT_LOCATION, - HTTP_FIELD_CONTENT_MD5, - HTTP_FIELD_CONTENT_RANGE, - HTTP_FIELD_CONTENT_TYPE, - HTTP_FIELD_CONTENT_VERSION, - HTTP_FIELD_DATE, - HTTP_FIELD_HOST, - HTTP_FIELD_IF_MODIFIED_SINCE, - HTTP_FIELD_IF_UNMODIFIED_SINCE, - HTTP_FIELD_KEEP_ALIVE, - HTTP_FIELD_LAST_MODIFIED, - HTTP_FIELD_LINK, - HTTP_FIELD_LOCATION, - HTTP_FIELD_RANGE, - HTTP_FIELD_REFERER, - HTTP_FIELD_RETRY_AFTER, - HTTP_FIELD_TRANSFER_ENCODING, - HTTP_FIELD_UPGRADE, - HTTP_FIELD_USER_AGENT, - HTTP_FIELD_WWW_AUTHENTICATE, - HTTP_FIELD_MAX + HTTP_FIELD_UNKNOWN = -1, /* Unknown field */ + HTTP_FIELD_ACCEPT_LANGUAGE, /* Accept-Language field */ + HTTP_FIELD_ACCEPT_RANGES, /* Accept-Ranges field */ + HTTP_FIELD_AUTHORIZATION, /* Authorization field */ + HTTP_FIELD_CONNECTION, /* Connection field */ + HTTP_FIELD_CONTENT_ENCODING, /* Content-Encoding field */ + HTTP_FIELD_CONTENT_LANGUAGE, /* Content-Language field */ + HTTP_FIELD_CONTENT_LENGTH, /* Content-Length field */ + HTTP_FIELD_CONTENT_LOCATION, /* Content-Location field */ + HTTP_FIELD_CONTENT_MD5, /* Content-MD5 field */ + HTTP_FIELD_CONTENT_RANGE, /* Content-Range field */ + HTTP_FIELD_CONTENT_TYPE, /* Content-Type field */ + HTTP_FIELD_CONTENT_VERSION, /* Content-Version field */ + HTTP_FIELD_DATE, /* Date field */ + HTTP_FIELD_HOST, /* Host field */ + HTTP_FIELD_IF_MODIFIED_SINCE, /* If-Modified-Since field */ + HTTP_FIELD_IF_UNMODIFIED_SINCE, /* If-Unmodified-Since field */ + HTTP_FIELD_KEEP_ALIVE, /* Keep-Alive field */ + HTTP_FIELD_LAST_MODIFIED, /* Last-Modified field */ + HTTP_FIELD_LINK, /* Link field */ + HTTP_FIELD_LOCATION, /* Location field */ + HTTP_FIELD_RANGE, /* Range field */ + HTTP_FIELD_REFERER, /* Referer field */ + HTTP_FIELD_RETRY_AFTER, /* Retry-After field */ + HTTP_FIELD_TRANSFER_ENCODING, /* Transfer-Encoding field */ + HTTP_FIELD_UPGRADE, /* Upgrade field */ + HTTP_FIELD_USER_AGENT, /* User-Agent field */ + HTTP_FIELD_WWW_AUTHENTICATE, /* WWW-Authenticate field */ + HTTP_FIELD_MAX /* Maximum field index */ } http_field_t; - -/* - * HTTP address structure (makes using IPv6 a little easier and more portable.) - */ - -typedef union +typedef union http_addr_u /**** Socket address union, which + **** makes using IPv6 and other + **** address types easier and + **** more portable. @since CUPS 1.2@ + ****/ { struct sockaddr addr; /* Base structure for family value */ struct sockaddr_in ipv4; /* IPv4 address */ @@ -289,14 +255,20 @@ typedef union #ifdef AF_LOCAL struct sockaddr_un un; /* Domain socket file */ #endif /* AF_LOCAL */ - char pad[128]; /* Pad to ensure binary compatibility */ + char pad[256]; /* Padding to ensure binary compatibility */ } http_addr_t; -/* - * HTTP connection structure... - */ +typedef struct http_addrlist_s /**** Socket address list, which is + **** used to enumerate all of the + **** addresses that are associated + **** with a hostname. @since CUPS 1.2@ + ****/ +{ + struct http_addrlist_s *next; /* Pointer to next address in list */ + http_addr_t addr; /* Address */ +} http_addrlist_t; -typedef struct +typedef struct http_s /**** HTTP connection structure. ****/ { int fd; /* File descriptor for this socket */ int blocking; /* To block or not to block */ @@ -306,14 +278,14 @@ typedef struct http_status_t status; /* Status of last request */ http_version_t version; /* Protocol version */ http_keepalive_t keep_alive; /* Keep-alive supported? */ - struct sockaddr_in oldaddr; /* Address of connected host */ + struct sockaddr_in _hostaddr; /* Address of connected host @deprecated@ */ char hostname[HTTP_MAX_HOST], /* Name of connected host */ fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE]; /* Field values */ char *data; /* Pointer to data buffer */ http_encoding_t data_encoding; /* Chunked or not */ - int _data_remaining;/* Number of bytes left (deprecated) */ + int _data_remaining;/* Number of bytes left @deprecated@ */ int used; /* Number of bytes used in buffer */ char buffer[HTTP_MAX_BUFFER]; /* Buffer for incoming data */ @@ -327,23 +299,22 @@ typedef struct void *tls; /* TLS state information */ http_encryption_t encryption; /* Encryption requirements */ /**** New in CUPS 1.1.19 ****/ - fd_set *input_set; /* select() set for httpWait() */ - http_status_t expect; /* Expect: header */ - char *cookie; /* Cookie value(s) */ + fd_set *input_set; /* select() set for httpWait() @since CUPS 1.1.19@ */ + http_status_t expect; /* Expect: header @since CUPS 1.1.19@ */ + char *cookie; /* Cookie value(s) @since CUPS 1.1.19@ */ /**** New in CUPS 1.1.20 ****/ char authstring[HTTP_MAX_VALUE], - /* Current Authentication value */ + /* Current Authentication value @since CUPS 1.1.20@ */ userpass[HTTP_MAX_VALUE]; - /* Username:password string */ - int digest_tries; /* Number of tries for digest auth */ + /* Username:password string @since CUPS 1.1.20@ */ + int digest_tries; /* Number of tries for digest auth @since CUPS 1.1.20@ */ /**** New in CUPS 1.2 ****/ - http_addr_t hostaddr; /* Host address and port */ - int wused; /* Write buffer bytes used */ - off_t data_remaining; /* Number of bytes left */ + http_addr_t *hostaddr; /* Current host address and port @since CUPS 1.2@ */ + http_addrlist_t *addrlist; /* List of valid addresses @since CUPS 1.2@ */ + int wused; /* Write buffer bytes used @since CUPS 1.2@ */ + off_t data_remaining; /* Number of bytes left @since CUPS 1.2@ */ } http_t; -/**** New in CUPS 1.1.20+ ****/ -extern int httpWriteFlush(http_t *http); /* * Prototypes... @@ -417,11 +388,13 @@ extern void httpSeparate2(const char *uri, /**** New in CUPS 1.2 ****/ extern int httpAddrAny(const http_addr_t *addr); +extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock); extern int httpAddrEqual(const http_addr_t *addr1, const http_addr_t *addr2); +extern void httpAddrFreeList(http_addrlist_t *addrlist); +extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, + const char *service); extern int httpAddrLength(const http_addr_t *addr); -extern void httpAddrLoad(const struct hostent *host, int port, - int n, http_addr_t *addr); extern int httpAddrLocalhost(const http_addr_t *addr); extern char *httpAddrLookup(const http_addr_t *addr, char *name, int namelen); diff --git a/cups/util.c b/cups/util.c index 35d8d0eb8..adcfbc2ac 100644 --- a/cups/util.c +++ b/cups/util.c @@ -1089,12 +1089,12 @@ cupsGetPPD2(http_t *http, /* I - HTTP connection */ */ #ifdef AF_INET6 - if (http->hostaddr.addr.sa_family == AF_INET6) - http_port = ntohs(http->hostaddr.ipv6.sin6_port); + if (http->hostaddr->addr.sa_family == AF_INET6) + http_port = ntohs(http->hostaddr->ipv6.sin6_port); else #endif /* AF_INET6 */ - if (http->hostaddr.addr.sa_family == AF_INET) - http_port = ntohs(http->hostaddr.ipv4.sin_port); + if (http->hostaddr->addr.sa_family == AF_INET) + http_port = ntohs(http->hostaddr->ipv4.sin_port); else http_port = ippPort(); diff --git a/scheduler/auth.c b/scheduler/auth.c index e576b3f00..a14439a54 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -1113,20 +1113,20 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ */ #ifdef AF_INET6 - if (con->http.hostaddr.addr.sa_family == AF_INET6) + if (con->http.hostaddr->addr.sa_family == AF_INET6) { /* * Copy IPv6 address... */ - address[0] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[0]); - address[1] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[1]); - address[2] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[2]); - address[3] = ntohl(con->http.hostaddr.ipv6.sin6_addr.s6_addr32[3]); + address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]); + address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]); + address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]); + address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]); } else #endif /* AF_INET6 */ - if (con->http.hostaddr.addr.sa_family == AF_INET) + if (con->http.hostaddr->addr.sa_family == AF_INET) { /* * Copy IPv4 address... @@ -1135,7 +1135,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ address[0] = 0; address[1] = 0; address[2] = 0; - address[3] = ntohl(con->http.hostaddr.ipv4.sin_addr.s_addr); + address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr); } else memset(address, 0, sizeof(address)); diff --git a/scheduler/client.c b/scheduler/client.c index b7ac039d9..703a62b12 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -86,7 +86,8 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ int count; /* Count of connections on a host */ int val; /* Parameter value */ cupsd_client_t *con; /* New client pointer */ - const struct hostent *host; /* Host entry for address */ + http_addrlist_t *addrlist, /* List of adddresses for host */ + *addr; /* Current address */ char *hostname; /* Hostname for address */ http_addr_t temp; /* Temporary address variable */ static time_t last_dos = 0; /* Time of last DoS attack */ @@ -112,6 +113,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ memset(con, 0, sizeof(cupsd_client_t)); con->http.activity = time(NULL); con->file = -1; + con->http.hostaddr = &(con->clientaddr); /* * Accept the client and get the remote address... @@ -119,7 +121,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ val = sizeof(struct sockaddr_in); - if ((con->http.fd = accept(lis->fd, (struct sockaddr *)&(con->http.hostaddr), + if ((con->http.fd = accept(lis->fd, (struct sockaddr *)con->http.hostaddr, &val)) < 0) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to accept client connection - %s.", @@ -129,18 +131,18 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ #ifdef AF_INET6 if (lis->address.addr.sa_family == AF_INET6) - con->http.hostaddr.ipv6.sin6_port = lis->address.ipv6.sin6_port; + con->http.hostaddr->ipv6.sin6_port = lis->address.ipv6.sin6_port; else #endif /* AF_INET6 */ if (lis->address.addr.sa_family == AF_INET) - con->http.hostaddr.ipv4.sin_port = lis->address.ipv4.sin_port; + con->http.hostaddr->ipv4.sin_port = lis->address.ipv4.sin_port; /* * Check the number of clients on the same address... */ for (i = 0, count = 0; i < NumClients; i ++) - if (httpAddrEqual(&(Clients[i].http.hostaddr), &(con->http.hostaddr))) + if (httpAddrEqual(Clients[i].http.hostaddr, con->http.hostaddr)) { count ++; if (count >= MaxClientsPerHost) @@ -170,7 +172,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Get the hostname or format the IP address as needed... */ - if (httpAddrLocalhost(&(con->http.hostaddr))) + if (httpAddrLocalhost(con->http.hostaddr)) { /* * Map accesses from the loopback interface to "localhost"... @@ -179,23 +181,30 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname)); hostname = con->http.hostname; } - else if (httpAddrEqual(&(con->http.hostaddr), &ServerAddr)) + else { /* * Map accesses from the same host to the server name. */ - strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname)); - hostname = con->http.hostname; - } - else if (HostNameLookups) - hostname = httpAddrLookup(&(con->http.hostaddr), con->http.hostname, - sizeof(con->http.hostname)); - else - { - hostname = NULL; - httpAddrString(&(con->http.hostaddr), con->http.hostname, - sizeof(con->http.hostname)); + for (addr = ServerAddrs; addr; addr = addr->next) + if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) + break; + + if (addr) + { + strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname)); + hostname = con->http.hostname; + } + else if (HostNameLookups) + hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, + sizeof(con->http.hostname)); + else + { + hostname = NULL; + httpAddrString(con->http.hostaddr, con->http.hostname, + sizeof(con->http.hostname)); + } } if (hostname == NULL && HostNameLookups == 2) @@ -226,40 +235,22 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ * Do double lookups as needed... */ - if ((host = httpGetHostByName(con->http.hostname)) != NULL) + if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) != NULL) { /* * See if the hostname maps to the same IP address... */ - if (host->h_addrtype != con->http.hostaddr.addr.sa_family) - { - /* - * Not the right type of address... - */ - - host = NULL; - } - else - { - /* - * Compare all of the addresses against this one... - */ - - for (i = 0; host->h_addr_list[i]; i ++) - { - httpAddrLoad(host, 0, i, &temp); - - if (httpAddrEqual(&(con->http.hostaddr), &temp)) - break; - } - - if (!host->h_addr_list[i]) - host = NULL; - } + for (addr = addrlist; addr; addr = addr->next) + if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) + break; } + else + addr = NULL; + + httpAddrFreeList(addrlist); - if (host == NULL) + if (!addr) { /* * Can't have a hostname that doesn't resolve to the same IP address @@ -284,21 +275,21 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ } #ifdef AF_INET6 - if (con->http.hostaddr.addr.sa_family == AF_INET6) + if (con->http.hostaddr->addr.sa_family == AF_INET6) cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv6)", con->http.fd, con->http.hostname, - ntohs(con->http.hostaddr.ipv6.sin6_port)); + ntohs(con->http.hostaddr->ipv6.sin6_port)); else #endif /* AF_INET6 */ #ifdef AF_LOCAL - if (con->http.hostaddr.addr.sa_family == AF_LOCAL) + if (con->http.hostaddr->addr.sa_family == AF_LOCAL) cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s (Domain)", con->http.fd, con->http.hostname); else #endif /* AF_LOCAL */ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv4)", con->http.fd, con->http.hostname, - ntohs(con->http.hostaddr.ipv4.sin_port)); + ntohs(con->http.hostaddr->ipv4.sin_port)); /* * Get the local address the client connected to... @@ -3265,7 +3256,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ strcpy(lang, "LANG=C"); strcpy(remote_addr, "REMOTE_ADDR="); - httpAddrString(&(con->http.hostaddr), remote_addr + 12, + httpAddrString(con->http.hostaddr, remote_addr + 12, sizeof(remote_addr) - 12); snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", diff --git a/scheduler/client.h b/scheduler/client.h index 1dce052a2..aa22b6536 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -52,6 +52,7 @@ struct cupsd_client_s #ifdef HAVE_SSL int auto_ssl; /* Automatic test for SSL/TLS */ #endif /* HAVE_SSL */ + http_addr_t clientaddr; /* Client address */ char servername[256];/* Server name for connection */ int serverport; /* Server port for connection */ }; @@ -83,13 +84,14 @@ VAR http_encryption_t LocalEncryption VALUE(HTTP_ENCRYPT_IF_REQUESTED); /* Local port encryption to use */ VAR int NumListeners VALUE(0); /* Number of listening sockets */ -VAR cupsd_listener_t *Listeners VALUE(NULL); +VAR cupsd_listener_t *Listeners VALUE(NULL); /* Listening sockets */ VAR int NumClients VALUE(0); /* Number of HTTP clients */ -VAR cupsd_client_t *Clients VALUE(NULL); +VAR cupsd_client_t *Clients VALUE(NULL); /* HTTP clients */ -VAR http_addr_t ServerAddr; /* Server address */ +VAR http_addrlist_t *ServerAddrs VALUE(NULL); + /* Server address(es) */ VAR char *ServerHeader VALUE(NULL); /* Server header in requests */ VAR int CGIPipes[2] VALUE2(-1,-1); diff --git a/scheduler/conf.c b/scheduler/conf.c index 741bd5860..59fa85808 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1035,11 +1035,11 @@ get_address(const char *value, /* I - Value string */ int deffamily, /* I - Default family */ http_addr_t *address) /* O - Socket address */ { - char hostname[256], /* Hostname or IP */ - portname[256], /* Port number or name */ - *ptr; /* Pointer into hostname string */ - struct hostent *host; /* Host address */ - struct servent *port; /* Port number */ + char hostname[1024], /* Hostname or IP */ + *portname; /* Port number or name */ + http_addrlist_t *addrlist; /* Address list */ + int portnum; /* Port number */ + struct servent *service; /* Service entry */ /* @@ -1103,24 +1103,22 @@ get_address(const char *value, /* I - Value string */ strlcpy(hostname, value, sizeof(hostname)); - if ((ptr = strrchr(hostname, ':')) != NULL) - { - /* - * Copy hostname and port separately... - */ - - *ptr++ = '\0'; - - strlcpy(portname, ptr, sizeof(portname)); - } + if ((portname = strrchr(hostname, ':')) != NULL) + *portname++ = '\0'; else if (isdigit(value[0] & 255)) { /* * Port number... */ - hostname[0] = '\0'; - strlcpy(portname, value, sizeof(portname)); +#ifdef AF_INET6 + if (deffamily == AF_INET6) + address->ipv6.sin6_port = htons(atoi(value)); + else +#endif /* AF_INET6 */ + address->ipv4.sin_port = htons(atoi(value)); + + return (1); } else { @@ -1128,7 +1126,7 @@ get_address(const char *value, /* I - Value string */ * Hostname by itself... */ - portname[0] = '\0'; + portname = NULL; } /* @@ -1137,45 +1135,46 @@ get_address(const char *value, /* I - Value string */ if (hostname[0] && strcmp(hostname, "*")) { - if ((host = httpGetHostByName(hostname)) == NULL) + if ((addrlist = httpAddrGetList(hostname, deffamily, portname)) == NULL) { - cupsdLogMessage(CUPSD_LOG_ERROR, "httpGetHostByName(\"%s\") failed - %s!", - hostname, hstrerror(h_errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed!", + hostname); return (0); } - httpAddrLoad(host, defport, 0, address); - } + memcpy(address, &(addrlist->addr), httpAddrLength(&(addrlist->addr))); - if (portname[0] != '\0') - { - if (isdigit(portname[0] & 255)) + if (!portname) { #ifdef AF_INET6 if (address->addr.sa_family == AF_INET6) - address->ipv6.sin6_port = htons(atoi(portname)); + address->ipv6.sin6_port = htons(atoi(value)); else #endif /* AF_INET6 */ - address->ipv4.sin_port = htons(atoi(portname)); + address->ipv4.sin_port = htons(atoi(value)); } + + httpAddrFreeList(addrlist); + } + else if (portname) + { + if (isdigit(*portname & 255)) + portnum = atoi(portname); + else if ((service = getservbyname(portname, NULL)) != NULL) + portnum = ntohs(service->s_port); else { - if ((port = getservbyname(portname, NULL)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "getservbyname(\"%s\") failed - %s!", - portname, strerror(errno)); - return (0); - } - else - { + cupsdLogMessage(CUPSD_LOG_ERROR, "Service lookup for \"%s\" failed!", + portname); + return (0); + } + #ifdef AF_INET6 - if (address->addr.sa_family == AF_INET6) - address->ipv6.sin6_port = htons(port->s_port); - else + if (deffamily == AF_INET6) + address->ipv6.sin6_port = htons(portnum); + else #endif /* AF_INET6 */ - address->ipv4.sin_port = htons(port->s_port); - } - } + address->ipv4.sin_port = htons(portnum); } return (1); diff --git a/scheduler/listen.c b/scheduler/listen.c index 45272d233..5faf5caa4 100644 --- a/scheduler/listen.c +++ b/scheduler/listen.c @@ -109,7 +109,6 @@ cupsdStartListening(void) p, /* Port number */ val; /* Parameter value */ cupsd_listener_t *lis; /* Current listening socket */ - struct hostent *host; /* Host entry for server address */ char s[256]; /* String addresss */ const char *have_domain; /* Have a domain socket? */ static const char * const encryptions[] = @@ -128,27 +127,18 @@ cupsdStartListening(void) * Get the server's IP address... */ - memset(&ServerAddr, 0, sizeof(ServerAddr)); + if (ServerAddrs) + httpAddrFreeList(ServerAddrs); - if ((host = httpGetHostByName(ServerName)) != NULL) - { - /* - * Found the server's address! - */ - - httpAddrLoad(host, 0, 0, &ServerAddr); - } - else + if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL) { /* * Didn't find it! Use an address of 0... */ cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdStartListening: Unable to find IP address for server name \"%s\" - %s\n", - ServerName, hstrerror(h_errno)); - - ServerAddr.ipv4.sin_family = AF_INET; + "cupsdStartListening: Unable to find IP address for server name \"%s\"!\n", + ServerName); } /* diff --git a/scheduler/network.c b/scheduler/network.c index f8fd6b379..8bc4bb088 100644 --- a/scheduler/network.c +++ b/scheduler/network.c @@ -143,6 +143,7 @@ cupsdNetIFUpdate(void) cupsd_netif_t *temp; /* Current interface */ struct ifaddrs *addrs, /* Interface address list */ *addr; /* Current interface address */ + http_addrlist_t *saddr; /* Current server address */ /* @@ -294,11 +295,18 @@ cupsdNetIFUpdate(void) if (httpAddrLocalhost(&(temp->address))) strcpy(temp->hostname, "localhost"); - else if (httpAddrEqual(&(temp->address), &ServerAddr)) - strlcpy(temp->hostname, ServerName, sizeof(temp->hostname)); else - httpAddrString(&(temp->address), temp->hostname, - sizeof(temp->hostname)); + { + for (saddr = ServerAddrs; saddr; saddr = saddr->next) + if (httpAddrEqual(&(temp->address), &(saddr->addr))) + break; + + if (saddr) + strlcpy(temp->hostname, ServerName, sizeof(temp->hostname)); + else + httpAddrString(&(temp->address), temp->hostname, + sizeof(temp->hostname)); + } } }