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