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