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