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