]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/listen.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / listen.c
1 /*
2 * "$Id: listen.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * Server listening routines for the Common UNIX Printing System (CUPS)
5 * scheduler.
6 *
7 * Copyright 2007 by Apple Inc.
8 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
9 *
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
15 *
16 * Contents:
17 *
18 * cupsdDeleteAllListeners() - Delete all listeners.
19 * cupsdPauseListening() - Clear input polling on all listening sockets...
20 * cupsdResumeListening() - Set input polling on all listening sockets...
21 * cupsdStartListening() - Create all listening sockets...
22 * cupsdStopListening() - Close all listening sockets...
23 */
24
25 /*
26 * Include necessary headers...
27 */
28
29 #include "cupsd.h"
30
31
32 /*
33 * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
34 * glibc don't define it even if the kernel supports it...
35 */
36
37 #if defined(__linux) && !defined(IPV6_V6ONLY)
38 # define IPV6_V6ONLY 26
39 #endif /* __linux && !IPV6_V6ONLY */
40
41
42 /*
43 * 'cupsdDeleteAllListeners()' - Delete all listeners.
44 */
45
46 void
47 cupsdDeleteAllListeners(void)
48 {
49 cupsd_listener_t *lis; /* Current listening socket */
50
51
52 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
53 lis;
54 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
55 free(lis);
56
57 cupsArrayDelete(Listeners);
58 Listeners = NULL;
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
79 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
80
81 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
82 lis;
83 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
84 cupsdRemoveSelect(lis->fd);
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 if (cupsArrayCount(Clients) >= (MaxClients - 1))
102 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
103
104 cupsdLogMessage(CUPSD_LOG_DEBUG2,
105 "cupsdResumeListening: Setting input bits...");
106
107 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
108 lis;
109 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
110 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
111 }
112
113
114 /*
115 * 'cupsdStartListening()' - Create all listening sockets...
116 */
117
118 void
119 cupsdStartListening(void)
120 {
121 int status; /* Bind result */
122 int p, /* Port number */
123 val; /* Parameter value */
124 cupsd_listener_t *lis; /* Current listening socket */
125 char s[256]; /* String addresss */
126 const char *have_domain; /* Have a domain socket? */
127 static const char * const encryptions[] =
128 { /* Encryption values */
129 "IfRequested",
130 "Never",
131 "Required",
132 "Always"
133 };
134
135
136 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
137 cupsArrayCount(Listeners));
138
139 /*
140 * Get the server's IP address...
141 */
142
143 if (ServerAddrs)
144 httpAddrFreeList(ServerAddrs);
145
146 if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
147 cupsdLogMessage(CUPSD_LOG_ERROR,
148 "Unable to find IP address for server name \"%s\"!\n",
149 ServerName);
150
151 /*
152 * Setup socket listeners...
153 */
154
155 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
156 have_domain = NULL;
157 lis;
158 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
159 {
160 httpAddrString(&(lis->address), s, sizeof(s));
161
162 #ifdef AF_INET6
163 if (lis->address.addr.sa_family == AF_INET6)
164 p = ntohs(lis->address.ipv6.sin6_port);
165 else
166 #endif /* AF_INET6 */
167 #ifdef AF_LOCAL
168 if (lis->address.addr.sa_family == AF_LOCAL)
169 p = 0;
170 else
171 #endif /* AF_LOCAL */
172 p = ntohs(lis->address.ipv4.sin_port);
173
174 /*
175 * If needed, create a socket for listening...
176 */
177
178 if (lis->fd == -1)
179 {
180 /*
181 * Create a socket for listening...
182 */
183
184 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
185
186 if (lis->fd == -1)
187 {
188 cupsdLogMessage(CUPSD_LOG_ERROR,
189 "Unable to open listen socket for address %s:%d - %s.",
190 s, p, strerror(errno));
191 continue;
192 }
193
194 /*
195 * Set things up to reuse the local address for this port.
196 */
197
198 val = 1;
199 #ifdef __sun
200 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
201 #else
202 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
203 #endif /* __sun */
204
205 /*
206 * Bind to the port we found...
207 */
208
209 #ifdef AF_INET6
210 if (lis->address.addr.sa_family == AF_INET6)
211 {
212 # ifdef IPV6_V6ONLY
213 /*
214 * Accept only IPv6 connections on this socket, to avoid
215 * potential security issues and to make all platforms behave
216 * the same.
217 */
218
219 val = 1;
220 # ifdef __sun
221 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
222 # else
223 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
224 # endif /* __sun */
225 # endif /* IPV6_V6ONLY */
226
227 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
228 httpAddrLength(&(lis->address)));
229 }
230 else
231 #endif /* AF_INET6 */
232 #ifdef AF_LOCAL
233 if (lis->address.addr.sa_family == AF_LOCAL)
234 {
235 mode_t mask; /* Umask setting */
236
237
238 /*
239 * Remove any existing domain socket file...
240 */
241
242 unlink(lis->address.un.sun_path);
243
244 /*
245 * Save the curent umask and set it to 0...
246 */
247
248 mask = umask(0);
249
250 /*
251 * Bind the domain socket...
252 */
253
254 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
255 httpAddrLength(&(lis->address)));
256
257 /*
258 * Restore the umask...
259 */
260
261 umask(mask);
262 }
263 else
264 #endif /* AF_LOCAL */
265 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
266 sizeof(lis->address.ipv4));
267
268 if (status < 0)
269 {
270 cupsdLogMessage(CUPSD_LOG_ERROR,
271 "Unable to bind socket for address %s:%d - %s.",
272 s, p, strerror(errno));
273 close(lis->fd);
274 lis->fd = -1;
275 continue;
276 }
277
278 /*
279 * Listen for new clients.
280 */
281
282 if (listen(lis->fd, ListenBackLog) < 0)
283 {
284 cupsdLogMessage(CUPSD_LOG_ERROR,
285 "Unable to listen for clients on address %s:%d - %s.",
286 s, p, strerror(errno));
287 exit(errno);
288 }
289 }
290
291 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
292
293 if (p)
294 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
295 s, p, lis->fd);
296 else
297 {
298 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
299 s, lis->fd);
300
301 if (chmod(s, 0140777))
302 cupsdLogMessage(CUPSD_LOG_ERROR,
303 "Unable to change permisssions on domain socket "
304 "\"%s\" - %s", s, strerror(errno));
305 }
306
307 /*
308 * Save the first port that is bound to the local loopback or
309 * "any" address...
310 */
311
312 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
313 (httpAddrLocalhost(&(lis->address)) ||
314 httpAddrAny(&(lis->address))))
315 {
316 LocalPort = p;
317 LocalEncryption = lis->encryption;
318 }
319
320 #ifdef AF_LOCAL
321 if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
322 have_domain = lis->address.un.sun_path;
323 #endif /* AF_LOCAL */
324 }
325
326 /*
327 * Make sure that we are listening on localhost!
328 */
329
330 if (!LocalPort && !have_domain)
331 {
332 cupsdLogMessage(CUPSD_LOG_EMERG,
333 "No Listen or Port lines were found to allow access via "
334 "localhost!");
335
336 /*
337 * Commit suicide...
338 */
339
340 cupsdEndProcess(getpid(), 0);
341 }
342
343 /*
344 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
345 * the listeners...
346 */
347
348 if (have_domain)
349 {
350 /*
351 * Use domain sockets for the local connection...
352 */
353
354 cupsdSetEnv("CUPS_SERVER", have_domain);
355
356 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
357 }
358 else
359 {
360 /*
361 * Use the default local loopback address for the server...
362 */
363
364 cupsdSetEnv("CUPS_SERVER", "localhost");
365 }
366
367 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
368
369 if (LocalPort)
370 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
371
372 /*
373 * Resume listening for connections...
374 */
375
376 cupsdResumeListening();
377 }
378
379
380 /*
381 * 'cupsdStopListening()' - Close all listening sockets...
382 */
383
384 void
385 cupsdStopListening(void)
386 {
387 cupsd_listener_t *lis; /* Current listening socket */
388
389
390 cupsdLogMessage(CUPSD_LOG_DEBUG2,
391 "cupsdStopListening: closing all listen sockets.");
392
393 cupsdPauseListening();
394
395 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
396 lis;
397 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
398 {
399 if (lis->fd != -1)
400 {
401 #ifdef WIN32
402 closesocket(lis->fd);
403 #else
404 close(lis->fd);
405 #endif /* WIN32 */
406
407 #ifdef AF_LOCAL
408 /*
409 * Remove domain sockets...
410 */
411
412 # ifdef HAVE_LAUNCH_H
413 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
414 # else
415 if (lis->address.addr.sa_family == AF_LOCAL)
416 # endif /* HAVE_LAUNCH_H */
417 unlink(lis->address.un.sun_path);
418 #endif /* AF_LOCAL */
419 }
420 }
421 }
422
423
424 /*
425 * End of "$Id: listen.c 6649 2007-07-11 21:46:42Z mike $".
426 */