2 * "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $"
4 * Server listening routines for the CUPS scheduler.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsdDeleteAllListeners() - Delete all listeners.
18 * cupsdPauseListening() - Clear input polling on all listening sockets...
19 * cupsdResumeListening() - Set input polling on all listening sockets...
20 * cupsdStartListening() - Create all listening sockets...
21 * cupsdStopListening() - Close all listening sockets...
25 * Include necessary headers...
32 * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
33 * glibc don't define it even if the kernel supports it...
36 #if defined(__linux) && !defined(IPV6_V6ONLY)
37 # define IPV6_V6ONLY 26
38 #endif /* __linux && !IPV6_V6ONLY */
42 * 'cupsdDeleteAllListeners()' - Delete all listeners.
46 cupsdDeleteAllListeners(void)
48 cupsd_listener_t *lis; /* Current listening socket */
51 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
53 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
56 cupsArrayDelete(Listeners);
62 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
66 cupsdPauseListening(void)
68 cupsd_listener_t *lis; /* Current listening socket */
71 if (cupsArrayCount(Listeners) < 1)
74 if (cupsArrayCount(Clients) == MaxClients)
75 cupsdLogMessage(CUPSD_LOG_WARN,
76 "Max clients reached, holding new connections...");
77 else if (errno == ENFILE || errno == EMFILE)
78 cupsdLogMessage(CUPSD_LOG_WARN,
79 "Too many open files, holding new connections for "
82 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
84 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
86 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
87 cupsdRemoveSelect(lis->fd);
89 ListeningPaused = time(NULL) + 30;
94 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
98 cupsdResumeListening(void)
100 cupsd_listener_t *lis; /* Current listening socket */
103 if (cupsArrayCount(Listeners) < 1)
106 cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
107 cupsdLogMessage(CUPSD_LOG_DEBUG2,
108 "cupsdResumeListening: Setting input bits...");
110 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
112 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
113 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
120 * 'cupsdStartListening()' - Create all listening sockets...
124 cupsdStartListening(void)
126 int status; /* Bind result */
127 int p, /* Port number */
128 val; /* Parameter value */
129 cupsd_listener_t *lis; /* Current listening socket */
130 char s[256]; /* String addresss */
131 const char *have_domain; /* Have a domain socket? */
132 static const char * const encryptions[] =
133 { /* Encryption values */
141 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
142 cupsArrayCount(Listeners));
145 * Setup socket listeners...
148 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
151 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
153 httpAddrString(&(lis->address), s, sizeof(s));
154 p = _httpAddrPort(&(lis->address));
157 * If needed, create a socket for listening...
163 * Create a socket for listening...
166 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
170 cupsdLogMessage(CUPSD_LOG_ERROR,
171 "Unable to open listen socket for address %s:%d - %s.",
172 s, p, strerror(errno));
176 * IPv6 is often disabled while DNS returns IPv6 addresses...
179 if (lis->address.addr.sa_family != AF_INET6 &&
180 (FatalErrors & CUPSD_FATAL_LISTEN))
181 cupsdEndProcess(getpid(), 0);
183 if (FatalErrors & CUPSD_FATAL_LISTEN)
184 cupsdEndProcess(getpid(), 0);
185 #endif /* AF_INET6 */
191 * Set things up to reuse the local address for this port.
196 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
198 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
202 * Bind to the port we found...
206 if (lis->address.addr.sa_family == AF_INET6)
210 * Accept only IPv6 connections on this socket, to avoid
211 * potential security issues and to make all platforms behave
217 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
219 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
221 # endif /* IPV6_V6ONLY */
223 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
224 httpAddrLength(&(lis->address)));
227 #endif /* AF_INET6 */
229 if (lis->address.addr.sa_family == AF_LOCAL)
231 mode_t mask; /* Umask setting */
235 * Remove any existing domain socket file...
238 unlink(lis->address.un.sun_path);
241 * Save the current umask and set it to 0 so that all users can access
242 * the domain socket...
248 * Bind the domain socket...
251 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
252 httpAddrLength(&(lis->address)));
255 * Restore the umask...
261 #endif /* AF_LOCAL */
262 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
263 sizeof(lis->address.ipv4));
267 cupsdLogMessage(CUPSD_LOG_ERROR,
268 "Unable to bind socket for address %s:%d - %s.",
269 s, p, strerror(errno));
273 if (FatalErrors & CUPSD_FATAL_LISTEN)
274 cupsdEndProcess(getpid(), 0);
280 * Listen for new clients.
283 if (listen(lis->fd, ListenBackLog) < 0)
285 cupsdLogMessage(CUPSD_LOG_ERROR,
286 "Unable to listen for clients on address %s:%d - %s.",
287 s, p, strerror(errno));
292 if (FatalErrors & CUPSD_FATAL_LISTEN)
293 cupsdEndProcess(getpid(), 0);
299 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
302 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
306 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
309 if (chmod(s, 0140777))
310 cupsdLogMessage(CUPSD_LOG_ERROR,
311 "Unable to change permisssions on domain socket "
312 "\"%s\" - %s", s, strerror(errno));
316 * Save the first port that is bound to the local loopback or
320 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
321 (httpAddrLocalhost(&(lis->address)) ||
322 httpAddrAny(&(lis->address))))
325 LocalEncryption = lis->encryption;
329 if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
330 have_domain = lis->address.un.sun_path;
331 #endif /* AF_LOCAL */
335 * Make sure that we are listening on localhost!
338 if (!LocalPort && !have_domain)
340 cupsdLogMessage(CUPSD_LOG_EMERG,
341 "No Listen or Port lines were found to allow access via "
344 if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
345 cupsdEndProcess(getpid(), 0);
349 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
356 * Use domain sockets for the local connection...
359 cupsdSetEnv("CUPS_SERVER", have_domain);
361 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
366 * Use the default local loopback address for the server...
369 cupsdSetEnv("CUPS_SERVER", "localhost");
372 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
375 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
378 * Resume listening for connections...
381 cupsdResumeListening();
386 * 'cupsdStopListening()' - Close all listening sockets...
390 cupsdStopListening(void)
392 cupsd_listener_t *lis; /* Current listening socket */
395 cupsdLogMessage(CUPSD_LOG_DEBUG2,
396 "cupsdStopListening: closing all listen sockets.");
398 cupsdPauseListening();
400 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
402 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
407 closesocket(lis->fd);
414 * Remove domain sockets...
417 # ifdef HAVE_LAUNCH_H
418 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
420 if (lis->address.addr.sa_family == AF_LOCAL)
421 # endif /* HAVE_LAUNCH_H */
422 unlink(lis->address.un.sun_path);
423 #endif /* AF_LOCAL */
430 * End of "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $".