#include "cupsd.h"
#if defined(__linux) && !defined(IPV6_V6ONLY)
# define IPV6_V6ONLY 26
#endif
void
cupsdDeleteAllListeners(void)
{
cupsd_listener_t *lis;
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
#ifdef HAVE_ONDEMAND
if (!lis->on_demand)
#endif
{
cupsArrayRemove(Listeners, lis);
free(lis);
}
if (cupsArrayCount(Listeners) == 0)
{
cupsArrayDelete(Listeners);
Listeners = NULL;
}
}
void
cupsdPauseListening(void)
{
cupsd_listener_t *lis;
if (cupsArrayCount(Listeners) < 1)
return;
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_DEBUG2, "cupsdPauseListening: Clearing input bits...");
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
cupsdRemoveSelect(lis->fd);
ListeningPaused = time(NULL) + 30;
}
void
cupsdResumeListening(void)
{
cupsd_listener_t *lis;
if (cupsArrayCount(Listeners) < 1)
return;
cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"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);
ListeningPaused = 0;
}
void
cupsdStartListening(void)
{
int p;
cupsd_listener_t *lis;
char s[256];
const char *have_domain;
static const char * const encryptions[] =
{
"IfRequested",
"Never",
"Required",
"Always"
};
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
cupsArrayCount(Listeners));
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));
p = httpAddrPort(&(lis->address));
if (lis->fd == -1)
{
lis->fd = httpAddrListen(&(lis->address), p);
if (lis->fd == -1)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to open listen socket for address %s:%d - %s.",
s, p, strerror(errno));
#ifdef AF_INET6
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
continue;
}
}
if (p)
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
s, p, lis->fd);
else
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
s, lis->fd);
if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
(httpAddrLocalhost(&(lis->address)) ||
httpAddrAny(&(lis->address))))
{
LocalPort = p;
LocalEncryption = lis->encryption;
}
#ifdef AF_LOCAL
if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
have_domain = lis->address.un.sun_path;
#endif
}
if (!LocalPort && !have_domain)
{
cupsdLogMessage(CUPSD_LOG_EMERG,
"No Listen or Port lines were found to allow access via "
"localhost.");
if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
cupsdEndProcess(getpid(), 0);
}
if (have_domain)
{
cupsdSetEnv("CUPS_SERVER", have_domain);
LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
}
else
{
cupsdSetEnv("CUPS_SERVER", "localhost");
}
cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
if (LocalPort)
cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
cupsdResumeListening();
}
void
cupsdStopListening(void)
{
cupsd_listener_t *lis;
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdStopListening: closing all listen sockets.");
cupsdPauseListening();
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
lis;
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
{
#ifdef HAVE_ONDEMAND
if (!lis->on_demand && lis->fd != -1)
{
httpAddrClose(&(lis->address), lis->fd);
lis->fd = -1;
}
#else
if (lis->fd != -1)
{
httpAddrClose(&(lis->address), lis->fd);
lis->fd = -1;
}
#endif
}
}