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 */
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 */
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...
*/
* 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)
* 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;
* 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);
* 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);
if (stat(filename, &filestats))
{
+ httpAddrFreeList(addrlist);
+ close(fd);
+
perror("ERROR: unable to stat print file");
return (CUPS_BACKEND_FAILED);
}
if ((fp = fopen(filename, "rb")) == NULL)
{
+ httpAddrFreeList(addrlist);
+ close(fd);
+
perror("ERROR: unable to open print file for reading");
return (CUPS_BACKEND_FAILED);
}
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,
{
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));
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);
{
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));
fclose(fp);
if (status == 0)
+ {
+ httpAddrFreeList(addrlist);
+
return (CUPS_BACKEND_OK);
+ }
/*
* Waiting for a retry...
sleep(30);
}
+ httpAddrFreeList(addrlist);
+
/*
* If we get here, then the job has been cancelled...
*/
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) */
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 */
* 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);
}
{
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)
{
close(fd);
}
+ httpAddrFreeList(addrlist);
+
/*
* Close the input file and return...
*/
globals.o \
http.o \
http-addr.o \
+ http-addrlist.o \
http-support.o \
ipp.o \
ipp-support.o \
* 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!");
#include <cups/debug.h>
#include <sys/types.h>
-#ifdef WIN32
-# include <io.h>
-# include <winsock2.h>
-#else
-# include <unistd.h>
-# include <fcntl.h>
-# include <sys/socket.h>
-# define closesocket(f) close(f)
-#endif /* WIN32 */
-
#include "file.h"
#ifdef HAVE_LIBZ
# include <zlib.h>
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 */
/*
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... */
# 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.
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 */
/* 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 */
*
* 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.
*/
/*
/*
* 'httpAddrAny()' - Check for the "any" address.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 1 if "any", 0 otherwise */
/*
* 'httpAddrEqual()' - Compare two addresses.
+ *
+ * @since CUPS 1.2@
*/
int /* O - 1 if equal, 0 if != */
/*
* 'httpAddrLength()' - Return the length of the address in bytes.
+ *
+ * @since CUPS 1.2@
*/
int /* O - Length in bytes */
}
-/*
- * '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 &&
/*
* 'httpAddrLookup()' - Lookup the hostname associated with the address.
+ *
+ * @since CUPS 1.2@
*/
char * /* O - Host name */
/*
* 'httpAddrString()' - Convert an IP address to a dotted string.
+ *
+ * @since CUPS 1.2@
*/
char * /* O - IP string */
/*
- * '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();
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 ++);
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...
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...
*/
return (gethostbyname(name));
}
-#endif /* HAVE_GETADDRINFO */
}
*
* 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 */
--- /dev/null
+/*
+ * "$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 <stdlib.h>
+#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$".
+ */
# include "config.h"
+# ifdef WIN32
+# include <io.h>
+# include <winsock2.h>
+# else
+# include <unistd.h>
+# include <fcntl.h>
+# include <sys/socket.h>
+# define closesocket(f) close(f)
+# endif /* WIN32 */
+
# ifdef __sun
/*
* Define FD_SETSIZE to CUPS_MAX_FDS on Solaris to get the correct version of
if (!http)
return;
+ httpAddrFreeList(http->addrlist);
+
if (http->input_set)
free(http->input_set);
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",
* 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);
/*
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);
}
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));
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
#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)
* 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.
/*
- * 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 */
#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 */
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 */
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...
/**** 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);
*/
#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();
*/
#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...
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));
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 */
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...
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.",
#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)
* 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"...
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)
* 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
}
#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...
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",
#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 */
};
/* 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);
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 */
/*
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
{
* Hostname by itself...
*/
- portname[0] = '\0';
+ portname = NULL;
}
/*
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);
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[] =
* 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);
}
/*
cupsd_netif_t *temp; /* Current interface */
struct ifaddrs *addrs, /* Interface address list */
*addr; /* Current interface address */
+ http_addrlist_t *saddr; /* Current server address */
/*
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));
+ }
}
}