]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/listen.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / listen.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: listen.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * Server listening routines for the Common UNIX Printing System (CUPS)
5 * scheduler.
6 *
bc44d920 7 * Copyright 2007 by Apple Inc.
4400e98d 8 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 9 *
10 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 15 *
16 * Contents:
17 *
bd7854cb 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...
ef416fc2 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
bd7854cb 42/*
43 * 'cupsdDeleteAllListeners()' - Delete all listeners.
44 */
45
46void
47cupsdDeleteAllListeners(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
ef416fc2 62/*
63 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
64 */
65
66void
67cupsdPauseListening(void)
68{
ef416fc2 69 cupsd_listener_t *lis; /* Current listening socket */
70
71
bd7854cb 72 if (cupsArrayCount(Listeners) < 1)
ef416fc2 73 return;
74
bd7854cb 75 if (cupsArrayCount(Clients) == MaxClients)
ef416fc2 76 cupsdLogMessage(CUPSD_LOG_WARN,
77 "Max clients reached, holding new connections...");
78
bd7854cb 79 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
ef416fc2 80
bd7854cb 81 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
82 lis;
83 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f7deaa1a 84 cupsdRemoveSelect(lis->fd);
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
bd7854cb 101 if (cupsArrayCount(Clients) >= (MaxClients - 1))
ef416fc2 102 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
103
bd7854cb 104 cupsdLogMessage(CUPSD_LOG_DEBUG2,
105 "cupsdResumeListening: Setting input bits...");
ef416fc2 106
bd7854cb 107 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
108 lis;
109 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f7deaa1a 110 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
ef416fc2 111}
112
113
114/*
115 * 'cupsdStartListening()' - Create all listening sockets...
116 */
117
118void
119cupsdStartListening(void)
120{
121 int status; /* Bind result */
bd7854cb 122 int p, /* Port number */
ef416fc2 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
bd7854cb 136 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
137 cupsArrayCount(Listeners));
ef416fc2 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,
bd7854cb 148 "Unable to find IP address for server name \"%s\"!\n",
149 ServerName);
ef416fc2 150
151 /*
152 * Setup socket listeners...
153 */
154
bd7854cb 155 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
156 have_domain = NULL;
157 lis;
158 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 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 /*
a4d04587 175 * If needed, create a socket for listening...
ef416fc2 176 */
177
ef416fc2 178 if (lis->fd == -1)
179 {
ef416fc2 180 /*
a4d04587 181 * Create a socket for listening...
ef416fc2 182 */
bd7854cb 183
a4d04587 184 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
bd7854cb 185
a4d04587 186 if (lis->fd == -1)
187 {
188 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 189 "Unable to open listen socket for address %s:%d - %s.",
a4d04587 190 s, p, strerror(errno));
191 continue;
192 }
bd7854cb 193
ef416fc2 194 /*
a4d04587 195 * Set things up to reuse the local address for this port.
ef416fc2 196 */
bd7854cb 197
a4d04587 198 val = 1;
e00b005a 199#ifdef __sun
a4d04587 200 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
e00b005a 201#else
a4d04587 202 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
e00b005a 203#endif /* __sun */
bd7854cb 204
ef416fc2 205 /*
a4d04587 206 * Bind to the port we found...
ef416fc2 207 */
bd7854cb 208
e00b005a 209#ifdef AF_INET6
a4d04587 210 if (lis->address.addr.sa_family == AF_INET6)
211 {
e00b005a 212# ifdef IPV6_V6ONLY
a4d04587 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 */
bd7854cb 218
a4d04587 219 val = 1;
e00b005a 220# ifdef __sun
a4d04587 221 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
e00b005a 222# else
a4d04587 223 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
e00b005a 224# endif /* __sun */
225# endif /* IPV6_V6ONLY */
bd7854cb 226
a4d04587 227 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
228 httpAddrLength(&(lis->address)));
229 }
230 else
e00b005a 231#endif /* AF_INET6 */
232#ifdef AF_LOCAL
a4d04587 233 if (lis->address.addr.sa_family == AF_LOCAL)
234 {
235 mode_t mask; /* Umask setting */
bd7854cb 236
237
a4d04587 238 /*
239 * Remove any existing domain socket file...
240 */
bd7854cb 241
a4d04587 242 unlink(lis->address.un.sun_path);
bd7854cb 243
a4d04587 244 /*
245 * Save the curent umask and set it to 0...
246 */
bd7854cb 247
a4d04587 248 mask = umask(0);
bd7854cb 249
a4d04587 250 /*
251 * Bind the domain socket...
252 */
bd7854cb 253
a4d04587 254 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
255 httpAddrLength(&(lis->address)));
bd7854cb 256
a4d04587 257 /*
258 * Restore the umask...
259 */
bd7854cb 260
a4d04587 261 umask(mask);
262 }
263 else
e00b005a 264#endif /* AF_LOCAL */
ef416fc2 265 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
a4d04587 266 sizeof(lis->address.ipv4));
bd7854cb 267
a4d04587 268 if (status < 0)
269 {
270 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 271 "Unable to bind socket for address %s:%d - %s.",
a4d04587 272 s, p, strerror(errno));
273 close(lis->fd);
274 lis->fd = -1;
275 continue;
276 }
bd7854cb 277
ef416fc2 278 /*
a4d04587 279 * Listen for new clients.
ef416fc2 280 */
bd7854cb 281
a4d04587 282 if (listen(lis->fd, ListenBackLog) < 0)
283 {
284 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 285 "Unable to listen for clients on address %s:%d - %s.",
a4d04587 286 s, p, strerror(errno));
287 exit(errno);
288 }
ef416fc2 289 }
ef416fc2 290
a4d04587 291 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
ef416fc2 292
293 if (p)
bd7854cb 294 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
ef416fc2 295 s, p, lis->fd);
296 else
4400e98d 297 {
bd7854cb 298 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
ef416fc2 299 s, lis->fd);
300
4400e98d 301 if (chmod(s, 0140777))
302 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 303 "Unable to change permisssions on domain socket "
304 "\"%s\" - %s", s, strerror(errno));
4400e98d 305 }
306
ef416fc2 307 /*
308 * Save the first port that is bound to the local loopback or
309 * "any" address...
310 */
311
8ca02f3c 312 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
ef416fc2 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,
07725fee 333 "No Listen or Port lines were found to allow access via "
334 "localhost!");
ef416fc2 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);
8ca02f3c 355
356 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
ef416fc2 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]);
07725fee 368
369 if (LocalPort)
370 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
ef416fc2 371
372 /*
373 * Resume listening for connections...
374 */
375
376 cupsdResumeListening();
377}
378
379
380/*
381 * 'cupsdStopListening()' - Close all listening sockets...
382 */
383
384void
385cupsdStopListening(void)
386{
ef416fc2 387 cupsd_listener_t *lis; /* Current listening socket */
388
389
bd7854cb 390 cupsdLogMessage(CUPSD_LOG_DEBUG2,
ef416fc2 391 "cupsdStopListening: closing all listen sockets.");
392
393 cupsdPauseListening();
394
bd7854cb 395 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
396 lis;
397 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 398 {
a4d04587 399 if (lis->fd != -1)
400 {
ef416fc2 401#ifdef WIN32
a4d04587 402 closesocket(lis->fd);
ef416fc2 403#else
a4d04587 404 close(lis->fd);
ef416fc2 405#endif /* WIN32 */
406
407#ifdef AF_LOCAL
4400e98d 408 /*
409 * Remove domain sockets...
410 */
ef416fc2 411
4400e98d 412# ifdef HAVE_LAUNCH_H
413 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
414# else
a4d04587 415 if (lis->address.addr.sa_family == AF_LOCAL)
4400e98d 416# endif /* HAVE_LAUNCH_H */
a4d04587 417 unlink(lis->address.un.sun_path);
ef416fc2 418#endif /* AF_LOCAL */
a4d04587 419 }
ef416fc2 420 }
421}
422
423
424/*
bc44d920 425 * End of "$Id: listen.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 426 */