]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
87e98392 | 2 | * Server listening routines for the CUPS scheduler. |
ef416fc2 | 3 | * |
1166bf58 | 4 | * Copyright 2007-2016 by Apple Inc. |
87e98392 | 5 | * Copyright 1997-2006 by Easy Software Products, all rights reserved. |
ef416fc2 | 6 | * |
87e98392 MS |
7 | * These coded instructions, statements, and computer programs are the |
8 | * property of Apple Inc. and are protected by Federal copyright | |
9 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
10 | * which should have been included with this file. If this file is | |
57b7b66b | 11 | * missing or damaged, see the license at "http://www.cups.org/". |
ef416fc2 | 12 | */ |
13 | ||
14 | /* | |
15 | * Include necessary headers... | |
16 | */ | |
17 | ||
18 | #include "cupsd.h" | |
19 | ||
20 | ||
21 | /* | |
22 | * Make sure the IPV6_V6ONLY is defined on Linux - older versions of | |
23 | * glibc don't define it even if the kernel supports it... | |
24 | */ | |
25 | ||
26 | #if defined(__linux) && !defined(IPV6_V6ONLY) | |
27 | # define IPV6_V6ONLY 26 | |
28 | #endif /* __linux && !IPV6_V6ONLY */ | |
29 | ||
30 | ||
bd7854cb | 31 | /* |
32 | * 'cupsdDeleteAllListeners()' - Delete all listeners. | |
33 | */ | |
34 | ||
35 | void | |
36 | cupsdDeleteAllListeners(void) | |
37 | { | |
38 | cupsd_listener_t *lis; /* Current listening socket */ | |
39 | ||
40 | ||
41 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); | |
42 | lis; | |
43 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
1166bf58 | 44 | #ifdef HAVE_ONDEMAND |
6e6adc4f | 45 | if (!lis->on_demand) |
c187d9ab | 46 | #endif /* HAVE_ONDEMAND */ |
6e6adc4f MS |
47 | { |
48 | cupsArrayRemove(Listeners, lis); | |
49 | free(lis); | |
50 | } | |
bd7854cb | 51 | |
6e6adc4f MS |
52 | if (cupsArrayCount(Listeners) == 0) |
53 | { | |
54 | cupsArrayDelete(Listeners); | |
55 | Listeners = NULL; | |
56 | } | |
bd7854cb | 57 | } |
58 | ||
59 | ||
ef416fc2 | 60 | /* |
61 | * 'cupsdPauseListening()' - Clear input polling on all listening sockets... | |
62 | */ | |
63 | ||
64 | void | |
65 | cupsdPauseListening(void) | |
66 | { | |
ef416fc2 | 67 | cupsd_listener_t *lis; /* Current listening socket */ |
68 | ||
69 | ||
bd7854cb | 70 | if (cupsArrayCount(Listeners) < 1) |
ef416fc2 | 71 | return; |
72 | ||
bd7854cb | 73 | if (cupsArrayCount(Clients) == MaxClients) |
ef416fc2 | 74 | cupsdLogMessage(CUPSD_LOG_WARN, |
75 | "Max clients reached, holding new connections..."); | |
76cd9e37 MS |
76 | else if (errno == ENFILE || errno == EMFILE) |
77 | cupsdLogMessage(CUPSD_LOG_WARN, | |
78 | "Too many open files, holding new connections for " | |
79 | "30 seconds..."); | |
ef416fc2 | 80 | |
bd7854cb | 81 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits..."); |
ef416fc2 | 82 | |
bd7854cb | 83 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
84 | lis; | |
85 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
f7deaa1a | 86 | cupsdRemoveSelect(lis->fd); |
76cd9e37 MS |
87 | |
88 | ListeningPaused = time(NULL) + 30; | |
ef416fc2 | 89 | } |
90 | ||
91 | ||
92 | /* | |
93 | * 'cupsdResumeListening()' - Set input polling on all listening sockets... | |
94 | */ | |
95 | ||
96 | void | |
97 | cupsdResumeListening(void) | |
98 | { | |
ef416fc2 | 99 | cupsd_listener_t *lis; /* Current listening socket */ |
100 | ||
101 | ||
bd7854cb | 102 | if (cupsArrayCount(Listeners) < 1) |
ef416fc2 | 103 | return; |
104 | ||
76cd9e37 | 105 | cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing..."); |
bd7854cb | 106 | cupsdLogMessage(CUPSD_LOG_DEBUG2, |
107 | "cupsdResumeListening: Setting input bits..."); | |
ef416fc2 | 108 | |
bd7854cb | 109 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
110 | lis; | |
111 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
f7deaa1a | 112 | cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis); |
76cd9e37 MS |
113 | |
114 | ListeningPaused = 0; | |
ef416fc2 | 115 | } |
116 | ||
117 | ||
118 | /* | |
119 | * 'cupsdStartListening()' - Create all listening sockets... | |
120 | */ | |
121 | ||
122 | void | |
123 | cupsdStartListening(void) | |
124 | { | |
87e98392 | 125 | int p; /* Port number */ |
ef416fc2 | 126 | cupsd_listener_t *lis; /* Current listening socket */ |
127 | char s[256]; /* String addresss */ | |
128 | const char *have_domain; /* Have a domain socket? */ | |
129 | static const char * const encryptions[] = | |
130 | { /* Encryption values */ | |
131 | "IfRequested", | |
132 | "Never", | |
133 | "Required", | |
134 | "Always" | |
135 | }; | |
136 | ||
137 | ||
bd7854cb | 138 | cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners", |
139 | cupsArrayCount(Listeners)); | |
ef416fc2 | 140 | |
ef416fc2 | 141 | /* |
142 | * Setup socket listeners... | |
143 | */ | |
144 | ||
bd7854cb | 145 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0, |
146 | have_domain = NULL; | |
147 | lis; | |
148 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
ef416fc2 | 149 | { |
150 | httpAddrString(&(lis->address), s, sizeof(s)); | |
a469f8a5 | 151 | p = httpAddrPort(&(lis->address)); |
ef416fc2 | 152 | |
153 | /* | |
a4d04587 | 154 | * If needed, create a socket for listening... |
ef416fc2 | 155 | */ |
156 | ||
ef416fc2 | 157 | if (lis->fd == -1) |
158 | { | |
ef416fc2 | 159 | /* |
a4d04587 | 160 | * Create a socket for listening... |
ef416fc2 | 161 | */ |
bd7854cb | 162 | |
87e98392 | 163 | lis->fd = httpAddrListen(&(lis->address), p); |
bd7854cb | 164 | |
a4d04587 | 165 | if (lis->fd == -1) |
166 | { | |
167 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
bd7854cb | 168 | "Unable to open listen socket for address %s:%d - %s.", |
a4d04587 | 169 | s, p, strerror(errno)); |
49d87452 MS |
170 | |
171 | #ifdef AF_INET6 | |
172 | /* | |
173 | * IPv6 is often disabled while DNS returns IPv6 addresses... | |
174 | */ | |
175 | ||
176 | if (lis->address.addr.sa_family != AF_INET6 && | |
177 | (FatalErrors & CUPSD_FATAL_LISTEN)) | |
178 | cupsdEndProcess(getpid(), 0); | |
179 | #else | |
180 | if (FatalErrors & CUPSD_FATAL_LISTEN) | |
181 | cupsdEndProcess(getpid(), 0); | |
182 | #endif /* AF_INET6 */ | |
183 | ||
a4d04587 | 184 | continue; |
185 | } | |
ef416fc2 | 186 | } |
ef416fc2 | 187 | |
ef416fc2 | 188 | if (p) |
bd7854cb | 189 | cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...", |
ef416fc2 | 190 | s, p, lis->fd); |
191 | else | |
bd7854cb | 192 | cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...", |
ef416fc2 | 193 | s, lis->fd); |
194 | ||
195 | /* | |
196 | * Save the first port that is bound to the local loopback or | |
197 | * "any" address... | |
198 | */ | |
199 | ||
8ca02f3c | 200 | if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 && |
ef416fc2 | 201 | (httpAddrLocalhost(&(lis->address)) || |
202 | httpAddrAny(&(lis->address)))) | |
203 | { | |
204 | LocalPort = p; | |
205 | LocalEncryption = lis->encryption; | |
206 | } | |
207 | ||
208 | #ifdef AF_LOCAL | |
209 | if (lis->address.addr.sa_family == AF_LOCAL && !have_domain) | |
210 | have_domain = lis->address.un.sun_path; | |
211 | #endif /* AF_LOCAL */ | |
212 | } | |
213 | ||
214 | /* | |
215 | * Make sure that we are listening on localhost! | |
216 | */ | |
217 | ||
218 | if (!LocalPort && !have_domain) | |
219 | { | |
220 | cupsdLogMessage(CUPSD_LOG_EMERG, | |
07725fee | 221 | "No Listen or Port lines were found to allow access via " |
87e98392 | 222 | "localhost."); |
ef416fc2 | 223 | |
49d87452 MS |
224 | if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN)) |
225 | cupsdEndProcess(getpid(), 0); | |
ef416fc2 | 226 | } |
227 | ||
228 | /* | |
229 | * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on | |
230 | * the listeners... | |
231 | */ | |
232 | ||
233 | if (have_domain) | |
234 | { | |
235 | /* | |
236 | * Use domain sockets for the local connection... | |
237 | */ | |
238 | ||
239 | cupsdSetEnv("CUPS_SERVER", have_domain); | |
8ca02f3c | 240 | |
241 | LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED; | |
ef416fc2 | 242 | } |
243 | else | |
244 | { | |
245 | /* | |
246 | * Use the default local loopback address for the server... | |
247 | */ | |
248 | ||
249 | cupsdSetEnv("CUPS_SERVER", "localhost"); | |
250 | } | |
251 | ||
252 | cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]); | |
07725fee | 253 | |
254 | if (LocalPort) | |
255 | cupsdSetEnvf("IPP_PORT", "%d", LocalPort); | |
ef416fc2 | 256 | |
257 | /* | |
258 | * Resume listening for connections... | |
259 | */ | |
260 | ||
261 | cupsdResumeListening(); | |
262 | } | |
263 | ||
264 | ||
265 | /* | |
266 | * 'cupsdStopListening()' - Close all listening sockets... | |
267 | */ | |
268 | ||
269 | void | |
270 | cupsdStopListening(void) | |
271 | { | |
ef416fc2 | 272 | cupsd_listener_t *lis; /* Current listening socket */ |
273 | ||
274 | ||
bd7854cb | 275 | cupsdLogMessage(CUPSD_LOG_DEBUG2, |
ef416fc2 | 276 | "cupsdStopListening: closing all listen sockets."); |
277 | ||
278 | cupsdPauseListening(); | |
279 | ||
bd7854cb | 280 | for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); |
281 | lis; | |
282 | lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) | |
ef416fc2 | 283 | { |
1166bf58 | 284 | #ifdef HAVE_ONDEMAND |
6e6adc4f MS |
285 | if (!lis->on_demand && lis->fd != -1) |
286 | { | |
1720786e | 287 | httpAddrClose(&(lis->address), lis->fd); |
6e6adc4f MS |
288 | lis->fd = -1; |
289 | } | |
1720786e | 290 | |
ef416fc2 | 291 | #else |
1720786e | 292 | if (lis->fd != -1) |
6e6adc4f | 293 | { |
87e98392 | 294 | httpAddrClose(&(lis->address), lis->fd); |
6e6adc4f MS |
295 | lis->fd = -1; |
296 | } | |
c187d9ab | 297 | #endif /* HAVE_ONDEMAND */ |
ef416fc2 | 298 | } |
299 | } |