2 * "$Id: listen.c 7918 2008-09-08 22:03:01Z mike $"
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
));
156 if (lis
->address
.addr
.sa_family
== AF_INET6
)
157 p
= ntohs(lis
->address
.ipv6
.sin6_port
);
159 #endif /* AF_INET6 */
161 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
164 #endif /* AF_LOCAL */
165 p
= ntohs(lis
->address
.ipv4
.sin_port
);
168 * If needed, create a socket for listening...
174 * Create a socket for listening...
177 lis
->fd
= socket(lis
->address
.addr
.sa_family
, SOCK_STREAM
, 0);
181 cupsdLogMessage(CUPSD_LOG_ERROR
,
182 "Unable to open listen socket for address %s:%d - %s.",
183 s
, p
, strerror(errno
));
187 * IPv6 is often disabled while DNS returns IPv6 addresses...
190 if (lis
->address
.addr
.sa_family
!= AF_INET6
&&
191 (FatalErrors
& CUPSD_FATAL_LISTEN
))
192 cupsdEndProcess(getpid(), 0);
194 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
195 cupsdEndProcess(getpid(), 0);
196 #endif /* AF_INET6 */
202 * Set things up to reuse the local address for this port.
207 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
, sizeof(val
));
209 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
213 * Bind to the port we found...
217 if (lis
->address
.addr
.sa_family
== AF_INET6
)
221 * Accept only IPv6 connections on this socket, to avoid
222 * potential security issues and to make all platforms behave
228 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
230 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &val
, sizeof(val
));
232 # endif /* IPV6_V6ONLY */
234 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
235 httpAddrLength(&(lis
->address
)));
238 #endif /* AF_INET6 */
240 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
242 mode_t mask
; /* Umask setting */
246 * Remove any existing domain socket file...
249 unlink(lis
->address
.un
.sun_path
);
252 * Save the current umask and set it to 0 so that all users can access
253 * the domain socket...
259 * Bind the domain socket...
262 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
263 httpAddrLength(&(lis
->address
)));
266 * Restore the umask...
272 #endif /* AF_LOCAL */
273 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
274 sizeof(lis
->address
.ipv4
));
278 cupsdLogMessage(CUPSD_LOG_ERROR
,
279 "Unable to bind socket for address %s:%d - %s.",
280 s
, p
, strerror(errno
));
284 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
285 cupsdEndProcess(getpid(), 0);
291 * Listen for new clients.
294 if (listen(lis
->fd
, ListenBackLog
) < 0)
296 cupsdLogMessage(CUPSD_LOG_ERROR
,
297 "Unable to listen for clients on address %s:%d - %s.",
298 s
, p
, strerror(errno
));
303 if (FatalErrors
& CUPSD_FATAL_LISTEN
)
304 cupsdEndProcess(getpid(), 0);
310 fcntl(lis
->fd
, F_SETFD
, fcntl(lis
->fd
, F_GETFD
) | FD_CLOEXEC
);
313 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s:%d on fd %d...",
317 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s on fd %d...",
320 if (chmod(s
, 0140777))
321 cupsdLogMessage(CUPSD_LOG_ERROR
,
322 "Unable to change permisssions on domain socket "
323 "\"%s\" - %s", s
, strerror(errno
));
327 * Save the first port that is bound to the local loopback or
331 if ((!LocalPort
|| LocalEncryption
== HTTP_ENCRYPT_ALWAYS
) && p
> 0 &&
332 (httpAddrLocalhost(&(lis
->address
)) ||
333 httpAddrAny(&(lis
->address
))))
336 LocalEncryption
= lis
->encryption
;
340 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !have_domain
)
341 have_domain
= lis
->address
.un
.sun_path
;
342 #endif /* AF_LOCAL */
346 * Make sure that we are listening on localhost!
349 if (!LocalPort
&& !have_domain
)
351 cupsdLogMessage(CUPSD_LOG_EMERG
,
352 "No Listen or Port lines were found to allow access via "
355 if (FatalErrors
& (CUPSD_FATAL_CONFIG
| CUPSD_FATAL_LISTEN
))
356 cupsdEndProcess(getpid(), 0);
360 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
367 * Use domain sockets for the local connection...
370 cupsdSetEnv("CUPS_SERVER", have_domain
);
372 LocalEncryption
= HTTP_ENCRYPT_IF_REQUESTED
;
377 * Use the default local loopback address for the server...
380 cupsdSetEnv("CUPS_SERVER", "localhost");
383 cupsdSetEnv("CUPS_ENCRYPTION", encryptions
[LocalEncryption
]);
386 cupsdSetEnvf("IPP_PORT", "%d", LocalPort
);
389 * Resume listening for connections...
392 cupsdResumeListening();
397 * 'cupsdStopListening()' - Close all listening sockets...
401 cupsdStopListening(void)
403 cupsd_listener_t
*lis
; /* Current listening socket */
406 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
407 "cupsdStopListening: closing all listen sockets.");
409 cupsdPauseListening();
411 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
413 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
418 closesocket(lis
->fd
);
425 * Remove domain sockets...
428 # ifdef HAVE_LAUNCH_H
429 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !Launchd
)
431 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
432 # endif /* HAVE_LAUNCH_H */
433 unlink(lis
->address
.un
.sun_path
);
434 #endif /* AF_LOCAL */
441 * End of "$Id: listen.c 7918 2008-09-08 22:03:01Z mike $".