/*
- * "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $"
+ * "$Id$"
*
- * Server listening routines for the Common UNIX Printing System (CUPS)
- * scheduler.
+ * Server listening routines for the CUPS scheduler.
*
- * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2013 by Apple Inc.
+ * Copyright 1997-2006 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:
- *
- * cupsdPauseListening() - Clear input polling on all listening sockets...
- * cupsdResumeListening() - Set input polling on all listening sockets...
- * cupsdStartListening() - Create all listening sockets...
- * cupsdStopListening() - Close all listening sockets...
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*/
/*
#endif /* __linux && !IPV6_V6ONLY */
+/*
+ * 'cupsdDeleteAllListeners()' - Delete all listeners.
+ */
+
+void
+cupsdDeleteAllListeners(void)
+{
+ cupsd_listener_t *lis; /* Current listening socket */
+
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ free(lis);
+
+ cupsArrayDelete(Listeners);
+ Listeners = NULL;
+}
+
+
/*
* 'cupsdPauseListening()' - Clear input polling on all listening sockets...
*/
void
cupsdPauseListening(void)
{
- int i; /* Looping var */
cupsd_listener_t *lis; /* Current listening socket */
- if (NumListeners < 1)
+ if (cupsArrayCount(Listeners) < 1)
return;
- if (NumClients == MaxClients)
+ if (cupsArrayCount(Clients) == MaxClients)
cupsdLogMessage(CUPSD_LOG_WARN,
"Max clients reached, holding new connections...");
+ else if (errno == ENFILE || errno == EMFILE)
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Too many open files, holding new connections for "
+ "30 seconds...");
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdPauseListening: Clearing input bits...");
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
- for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
- if (lis->fd >= 0)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdPauseListening: Removing fd %d from InputSet...",
- lis->fd);
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ cupsdRemoveSelect(lis->fd);
- FD_CLR(lis->fd, InputSet);
- }
+ ListeningPaused = time(NULL) + 30;
}
void
cupsdResumeListening(void)
{
- int i; /* Looping var */
cupsd_listener_t *lis; /* Current listening socket */
- if (NumListeners < 1)
+ if (cupsArrayCount(Listeners) < 1)
return;
- if (NumClients >= (MaxClients - 1))
- cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
+ cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdResumeListening: Setting input bits...");
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdResumeListening: Setting input bits...");
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
- for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
- if (lis->fd >= 0)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdResumeListening: Adding fd %d to InputSet...",
- lis->fd);
- FD_SET(lis->fd, InputSet);
- }
+ ListeningPaused = 0;
}
void
cupsdStartListening(void)
{
- int status; /* Bind result */
- int i, /* Looping var */
- p, /* Port number */
- val; /* Parameter value */
+ int p; /* Port number */
cupsd_listener_t *lis; /* Current listening socket */
char s[256]; /* String addresss */
const char *have_domain; /* Have a domain socket? */
};
- cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartListening: NumListeners=%d",
- NumListeners);
-
- /*
- * Get the server's IP address...
- */
-
- if (ServerAddrs)
- httpAddrFreeList(ServerAddrs);
-
- if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartListening: Unable to find IP address for "
- "server name \"%s\"!\n", ServerName);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
+ cupsArrayCount(Listeners));
/*
* Setup socket listeners...
*/
- for (i = NumListeners, lis = Listeners, LocalPort = 0, have_domain = NULL;
- i > 0; i --, lis ++)
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
+ have_domain = NULL;
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
httpAddrString(&(lis->address), s, sizeof(s));
-
-#ifdef AF_INET6
- if (lis->address.addr.sa_family == AF_INET6)
- p = ntohs(lis->address.ipv6.sin6_port);
- else
-#endif /* AF_INET6 */
-#ifdef AF_LOCAL
- if (lis->address.addr.sa_family == AF_LOCAL)
- p = 0;
- else
-#endif /* AF_LOCAL */
- p = ntohs(lis->address.ipv4.sin_port);
+ p = httpAddrPort(&(lis->address));
/*
- * Create a socket for listening...
+ * If needed, create a socket for listening...
*/
- lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
-
if (lis->fd == -1)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.",
- s, p, strerror(errno));
- continue;
- }
-
- fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
-
- /*
- * Set things up to reuse the local address for this port.
- */
-
- val = 1;
-#ifdef __sun
- setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
-#else
- setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-#endif /* __sun */
-
- /*
- * Bind to the port we found...
- */
-
-#ifdef AF_INET6
- if (lis->address.addr.sa_family == AF_INET6)
- {
-# ifdef IPV6_V6ONLY
/*
- * Accept only IPv6 connections on this socket, to avoid
- * potential security issues and to make all platforms behave
- * the same.
+ * Create a socket for listening...
*/
- val = 1;
-# ifdef __sun
- setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
-# else
- setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
-# endif /* __sun */
-# endif /* IPV6_V6ONLY */
+ lis->fd = httpAddrListen(&(lis->address), p);
- status = bind(lis->fd, (struct sockaddr *)&(lis->address),
- httpAddrLength(&(lis->address)));
- }
- else
-#endif /* AF_INET6 */
-#ifdef AF_LOCAL
- if (lis->address.addr.sa_family == AF_LOCAL)
- {
- mode_t mask; /* Umask setting */
-
-
- /*
- * Remove any existing domain socket file...
- */
-
- unlink(lis->address.un.sun_path);
-
- /*
- * Save the curent umask and set it to 0...
- */
-
- mask = umask(0);
-
- /*
- * Bind the domain socket...
- */
-
- status = bind(lis->fd, (struct sockaddr *)&(lis->address),
- httpAddrLength(&(lis->address)));
+ if (lis->fd == -1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open listen socket for address %s:%d - %s.",
+ s, p, strerror(errno));
- /*
- * Restore the umask...
- */
-
- umask(mask);
- }
- else
-#endif /* AF_LOCAL */
- status = bind(lis->fd, (struct sockaddr *)&(lis->address),
- sizeof(lis->address.ipv4));
-
- if (status < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartListening: Unable to bind socket for address %s:%d - %s.",
- s, p, strerror(errno));
- close(lis->fd);
- lis->fd = -1;
- continue;
- }
+#ifdef AF_INET6
+ /*
+ * IPv6 is often disabled while DNS returns IPv6 addresses...
+ */
- /*
- * Listen for new clients.
- */
+ if (lis->address.addr.sa_family != AF_INET6 &&
+ (FatalErrors & CUPSD_FATAL_LISTEN))
+ cupsdEndProcess(getpid(), 0);
+#else
+ if (FatalErrors & CUPSD_FATAL_LISTEN)
+ cupsdEndProcess(getpid(), 0);
+#endif /* AF_INET6 */
- if (listen(lis->fd, ListenBackLog) < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.",
- s, p, strerror(errno));
- exit(errno);
+ continue;
+ }
}
if (p)
- cupsdLogMessage(CUPSD_LOG_INFO,
- "cupsdStartListening: Listening to %s:%d on fd %d...",
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
s, p, lis->fd);
else
- cupsdLogMessage(CUPSD_LOG_INFO,
- "cupsdStartListening: Listening to %s on fd %d...",
+ cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
s, lis->fd);
/*
* "any" address...
*/
- if (!LocalPort && p > 0 &&
+ if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
(httpAddrLocalhost(&(lis->address)) ||
httpAddrAny(&(lis->address))))
{
if (!LocalPort && !have_domain)
{
cupsdLogMessage(CUPSD_LOG_EMERG,
- "No Listen or Port lines were found to allow access via localhost!");
+ "No Listen or Port lines were found to allow access via "
+ "localhost.");
- /*
- * Commit suicide...
- */
-
- cupsdEndProcess(getpid(), 0);
+ if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
+ cupsdEndProcess(getpid(), 0);
}
/*
*/
cupsdSetEnv("CUPS_SERVER", have_domain);
+
+ LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
}
else
{
}
cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
- cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
+
+ if (LocalPort)
+ cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
/*
* Resume listening for connections...
void
cupsdStopListening(void)
{
- int i; /* Looping var */
cupsd_listener_t *lis; /* Current listening socket */
- cupsdLogMessage(CUPSD_LOG_DEBUG,
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdStopListening: closing all listen sockets.");
cupsdPauseListening();
- for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
-#ifdef WIN32
- closesocket(lis->fd);
+ if (lis->fd != -1)
+ {
+#ifdef HAVE_LAUNCH_H
+ httpAddrClose(NULL, lis->fd);
#else
- close(lis->fd);
-#endif /* WIN32 */
+ httpAddrClose(&(lis->address), lis->fd);
+#endif /* HAVE_LAUNCH */
-#ifdef AF_LOCAL
- /*
- * Remove domain sockets...
- */
-
- if (lis->address.addr.sa_family == AF_LOCAL)
- unlink(lis->address.un.sun_path);
-#endif /* AF_LOCAL */
+ lis->fd = -1;
+ }
}
}
/*
- * End of "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $".
+ * End of "$Id$".
*/