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