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