2 * "$Id: listen.c 7673 2008-06-18 22:31:26Z mike $"
4 * Server listening routines for the Common UNIX Printing System (CUPS)
7 * Copyright 2007-2008 by Apple Inc.
8 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
18 * cupsdDeleteAllListeners() - Delete all listeners.
19 * cupsdPauseListening() - Clear input polling on all listening sockets...
20 * cupsdResumeListening() - Set input polling on all listening sockets...
21 * cupsdStartListening() - Create all listening sockets...
22 * cupsdStopListening() - Close all listening sockets...
26 * Include necessary headers...
33 * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
34 * glibc don't define it even if the kernel supports it...
37 #if defined(__linux) && !defined(IPV6_V6ONLY)
38 # define IPV6_V6ONLY 26
39 #endif /* __linux && !IPV6_V6ONLY */
43 * 'cupsdDeleteAllListeners()' - Delete all listeners.
47 cupsdDeleteAllListeners(void)
49 cupsd_listener_t
*lis
; /* Current listening socket */
52 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
54 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
57 cupsArrayDelete(Listeners
);
63 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
67 cupsdPauseListening(void)
69 cupsd_listener_t
*lis
; /* Current listening socket */
72 if (cupsArrayCount(Listeners
) < 1)
75 if (cupsArrayCount(Clients
) == MaxClients
)
76 cupsdLogMessage(CUPSD_LOG_WARN
,
77 "Max clients reached, holding new connections...");
78 else if (errno
== ENFILE
|| errno
== EMFILE
)
79 cupsdLogMessage(CUPSD_LOG_WARN
,
80 "Too many open files, holding new connections for "
83 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdPauseListening: Clearing input bits...");
85 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
87 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
88 cupsdRemoveSelect(lis
->fd
);
90 ListeningPaused
= time(NULL
) + 30;
95 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
99 cupsdResumeListening(void)
101 cupsd_listener_t
*lis
; /* Current listening socket */
104 if (cupsArrayCount(Listeners
) < 1)
107 cupsdLogMessage(CUPSD_LOG_INFO
, "Resuming new connection processing...");
108 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
109 "cupsdResumeListening: Setting input bits...");
111 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
113 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
114 cupsdAddSelect(lis
->fd
, (cupsd_selfunc_t
)cupsdAcceptClient
, NULL
, lis
);
121 * 'cupsdStartListening()' - Create all listening sockets...
125 cupsdStartListening(void)
127 int status
; /* Bind result */
128 int p
, /* Port number */
129 val
; /* Parameter value */
130 cupsd_listener_t
*lis
; /* Current listening socket */
131 char s
[256]; /* String addresss */
132 const char *have_domain
; /* Have a domain socket? */
133 static const char * const encryptions
[] =
134 { /* Encryption values */
142 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartListening: %d Listeners",
143 cupsArrayCount(Listeners
));
146 * Get the server's IP address...
150 httpAddrFreeList(ServerAddrs
);
152 if ((ServerAddrs
= httpAddrGetList(ServerName
, AF_UNSPEC
, NULL
)) == NULL
)
154 cupsdLogMessage(CUPSD_LOG_ERROR
,
155 "Unable to find IP address for server name \"%s\"!",
158 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
159 cupsdEndProcess(getpid(), 0);
163 * Setup socket listeners...
166 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
), LocalPort
= 0,
169 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
171 httpAddrString(&(lis
->address
), s
, sizeof(s
));
174 if (lis
->address
.addr
.sa_family
== AF_INET6
)
175 p
= ntohs(lis
->address
.ipv6
.sin6_port
);
177 #endif /* AF_INET6 */
179 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
182 #endif /* AF_LOCAL */
183 p
= ntohs(lis
->address
.ipv4
.sin_port
);
186 * If needed, create a socket for listening...
192 * Create a socket for listening...
195 lis
->fd
= socket(lis
->address
.addr
.sa_family
, SOCK_STREAM
, 0);
199 cupsdLogMessage(CUPSD_LOG_ERROR
,
200 "Unable to open listen socket for address %s:%d - %s.",
201 s
, p
, strerror(errno
));
205 * IPv6 is often disabled while DNS returns IPv6 addresses...
208 if (lis
->address
.addr
.sa_family
!= AF_INET6
&&
209 (FatalErrors
& CUPSD_FATAL_LISTEN
))
210 cupsdEndProcess(getpid(), 0);
212 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
213 cupsdEndProcess(getpid(), 0);
214 #endif /* AF_INET6 */
220 * Set things up to reuse the local address for this port.
225 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
, sizeof(val
));
227 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
231 * Bind to the port we found...
235 if (lis
->address
.addr
.sa_family
== AF_INET6
)
239 * Accept only IPv6 connections on this socket, to avoid
240 * potential security issues and to make all platforms behave
246 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
248 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &val
, sizeof(val
));
250 # endif /* IPV6_V6ONLY */
252 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
253 httpAddrLength(&(lis
->address
)));
256 #endif /* AF_INET6 */
258 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
260 mode_t mask
; /* Umask setting */
264 * Remove any existing domain socket file...
267 unlink(lis
->address
.un
.sun_path
);
270 * Save the curent umask and set it to 0...
276 * Bind the domain socket...
279 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
280 httpAddrLength(&(lis
->address
)));
283 * Restore the umask...
289 #endif /* AF_LOCAL */
290 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
291 sizeof(lis
->address
.ipv4
));
295 cupsdLogMessage(CUPSD_LOG_ERROR
,
296 "Unable to bind socket for address %s:%d - %s.",
297 s
, p
, strerror(errno
));
301 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
302 cupsdEndProcess(getpid(), 0);
308 * Listen for new clients.
311 if (listen(lis
->fd
, ListenBackLog
) < 0)
313 cupsdLogMessage(CUPSD_LOG_ERROR
,
314 "Unable to listen for clients on address %s:%d - %s.",
315 s
, p
, strerror(errno
));
320 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
321 cupsdEndProcess(getpid(), 0);
327 fcntl(lis
->fd
, F_SETFD
, fcntl(lis
->fd
, F_GETFD
) | FD_CLOEXEC
);
330 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s:%d on fd %d...",
334 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s on fd %d...",
337 if (chmod(s
, 0140777))
338 cupsdLogMessage(CUPSD_LOG_ERROR
,
339 "Unable to change permisssions on domain socket "
340 "\"%s\" - %s", s
, strerror(errno
));
344 * Save the first port that is bound to the local loopback or
348 if ((!LocalPort
|| LocalEncryption
== HTTP_ENCRYPT_ALWAYS
) && p
> 0 &&
349 (httpAddrLocalhost(&(lis
->address
)) ||
350 httpAddrAny(&(lis
->address
))))
353 LocalEncryption
= lis
->encryption
;
357 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !have_domain
)
358 have_domain
= lis
->address
.un
.sun_path
;
359 #endif /* AF_LOCAL */
363 * Make sure that we are listening on localhost!
366 if (!LocalPort
&& !have_domain
)
368 cupsdLogMessage(CUPSD_LOG_EMERG
,
369 "No Listen or Port lines were found to allow access via "
372 if (FatalErrors
& (CUPSD_FATAL_CONFIG
| CUPSD_FATAL_LISTEN
))
373 cupsdEndProcess(getpid(), 0);
377 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
384 * Use domain sockets for the local connection...
387 cupsdSetEnv("CUPS_SERVER", have_domain
);
389 LocalEncryption
= HTTP_ENCRYPT_IF_REQUESTED
;
394 * Use the default local loopback address for the server...
397 cupsdSetEnv("CUPS_SERVER", "localhost");
400 cupsdSetEnv("CUPS_ENCRYPTION", encryptions
[LocalEncryption
]);
403 cupsdSetEnvf("IPP_PORT", "%d", LocalPort
);
406 * Resume listening for connections...
409 cupsdResumeListening();
414 * 'cupsdStopListening()' - Close all listening sockets...
418 cupsdStopListening(void)
420 cupsd_listener_t
*lis
; /* Current listening socket */
423 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
424 "cupsdStopListening: closing all listen sockets.");
426 cupsdPauseListening();
428 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
430 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
435 closesocket(lis
->fd
);
442 * Remove domain sockets...
445 # ifdef HAVE_LAUNCH_H
446 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !Launchd
)
448 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
449 # endif /* HAVE_LAUNCH_H */
450 unlink(lis
->address
.un
.sun_path
);
451 #endif /* AF_LOCAL */
458 * End of "$Id: listen.c 7673 2008-06-18 22:31:26Z mike $".