]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/listen.c
b55d918b01e9c5bf0e515f19ee81653bcf03d831
[thirdparty/cups.git] / scheduler / listen.c
1 /*
2 * "$Id$"
3 *
4 * Server listening routines for the CUPS scheduler.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 *
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/".
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
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))
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 }
53
54 if (cupsArrayCount(Listeners) == 0)
55 {
56 cupsArrayDelete(Listeners);
57 Listeners = NULL;
58 }
59 }
60
61
62 /*
63 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
64 */
65
66 void
67 cupsdPauseListening(void)
68 {
69 cupsd_listener_t *lis; /* Current listening socket */
70
71
72 if (cupsArrayCount(Listeners) < 1)
73 return;
74
75 if (cupsArrayCount(Clients) == MaxClients)
76 cupsdLogMessage(CUPSD_LOG_WARN,
77 "Max clients reached, holding new connections...");
78 else if (errno == ENFILE || errno == EMFILE)
79 cupsdLogMessage(CUPSD_LOG_WARN,
80 "Too many open files, holding new connections for "
81 "30 seconds...");
82
83 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
84
85 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
86 lis;
87 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
88 cupsdRemoveSelect(lis->fd);
89
90 ListeningPaused = time(NULL) + 30;
91 }
92
93
94 /*
95 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
96 */
97
98 void
99 cupsdResumeListening(void)
100 {
101 cupsd_listener_t *lis; /* Current listening socket */
102
103
104 if (cupsArrayCount(Listeners) < 1)
105 return;
106
107 cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
108 cupsdLogMessage(CUPSD_LOG_DEBUG2,
109 "cupsdResumeListening: Setting input bits...");
110
111 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
112 lis;
113 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
114 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
115
116 ListeningPaused = 0;
117 }
118
119
120 /*
121 * 'cupsdStartListening()' - Create all listening sockets...
122 */
123
124 void
125 cupsdStartListening(void)
126 {
127 int p; /* Port number */
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
140 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
141 cupsArrayCount(Listeners));
142
143 /*
144 * Setup socket listeners...
145 */
146
147 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
148 have_domain = NULL;
149 lis;
150 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
151 {
152 httpAddrString(&(lis->address), s, sizeof(s));
153 p = httpAddrPort(&(lis->address));
154
155 /*
156 * If needed, create a socket for listening...
157 */
158
159 if (lis->fd == -1)
160 {
161 /*
162 * Create a socket for listening...
163 */
164
165 lis->fd = httpAddrListen(&(lis->address), p);
166
167 if (lis->fd == -1)
168 {
169 cupsdLogMessage(CUPSD_LOG_ERROR,
170 "Unable to open listen socket for address %s:%d - %s.",
171 s, p, strerror(errno));
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
186 continue;
187 }
188 }
189
190 if (p)
191 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
192 s, p, lis->fd);
193 else
194 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
195 s, lis->fd);
196
197 /*
198 * Save the first port that is bound to the local loopback or
199 * "any" address...
200 */
201
202 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
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,
223 "No Listen or Port lines were found to allow access via "
224 "localhost.");
225
226 if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
227 cupsdEndProcess(getpid(), 0);
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);
242
243 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
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]);
255
256 if (LocalPort)
257 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
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 {
274 cupsd_listener_t *lis; /* Current listening socket */
275
276
277 cupsdLogMessage(CUPSD_LOG_DEBUG2,
278 "cupsdStopListening: closing all listen sockets.");
279
280 cupsdPauseListening();
281
282 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
283 lis;
284 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
285 {
286 #if defined(HAVE_LAUNCHD) || defined(HAVE_SYSTEMD)
287 if (!lis->on_demand && lis->fd != -1)
288 {
289 httpAddrClose(&(lis->address), lis->fd);
290 lis->fd = -1;
291 }
292
293 #else
294 if (lis->fd != -1)
295 {
296 httpAddrClose(&(lis->address), lis->fd);
297 lis->fd = -1;
298 }
299 #endif /* HAVE_LAUNCHD || HAVE_SYSTEMD */
300 }
301 }
302
303
304 /*
305 * End of "$Id$".
306 */