]> git.ipfire.org Git - thirdparty/cups.git/blame_incremental - scheduler/listen.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / listen.c
... / ...
CommitLineData
1/*
2 * "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $"
3 *
4 * Server listening routines for the Common UNIX Printing System (CUPS)
5 * scheduler.
6 *
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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 *
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...
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
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
71/*
72 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
73 */
74
75void
76cupsdPauseListening(void)
77{
78 cupsd_listener_t *lis; /* Current listening socket */
79
80
81 if (cupsArrayCount(Listeners) < 1)
82 return;
83
84 if (cupsArrayCount(Clients) == MaxClients)
85 cupsdLogMessage(CUPSD_LOG_WARN,
86 "Max clients reached, holding new connections...");
87
88 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
89
90 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
91 lis;
92 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
93 cupsdRemoveSelect(lis->fd);
94}
95
96
97/*
98 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
99 */
100
101void
102cupsdResumeListening(void)
103{
104 cupsd_listener_t *lis; /* Current listening socket */
105
106
107 if (cupsArrayCount(Listeners) < 1)
108 return;
109
110 if (cupsArrayCount(Clients) >= (MaxClients - 1))
111 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
112
113 cupsdLogMessage(CUPSD_LOG_DEBUG2,
114 "cupsdResumeListening: Setting input bits...");
115
116 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
117 lis;
118 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
119 cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
120}
121
122
123/*
124 * 'cupsdStartListening()' - Create all listening sockets...
125 */
126
127void
128cupsdStartListening(void)
129{
130 int status; /* Bind result */
131 int p, /* Port number */
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
145 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
146 cupsArrayCount(Listeners));
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,
157 "Unable to find IP address for server name \"%s\"!\n",
158 ServerName);
159
160 /*
161 * Setup socket listeners...
162 */
163
164 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
165 have_domain = NULL;
166 lis;
167 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
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 /*
184 * If needed, create a socket for listening...
185 */
186
187 if (lis->fd == -1)
188 {
189 /*
190 * Create a socket for listening...
191 */
192
193 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
194
195 if (lis->fd == -1)
196 {
197 cupsdLogMessage(CUPSD_LOG_ERROR,
198 "Unable to open listen socket for address %s:%d - %s.",
199 s, p, strerror(errno));
200 continue;
201 }
202
203 /*
204 * Set things up to reuse the local address for this port.
205 */
206
207 val = 1;
208#ifdef __sun
209 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
210#else
211 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
212#endif /* __sun */
213
214 /*
215 * Bind to the port we found...
216 */
217
218#ifdef AF_INET6
219 if (lis->address.addr.sa_family == AF_INET6)
220 {
221# ifdef IPV6_V6ONLY
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 */
227
228 val = 1;
229# ifdef __sun
230 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
231# else
232 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
233# endif /* __sun */
234# endif /* IPV6_V6ONLY */
235
236 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
237 httpAddrLength(&(lis->address)));
238 }
239 else
240#endif /* AF_INET6 */
241#ifdef AF_LOCAL
242 if (lis->address.addr.sa_family == AF_LOCAL)
243 {
244 mode_t mask; /* Umask setting */
245
246
247 /*
248 * Remove any existing domain socket file...
249 */
250
251 unlink(lis->address.un.sun_path);
252
253 /*
254 * Save the curent umask and set it to 0...
255 */
256
257 mask = umask(0);
258
259 /*
260 * Bind the domain socket...
261 */
262
263 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
264 httpAddrLength(&(lis->address)));
265
266 /*
267 * Restore the umask...
268 */
269
270 umask(mask);
271 }
272 else
273#endif /* AF_LOCAL */
274 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
275 sizeof(lis->address.ipv4));
276
277 if (status < 0)
278 {
279 cupsdLogMessage(CUPSD_LOG_ERROR,
280 "Unable to bind socket for address %s:%d - %s.",
281 s, p, strerror(errno));
282 close(lis->fd);
283 lis->fd = -1;
284 continue;
285 }
286
287 /*
288 * Listen for new clients.
289 */
290
291 if (listen(lis->fd, ListenBackLog) < 0)
292 {
293 cupsdLogMessage(CUPSD_LOG_ERROR,
294 "Unable to listen for clients on address %s:%d - %s.",
295 s, p, strerror(errno));
296 exit(errno);
297 }
298 }
299
300 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
301
302 if (p)
303 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
304 s, p, lis->fd);
305 else
306 {
307 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
308 s, lis->fd);
309
310 if (chmod(s, 0140777))
311 cupsdLogMessage(CUPSD_LOG_ERROR,
312 "Unable to change permisssions on domain socket "
313 "\"%s\" - %s", s, strerror(errno));
314 }
315
316 /*
317 * Save the first port that is bound to the local loopback or
318 * "any" address...
319 */
320
321 if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
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,
342 "No Listen or Port lines were found to allow access via "
343 "localhost!");
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);
364
365 LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
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]);
377
378 if (LocalPort)
379 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
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{
396 cupsd_listener_t *lis; /* Current listening socket */
397
398
399 cupsdLogMessage(CUPSD_LOG_DEBUG2,
400 "cupsdStopListening: closing all listen sockets.");
401
402 cupsdPauseListening();
403
404 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
405 lis;
406 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
407 {
408 if (lis->fd != -1)
409 {
410#ifdef WIN32
411 closesocket(lis->fd);
412#else
413 close(lis->fd);
414#endif /* WIN32 */
415
416#ifdef AF_LOCAL
417 /*
418 * Remove domain sockets...
419 */
420
421# ifdef HAVE_LAUNCH_H
422 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
423# else
424 if (lis->address.addr.sa_family == AF_LOCAL)
425# endif /* HAVE_LAUNCH_H */
426 unlink(lis->address.un.sun_path);
427#endif /* AF_LOCAL */
428 }
429 }
430}
431
432
433/*
434 * End of "$Id: listen.c 6123 2006-11-21 15:36:04Z mike $".
435 */