]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/listen.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / scheduler / listen.c
CommitLineData
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 *
e3101897 7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 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
bd7854cb 27/*
28 * 'cupsdDeleteAllListeners()' - Delete all listeners.
29 */
30
31void
32cupsdDeleteAllListeners(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))
1166bf58 40#ifdef HAVE_ONDEMAND
6e6adc4f 41 if (!lis->on_demand)
c187d9ab 42#endif /* HAVE_ONDEMAND */
6e6adc4f
MS
43 {
44 cupsArrayRemove(Listeners, lis);
45 free(lis);
46 }
bd7854cb 47
6e6adc4f
MS
48 if (cupsArrayCount(Listeners) == 0)
49 {
50 cupsArrayDelete(Listeners);
51 Listeners = NULL;
52 }
bd7854cb 53}
54
55
ef416fc2 56/*
57 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
58 */
59
60void
61cupsdPauseListening(void)
62{
ef416fc2 63 cupsd_listener_t *lis; /* Current listening socket */
64
65
bd7854cb 66 if (cupsArrayCount(Listeners) < 1)
ef416fc2 67 return;
68
bd7854cb 69 if (cupsArrayCount(Clients) == MaxClients)
ef416fc2 70 cupsdLogMessage(CUPSD_LOG_WARN,
71 "Max clients reached, holding new connections...");
76cd9e37
MS
72 else if (errno == ENFILE || errno == EMFILE)
73 cupsdLogMessage(CUPSD_LOG_WARN,
74 "Too many open files, holding new connections for "
75 "30 seconds...");
ef416fc2 76
bd7854cb 77 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
ef416fc2 78
bd7854cb 79 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
80 lis;
81 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f7deaa1a 82 cupsdRemoveSelect(lis->fd);
76cd9e37
MS
83
84 ListeningPaused = time(NULL) + 30;
ef416fc2 85}
86
87
88/*
89 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
90 */
91
92void
93cupsdResumeListening(void)
94{
ef416fc2 95 cupsd_listener_t *lis; /* Current listening socket */
96
97
bd7854cb 98 if (cupsArrayCount(Listeners) < 1)
ef416fc2 99 return;
100
76cd9e37 101 cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
bd7854cb 102 cupsdLogMessage(CUPSD_LOG_DEBUG2,
103 "cupsdResumeListening: Setting input bits...");
ef416fc2 104
bd7854cb 105 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
106 lis;
107 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f7deaa1a 108 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
76cd9e37
MS
109
110 ListeningPaused = 0;
ef416fc2 111}
112
113
114/*
115 * 'cupsdStartListening()' - Create all listening sockets...
116 */
117
118void
119cupsdStartListening(void)
120{
87e98392 121 int p; /* Port number */
ef416fc2 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
bd7854cb 134 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
135 cupsArrayCount(Listeners));
ef416fc2 136
ef416fc2 137 /*
138 * Setup socket listeners...
139 */
140
bd7854cb 141 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
142 have_domain = NULL;
143 lis;
144 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 145 {
146 httpAddrString(&(lis->address), s, sizeof(s));
a469f8a5 147 p = httpAddrPort(&(lis->address));
ef416fc2 148
149 /*
a4d04587 150 * If needed, create a socket for listening...
ef416fc2 151 */
152
ef416fc2 153 if (lis->fd == -1)
154 {
ef416fc2 155 /*
a4d04587 156 * Create a socket for listening...
ef416fc2 157 */
bd7854cb 158
87e98392 159 lis->fd = httpAddrListen(&(lis->address), p);
bd7854cb 160
a4d04587 161 if (lis->fd == -1)
162 {
163 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 164 "Unable to open listen socket for address %s:%d - %s.",
a4d04587 165 s, p, strerror(errno));
49d87452
MS
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
a4d04587 180 continue;
181 }
ef416fc2 182 }
ef416fc2 183
ef416fc2 184 if (p)
bd7854cb 185 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
ef416fc2 186 s, p, lis->fd);
187 else
bd7854cb 188 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
ef416fc2 189 s, lis->fd);
190
191 /*
192 * Save the first port that is bound to the local loopback or
193 * "any" address...
194 */
195
8ca02f3c 196 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
ef416fc2 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,
07725fee 217 "No Listen or Port lines were found to allow access via "
87e98392 218 "localhost.");
ef416fc2 219
49d87452
MS
220 if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
221 cupsdEndProcess(getpid(), 0);
ef416fc2 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);
8ca02f3c 236
237 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
ef416fc2 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]);
07725fee 249
250 if (LocalPort)
251 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
ef416fc2 252
253 /*
254 * Resume listening for connections...
255 */
256
257 cupsdResumeListening();
258}
259
260
261/*
262 * 'cupsdStopListening()' - Close all listening sockets...
263 */
264
265void
266cupsdStopListening(void)
267{
ef416fc2 268 cupsd_listener_t *lis; /* Current listening socket */
269
270
bd7854cb 271 cupsdLogMessage(CUPSD_LOG_DEBUG2,
ef416fc2 272 "cupsdStopListening: closing all listen sockets.");
273
274 cupsdPauseListening();
275
bd7854cb 276 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
277 lis;
278 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 279 {
1166bf58 280#ifdef HAVE_ONDEMAND
6e6adc4f
MS
281 if (!lis->on_demand && lis->fd != -1)
282 {
1720786e 283 httpAddrClose(&(lis->address), lis->fd);
6e6adc4f
MS
284 lis->fd = -1;
285 }
1720786e 286
ef416fc2 287#else
1720786e 288 if (lis->fd != -1)
6e6adc4f 289 {
87e98392 290 httpAddrClose(&(lis->address), lis->fd);
6e6adc4f
MS
291 lis->fd = -1;
292 }
c187d9ab 293#endif /* HAVE_ONDEMAND */
ef416fc2 294 }
295}