]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
f2d18633 | 2 | * "$Id$" |
ef416fc2 | 3 | * |
10d09e33 | 4 | * Server listening routines for the CUPS scheduler. |
ef416fc2 | 5 | * |
10d09e33 | 6 | * Copyright 2007-2010 by Apple Inc. |
4400e98d | 7 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 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/". | |
ef416fc2 | 14 | * |
15 | * Contents: | |
16 | * | |
bd7854cb | 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... | |
ef416fc2 | 22 | */ |
23 | ||
24 | /* | |
25 | * Include necessary headers... | |
26 | */ | |
27 | ||
28 | #include "cupsd.h" | |
29 | ||
30 | ||
31 | /* | |
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... | |
34 | */ | |
35 | ||
36 | #if defined(__linux) && !defined(IPV6_V6ONLY) | |
37 | # define IPV6_V6ONLY 26 | |
38 | #endif /* __linux && !IPV6_V6ONLY */ | |
39 | ||
40 | ||
bd7854cb | 41 | /* |
42 | * 'cupsdDeleteAllListeners()' - Delete all listeners. | |
43 | */ | |
44 | ||
45 | void | |
46 | cupsdDeleteAllListeners(void) | |
47 | { | |
48 | cupsd_listener_t *lis; /* Current listening socket */ | |
49 | ||
50 | ||
51 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); | |
52 | lis; | |
53 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
54 | free(lis); | |
55 | ||
56 | cupsArrayDelete(Listeners); | |
57 | Listeners = NULL; | |
58 | } | |
59 | ||
60 | ||
ef416fc2 | 61 | /* |
62 | * 'cupsdPauseListening()' - Clear input polling on all listening sockets... | |
63 | */ | |
64 | ||
65 | void | |
66 | cupsdPauseListening(void) | |
67 | { | |
ef416fc2 | 68 | cupsd_listener_t *lis; /* Current listening socket */ |
69 | ||
70 | ||
bd7854cb | 71 | if (cupsArrayCount(Listeners) < 1) |
ef416fc2 | 72 | return; |
73 | ||
bd7854cb | 74 | if (cupsArrayCount(Clients) == MaxClients) |
ef416fc2 | 75 | cupsdLogMessage(CUPSD_LOG_WARN, |
76 | "Max clients reached, holding new connections..."); | |
76cd9e37 MS |
77 | else if (errno == ENFILE || errno == EMFILE) |
78 | cupsdLogMessage(CUPSD_LOG_WARN, | |
79 | "Too many open files, holding new connections for " | |
80 | "30 seconds..."); | |
ef416fc2 | 81 | |
bd7854cb | 82 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits..."); |
ef416fc2 | 83 | |
bd7854cb | 84 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
85 | lis; | |
86 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
f7deaa1a | 87 | cupsdRemoveSelect(lis->fd); |
76cd9e37 MS |
88 | |
89 | ListeningPaused = time(NULL) + 30; | |
ef416fc2 | 90 | } |
91 | ||
92 | ||
93 | /* | |
94 | * 'cupsdResumeListening()' - Set input polling on all listening sockets... | |
95 | */ | |
96 | ||
97 | void | |
98 | cupsdResumeListening(void) | |
99 | { | |
ef416fc2 | 100 | cupsd_listener_t *lis; /* Current listening socket */ |
101 | ||
102 | ||
bd7854cb | 103 | if (cupsArrayCount(Listeners) < 1) |
ef416fc2 | 104 | return; |
105 | ||
76cd9e37 | 106 | cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing..."); |
bd7854cb | 107 | cupsdLogMessage(CUPSD_LOG_DEBUG2, |
108 | "cupsdResumeListening: Setting input bits..."); | |
ef416fc2 | 109 | |
bd7854cb | 110 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
111 | lis; | |
112 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
f7deaa1a | 113 | cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis); |
76cd9e37 MS |
114 | |
115 | ListeningPaused = 0; | |
ef416fc2 | 116 | } |
117 | ||
118 | ||
119 | /* | |
120 | * 'cupsdStartListening()' - Create all listening sockets... | |
121 | */ | |
122 | ||
123 | void | |
124 | cupsdStartListening(void) | |
125 | { | |
126 | int status; /* Bind result */ | |
bd7854cb | 127 | int p, /* Port number */ |
ef416fc2 | 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 */ | |
134 | "IfRequested", | |
135 | "Never", | |
136 | "Required", | |
137 | "Always" | |
138 | }; | |
139 | ||
140 | ||
bd7854cb | 141 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners", |
142 | cupsArrayCount(Listeners)); | |
ef416fc2 | 143 | |
ef416fc2 | 144 | /* |
145 | * Setup socket listeners... | |
146 | */ | |
147 | ||
bd7854cb | 148 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0, |
149 | have_domain = NULL; | |
150 | lis; | |
151 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
ef416fc2 | 152 | { |
153 | httpAddrString(&(lis->address), s, sizeof(s)); | |
a469f8a5 | 154 | p = httpAddrPort(&(lis->address)); |
ef416fc2 | 155 | |
156 | /* | |
a4d04587 | 157 | * If needed, create a socket for listening... |
ef416fc2 | 158 | */ |
159 | ||
ef416fc2 | 160 | if (lis->fd == -1) |
161 | { | |
ef416fc2 | 162 | /* |
a4d04587 | 163 | * Create a socket for listening... |
ef416fc2 | 164 | */ |
bd7854cb | 165 | |
a4d04587 | 166 | lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0); |
bd7854cb | 167 | |
a4d04587 | 168 | if (lis->fd == -1) |
169 | { | |
170 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
bd7854cb | 171 | "Unable to open listen socket for address %s:%d - %s.", |
a4d04587 | 172 | s, p, strerror(errno)); |
49d87452 MS |
173 | |
174 | #ifdef AF_INET6 | |
175 | /* | |
176 | * IPv6 is often disabled while DNS returns IPv6 addresses... | |
177 | */ | |
178 | ||
179 | if (lis->address.addr.sa_family != AF_INET6 && | |
180 | (FatalErrors & CUPSD_FATAL_LISTEN)) | |
181 | cupsdEndProcess(getpid(), 0); | |
182 | #else | |
183 | if (FatalErrors & CUPSD_FATAL_LISTEN) | |
184 | cupsdEndProcess(getpid(), 0); | |
185 | #endif /* AF_INET6 */ | |
186 | ||
a4d04587 | 187 | continue; |
188 | } | |
bd7854cb | 189 | |
ef416fc2 | 190 | /* |
a4d04587 | 191 | * Set things up to reuse the local address for this port. |
ef416fc2 | 192 | */ |
bd7854cb | 193 | |
a4d04587 | 194 | val = 1; |
e00b005a | 195 | #ifdef __sun |
a4d04587 | 196 | setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); |
e00b005a | 197 | #else |
a4d04587 | 198 | setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); |
e00b005a | 199 | #endif /* __sun */ |
bd7854cb | 200 | |
ef416fc2 | 201 | /* |
a4d04587 | 202 | * Bind to the port we found... |
ef416fc2 | 203 | */ |
bd7854cb | 204 | |
e00b005a | 205 | #ifdef AF_INET6 |
a4d04587 | 206 | if (lis->address.addr.sa_family == AF_INET6) |
207 | { | |
e00b005a | 208 | # ifdef IPV6_V6ONLY |
a4d04587 | 209 | /* |
210 | * Accept only IPv6 connections on this socket, to avoid | |
211 | * potential security issues and to make all platforms behave | |
212 | * the same. | |
213 | */ | |
bd7854cb | 214 | |
a4d04587 | 215 | val = 1; |
e00b005a | 216 | # ifdef __sun |
a4d04587 | 217 | setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val)); |
e00b005a | 218 | # else |
a4d04587 | 219 | setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); |
e00b005a | 220 | # endif /* __sun */ |
221 | # endif /* IPV6_V6ONLY */ | |
bd7854cb | 222 | |
a4d04587 | 223 | status = bind(lis->fd, (struct sockaddr *)&(lis->address), |
224 | httpAddrLength(&(lis->address))); | |
225 | } | |
226 | else | |
e00b005a | 227 | #endif /* AF_INET6 */ |
228 | #ifdef AF_LOCAL | |
a4d04587 | 229 | if (lis->address.addr.sa_family == AF_LOCAL) |
230 | { | |
231 | mode_t mask; /* Umask setting */ | |
bd7854cb | 232 | |
233 | ||
a4d04587 | 234 | /* |
235 | * Remove any existing domain socket file... | |
236 | */ | |
bd7854cb | 237 | |
a4d04587 | 238 | unlink(lis->address.un.sun_path); |
bd7854cb | 239 | |
a4d04587 | 240 | /* |
f8b3a85b MS |
241 | * Save the current umask and set it to 0 so that all users can access |
242 | * the domain socket... | |
a4d04587 | 243 | */ |
bd7854cb | 244 | |
a4d04587 | 245 | mask = umask(0); |
bd7854cb | 246 | |
a4d04587 | 247 | /* |
248 | * Bind the domain socket... | |
249 | */ | |
bd7854cb | 250 | |
a4d04587 | 251 | status = bind(lis->fd, (struct sockaddr *)&(lis->address), |
252 | httpAddrLength(&(lis->address))); | |
bd7854cb | 253 | |
a4d04587 | 254 | /* |
255 | * Restore the umask... | |
256 | */ | |
bd7854cb | 257 | |
a4d04587 | 258 | umask(mask); |
259 | } | |
260 | else | |
e00b005a | 261 | #endif /* AF_LOCAL */ |
ef416fc2 | 262 | status = bind(lis->fd, (struct sockaddr *)&(lis->address), |
a4d04587 | 263 | sizeof(lis->address.ipv4)); |
bd7854cb | 264 | |
a4d04587 | 265 | if (status < 0) |
266 | { | |
267 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
bd7854cb | 268 | "Unable to bind socket for address %s:%d - %s.", |
a4d04587 | 269 | s, p, strerror(errno)); |
270 | close(lis->fd); | |
271 | lis->fd = -1; | |
49d87452 MS |
272 | |
273 | if (FatalErrors & CUPSD_FATAL_LISTEN) | |
274 | cupsdEndProcess(getpid(), 0); | |
275 | ||
a4d04587 | 276 | continue; |
277 | } | |
bd7854cb | 278 | |
ef416fc2 | 279 | /* |
a4d04587 | 280 | * Listen for new clients. |
ef416fc2 | 281 | */ |
bd7854cb | 282 | |
a4d04587 | 283 | if (listen(lis->fd, ListenBackLog) < 0) |
284 | { | |
285 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
bd7854cb | 286 | "Unable to listen for clients on address %s:%d - %s.", |
a4d04587 | 287 | s, p, strerror(errno)); |
49d87452 MS |
288 | |
289 | close(lis->fd); | |
290 | lis->fd = -1; | |
291 | ||
292 | if (FatalErrors & CUPSD_FATAL_LISTEN) | |
293 | cupsdEndProcess(getpid(), 0); | |
294 | ||
295 | continue; | |
a4d04587 | 296 | } |
ef416fc2 | 297 | } |
ef416fc2 | 298 | |
a4d04587 | 299 | fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC); |
ef416fc2 | 300 | |
301 | if (p) | |
bd7854cb | 302 | cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...", |
ef416fc2 | 303 | s, p, lis->fd); |
304 | else | |
4400e98d | 305 | { |
bd7854cb | 306 | cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...", |
ef416fc2 | 307 | s, lis->fd); |
308 | ||
4400e98d | 309 | if (chmod(s, 0140777)) |
310 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
bd7854cb | 311 | "Unable to change permisssions on domain socket " |
312 | "\"%s\" - %s", s, strerror(errno)); | |
4400e98d | 313 | } |
314 | ||
ef416fc2 | 315 | /* |
316 | * Save the first port that is bound to the local loopback or | |
317 | * "any" address... | |
318 | */ | |
319 | ||
8ca02f3c | 320 | if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 && |
ef416fc2 | 321 | (httpAddrLocalhost(&(lis->address)) || |
322 | httpAddrAny(&(lis->address)))) | |
323 | { | |
324 | LocalPort = p; | |
325 | LocalEncryption = lis->encryption; | |
326 | } | |
327 | ||
328 | #ifdef AF_LOCAL | |
329 | if (lis->address.addr.sa_family == AF_LOCAL && !have_domain) | |
330 | have_domain = lis->address.un.sun_path; | |
331 | #endif /* AF_LOCAL */ | |
332 | } | |
333 | ||
334 | /* | |
335 | * Make sure that we are listening on localhost! | |
336 | */ | |
337 | ||
338 | if (!LocalPort && !have_domain) | |
339 | { | |
340 | cupsdLogMessage(CUPSD_LOG_EMERG, | |
07725fee | 341 | "No Listen or Port lines were found to allow access via " |
342 | "localhost!"); | |
ef416fc2 | 343 | |
49d87452 MS |
344 | if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN)) |
345 | cupsdEndProcess(getpid(), 0); | |
ef416fc2 | 346 | } |
347 | ||
348 | /* | |
349 | * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on | |
350 | * the listeners... | |
351 | */ | |
352 | ||
353 | if (have_domain) | |
354 | { | |
355 | /* | |
356 | * Use domain sockets for the local connection... | |
357 | */ | |
358 | ||
359 | cupsdSetEnv("CUPS_SERVER", have_domain); | |
8ca02f3c | 360 | |
361 | LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED; | |
ef416fc2 | 362 | } |
363 | else | |
364 | { | |
365 | /* | |
366 | * Use the default local loopback address for the server... | |
367 | */ | |
368 | ||
369 | cupsdSetEnv("CUPS_SERVER", "localhost"); | |
370 | } | |
371 | ||
372 | cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]); | |
07725fee | 373 | |
374 | if (LocalPort) | |
375 | cupsdSetEnvf("IPP_PORT", "%d", LocalPort); | |
ef416fc2 | 376 | |
377 | /* | |
378 | * Resume listening for connections... | |
379 | */ | |
380 | ||
381 | cupsdResumeListening(); | |
382 | } | |
383 | ||
384 | ||
385 | /* | |
386 | * 'cupsdStopListening()' - Close all listening sockets... | |
387 | */ | |
388 | ||
389 | void | |
390 | cupsdStopListening(void) | |
391 | { | |
ef416fc2 | 392 | cupsd_listener_t *lis; /* Current listening socket */ |
393 | ||
394 | ||
bd7854cb | 395 | cupsdLogMessage(CUPSD_LOG_DEBUG2, |
ef416fc2 | 396 | "cupsdStopListening: closing all listen sockets."); |
397 | ||
398 | cupsdPauseListening(); | |
399 | ||
bd7854cb | 400 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
401 | lis; | |
402 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
ef416fc2 | 403 | { |
a4d04587 | 404 | if (lis->fd != -1) |
405 | { | |
ef416fc2 | 406 | #ifdef WIN32 |
a4d04587 | 407 | closesocket(lis->fd); |
ef416fc2 | 408 | #else |
a4d04587 | 409 | close(lis->fd); |
ef416fc2 | 410 | #endif /* WIN32 */ |
411 | ||
412 | #ifdef AF_LOCAL | |
4400e98d | 413 | /* |
414 | * Remove domain sockets... | |
415 | */ | |
ef416fc2 | 416 | |
4400e98d | 417 | # ifdef HAVE_LAUNCH_H |
418 | if (lis->address.addr.sa_family == AF_LOCAL && !Launchd) | |
419 | # else | |
a4d04587 | 420 | if (lis->address.addr.sa_family == AF_LOCAL) |
4400e98d | 421 | # endif /* HAVE_LAUNCH_H */ |
a4d04587 | 422 | unlink(lis->address.un.sun_path); |
ef416fc2 | 423 | #endif /* AF_LOCAL */ |
a4d04587 | 424 | } |
ef416fc2 | 425 | } |
426 | } | |
427 | ||
428 | ||
429 | /* | |
f2d18633 | 430 | * End of "$Id$". |
ef416fc2 | 431 | */ |