]> 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/*
f7deaa1a 2 * "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $"
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))
f7deaa1a 93 cupsdRemoveSelect(lis->fd);
ef416fc2 94}
95
96
97/*
98 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
99 */
100
101void
102cupsdResumeListening(void)
103{
ef416fc2 104 cupsd_listener_t *lis; /* Current listening socket */
105
106
bd7854cb 107 if (cupsArrayCount(Listeners) < 1)
ef416fc2 108 return;
109
bd7854cb 110 if (cupsArrayCount(Clients) >= (MaxClients - 1))
ef416fc2 111 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
112
bd7854cb 113 cupsdLogMessage(CUPSD_LOG_DEBUG2,
114 "cupsdResumeListening: Setting input bits...");
ef416fc2 115
bd7854cb 116 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
117 lis;
118 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
f7deaa1a 119 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
ef416fc2 120}
121
122
123/*
124 * 'cupsdStartListening()' - Create all listening sockets...
125 */
126
127void
128cupsdStartListening(void)
129{
130 int status; /* Bind result */
bd7854cb 131 int p, /* Port number */
ef416fc2 132 val; /* Parameter value */
133 cupsd_listener_t *lis; /* Current listening socket */
134 char s[256]; /* String addresss */
135 const char *have_domain; /* Have a domain socket? */
136 static const char * const encryptions[] =
137 { /* Encryption values */
138 "IfRequested",
139 "Never",
140 "Required",
141 "Always"
142 };
143
144
bd7854cb 145 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
146 cupsArrayCount(Listeners));
ef416fc2 147
148 /*
149 * Get the server's IP address...
150 */
151
152 if (ServerAddrs)
153 httpAddrFreeList(ServerAddrs);
154
155 if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
156 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 157 "Unable to find IP address for server name \"%s\"!\n",
158 ServerName);
ef416fc2 159
160 /*
161 * Setup socket listeners...
162 */
163
bd7854cb 164 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
165 have_domain = NULL;
166 lis;
167 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 168 {
169 httpAddrString(&(lis->address), s, sizeof(s));
170
171#ifdef AF_INET6
172 if (lis->address.addr.sa_family == AF_INET6)
173 p = ntohs(lis->address.ipv6.sin6_port);
174 else
175#endif /* AF_INET6 */
176#ifdef AF_LOCAL
177 if (lis->address.addr.sa_family == AF_LOCAL)
178 p = 0;
179 else
180#endif /* AF_LOCAL */
181 p = ntohs(lis->address.ipv4.sin_port);
182
183 /*
a4d04587 184 * If needed, create a socket for listening...
ef416fc2 185 */
186
ef416fc2 187 if (lis->fd == -1)
188 {
ef416fc2 189 /*
a4d04587 190 * Create a socket for listening...
ef416fc2 191 */
bd7854cb 192
a4d04587 193 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
bd7854cb 194
a4d04587 195 if (lis->fd == -1)
196 {
197 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 198 "Unable to open listen socket for address %s:%d - %s.",
a4d04587 199 s, p, strerror(errno));
200 continue;
201 }
bd7854cb 202
ef416fc2 203 /*
a4d04587 204 * Set things up to reuse the local address for this port.
ef416fc2 205 */
bd7854cb 206
a4d04587 207 val = 1;
e00b005a 208#ifdef __sun
a4d04587 209 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
e00b005a 210#else
a4d04587 211 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
e00b005a 212#endif /* __sun */
bd7854cb 213
ef416fc2 214 /*
a4d04587 215 * Bind to the port we found...
ef416fc2 216 */
bd7854cb 217
e00b005a 218#ifdef AF_INET6
a4d04587 219 if (lis->address.addr.sa_family == AF_INET6)
220 {
e00b005a 221# ifdef IPV6_V6ONLY
a4d04587 222 /*
223 * Accept only IPv6 connections on this socket, to avoid
224 * potential security issues and to make all platforms behave
225 * the same.
226 */
bd7854cb 227
a4d04587 228 val = 1;
e00b005a 229# ifdef __sun
a4d04587 230 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
e00b005a 231# else
a4d04587 232 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
e00b005a 233# endif /* __sun */
234# endif /* IPV6_V6ONLY */
bd7854cb 235
a4d04587 236 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
237 httpAddrLength(&(lis->address)));
238 }
239 else
e00b005a 240#endif /* AF_INET6 */
241#ifdef AF_LOCAL
a4d04587 242 if (lis->address.addr.sa_family == AF_LOCAL)
243 {
244 mode_t mask; /* Umask setting */
bd7854cb 245
246
a4d04587 247 /*
248 * Remove any existing domain socket file...
249 */
bd7854cb 250
a4d04587 251 unlink(lis->address.un.sun_path);
bd7854cb 252
a4d04587 253 /*
254 * Save the curent umask and set it to 0...
255 */
bd7854cb 256
a4d04587 257 mask = umask(0);
bd7854cb 258
a4d04587 259 /*
260 * Bind the domain socket...
261 */
bd7854cb 262
a4d04587 263 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
264 httpAddrLength(&(lis->address)));
bd7854cb 265
a4d04587 266 /*
267 * Restore the umask...
268 */
bd7854cb 269
a4d04587 270 umask(mask);
271 }
272 else
e00b005a 273#endif /* AF_LOCAL */
ef416fc2 274 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
a4d04587 275 sizeof(lis->address.ipv4));
bd7854cb 276
a4d04587 277 if (status < 0)
278 {
279 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 280 "Unable to bind socket for address %s:%d - %s.",
a4d04587 281 s, p, strerror(errno));
282 close(lis->fd);
283 lis->fd = -1;
284 continue;
285 }
bd7854cb 286
ef416fc2 287 /*
a4d04587 288 * Listen for new clients.
ef416fc2 289 */
bd7854cb 290
a4d04587 291 if (listen(lis->fd, ListenBackLog) < 0)
292 {
293 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 294 "Unable to listen for clients on address %s:%d - %s.",
a4d04587 295 s, p, strerror(errno));
296 exit(errno);
297 }
ef416fc2 298 }
ef416fc2 299
a4d04587 300 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
ef416fc2 301
302 if (p)
bd7854cb 303 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
ef416fc2 304 s, p, lis->fd);
305 else
4400e98d 306 {
bd7854cb 307 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
ef416fc2 308 s, lis->fd);
309
4400e98d 310 if (chmod(s, 0140777))
311 cupsdLogMessage(CUPSD_LOG_ERROR,
bd7854cb 312 "Unable to change permisssions on domain socket "
313 "\"%s\" - %s", s, strerror(errno));
4400e98d 314 }
315
ef416fc2 316 /*
317 * Save the first port that is bound to the local loopback or
318 * "any" address...
319 */
320
8ca02f3c 321 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
ef416fc2 322 (httpAddrLocalhost(&(lis->address)) ||
323 httpAddrAny(&(lis->address))))
324 {
325 LocalPort = p;
326 LocalEncryption = lis->encryption;
327 }
328
329#ifdef AF_LOCAL
330 if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
331 have_domain = lis->address.un.sun_path;
332#endif /* AF_LOCAL */
333 }
334
335 /*
336 * Make sure that we are listening on localhost!
337 */
338
339 if (!LocalPort && !have_domain)
340 {
341 cupsdLogMessage(CUPSD_LOG_EMERG,
07725fee 342 "No Listen or Port lines were found to allow access via "
343 "localhost!");
ef416fc2 344
345 /*
346 * Commit suicide...
347 */
348
349 cupsdEndProcess(getpid(), 0);
350 }
351
352 /*
353 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
354 * the listeners...
355 */
356
357 if (have_domain)
358 {
359 /*
360 * Use domain sockets for the local connection...
361 */
362
363 cupsdSetEnv("CUPS_SERVER", have_domain);
8ca02f3c 364
365 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
ef416fc2 366 }
367 else
368 {
369 /*
370 * Use the default local loopback address for the server...
371 */
372
373 cupsdSetEnv("CUPS_SERVER", "localhost");
374 }
375
376 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
07725fee 377
378 if (LocalPort)
379 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
ef416fc2 380
381 /*
382 * Resume listening for connections...
383 */
384
385 cupsdResumeListening();
386}
387
388
389/*
390 * 'cupsdStopListening()' - Close all listening sockets...
391 */
392
393void
394cupsdStopListening(void)
395{
ef416fc2 396 cupsd_listener_t *lis; /* Current listening socket */
397
398
bd7854cb 399 cupsdLogMessage(CUPSD_LOG_DEBUG2,
ef416fc2 400 "cupsdStopListening: closing all listen sockets.");
401
402 cupsdPauseListening();
403
bd7854cb 404 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
405 lis;
406 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
ef416fc2 407 {
a4d04587 408 if (lis->fd != -1)
409 {
ef416fc2 410#ifdef WIN32
a4d04587 411 closesocket(lis->fd);
ef416fc2 412#else
a4d04587 413 close(lis->fd);
ef416fc2 414#endif /* WIN32 */
415
416#ifdef AF_LOCAL
4400e98d 417 /*
418 * Remove domain sockets...
419 */
ef416fc2 420
4400e98d 421# ifdef HAVE_LAUNCH_H
422 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
423# else
a4d04587 424 if (lis->address.addr.sa_family == AF_LOCAL)
4400e98d 425# endif /* HAVE_LAUNCH_H */
a4d04587 426 unlink(lis->address.un.sun_path);
ef416fc2 427#endif /* AF_LOCAL */
a4d04587 428 }
ef416fc2 429 }
430}
431
432
433/*
f7deaa1a 434 * End of "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $".
ef416fc2 435 */