#include "cupsd.h"
#ifdef HAVE_DOMAINSOCKETS
# include <sys/un.h>
#endif
void
PauseListening(void)
{
int i;
listener_t *lis;
if (NumListeners < 1 || !FD_ISSET(Listeners[0].fd, InputSet))
return;
if (NumClients == MaxClients)
LogMessage(L_WARN, "Max clients reached, holding new connections...");
LogMessage(L_DEBUG, "PauseListening: clearing input bits...");
for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
{
LogMessage(L_DEBUG2, "PauseListening: Removing fd %d from InputSet...",
lis->fd);
FD_CLR(lis->fd, InputFds);
FD_CLR(lis->fd, InputSet);
}
}
void
ResumeListening(void)
{
int i;
listener_t *lis;
if (NumListeners < 1 || FD_ISSET(Listeners[0].fd, InputSet))
return;
if (NumClients >= (MaxClients - 1))
LogMessage(L_WARN, "Resuming new connection processing...");
LogMessage(L_DEBUG, "ResumeListening: setting input bits...");
for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
{
LogMessage(L_DEBUG2, "ResumeListening: Adding fd %d to InputSet...",
lis->fd);
FD_SET(lis->fd, InputSet);
}
}
void
StartListening(void)
{
int i,
val;
listener_t *lis;
struct hostent *host;
LogMessage(L_DEBUG, "StartListening: NumListeners=%d", NumListeners);
memset(&ServerAddr, 0, sizeof(ServerAddr));
if ((host = httpGetHostByName(ServerName)) != NULL)
{
memcpy((char *)&(ServerAddr.sin_addr), host->h_addr, host->h_length);
ServerAddr.sin_family = host->h_addrtype;
}
else
{
LogMessage(L_ERROR, "StartListening: Unable to find IP address for server name \"%s\" - %s\n",
ServerName, hstrerror(h_errno));
ServerAddr.sin_family = AF_INET;
}
for (i = NumListeners, lis = Listeners, LocalPort = 0; i > 0; i --, lis ++)
{
#ifdef HAVE_DOMAINSOCKETS
if (lis->address.sin_family == AF_LOCAL)
LogMessage(L_DEBUG, "StartListening: domain socket=%s", (char*)lis->address.sin_addr.s_addr);
else
#endif
LogMessage(L_DEBUG, "StartListening: address=%08x port=%d",
(unsigned)ntohl(lis->address.sin_addr.s_addr),
ntohs(lis->address.sin_port));
if (!LocalPort &&
lis->address.sin_family == AF_INET &&
(ntohl(lis->address.sin_addr.s_addr) == 0x7f000001 ||
ntohl(lis->address.sin_addr.s_addr) == 0x00000000))
{
LocalPort = ntohs(lis->address.sin_port);
LocalEncryption = lis->encryption;
}
if ((lis->fd = socket(lis->address.sin_family, SOCK_STREAM, 0)) == -1)
{
LogMessage(L_ERROR, "StartListening: Unable to open listen socket for address %08x:%d - %s.",
(unsigned)ntohl(lis->address.sin_addr.s_addr),
ntohs(lis->address.sin_port), strerror(errno));
exit(errno);
}
fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
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
if (lis->address.sin_family == AF_INET)
{
if (bind(lis->fd, (struct sockaddr *)&(lis->address), sizeof(lis->address)) < 0)
{
LogMessage(L_ERROR, "StartListening: Unable to bind socket for address %08x:%d - %s.",
(unsigned)ntohl(lis->address.sin_addr.s_addr),
ntohs(lis->address.sin_port), strerror(errno));
exit(errno);
}
}
#ifdef HAVE_DOMAINSOCKETS
else if (lis->address.sin_family == AF_LOCAL)
{
struct sockaddr_un laddr;
mode_t mask;
bzero(&laddr, sizeof(laddr));
laddr.sun_family = AF_LOCAL;
strlcpy(laddr.sun_path, *(char **)&lis->address.sin_addr, sizeof(laddr.sun_path));
unlink(laddr.sun_path);
mask = umask(0);
if (bind(lis->fd, (struct sockaddr *)&laddr, SUN_LEN(&laddr)) < 0)
{
LogMessage(L_ERROR, "StartListening: Unable to bind socket for address %s - %s.",
laddr.sun_path, strerror(errno));
exit(errno);
}
umask(mask);
}
#endif
else
{
LogMessage(L_ERROR, "StartListening: Unknown address family %d.",
(int)lis->address.sin_family);
exit(errno);
}
if (listen(lis->fd, ListenBackLog) < 0)
{
LogMessage(L_ERROR, "StartListening: Unable to listen for clients on address %08x:%d - %s.",
(unsigned)ntohl(lis->address.sin_addr.s_addr),
ntohs(lis->address.sin_port), strerror(errno));
exit(errno);
}
}
if (!LocalPort)
{
LogMessage(L_EMERG, "No Listen or Port lines were found to allow access via localhost!");
kill(getpid(), SIGTERM);
}
ResumeListening();
}
void
StopListening(void)
{
int i;
listener_t *lis;
LogMessage(L_DEBUG, "StopListening: closing all listen sockets.");
PauseListening();
for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
{
#ifdef WIN32
closesocket(lis->fd);
#else
close(lis->fd);
#endif
#ifdef HAVE_DOMAINSOCKETS
if (lis->address.sin_family == AF_LOCAL)
unlink(*(char **)&lis->address.sin_addr);
#endif
}
}