]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/listen.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / listen.c
1 /*
2 * "$Id: listen.c 5083 2006-02-06 02:57:43Z 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
55 void
56 cupsdDeleteAllListeners(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
75 void
76 cupsdPauseListening(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 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
108 void
109 cupsdResumeListening(void)
110 {
111 cupsd_listener_t *lis; /* Current listening socket */
112
113
114 if (cupsArrayCount(Listeners) < 1)
115 return;
116
117 if (cupsArrayCount(Clients) >= (MaxClients - 1))
118 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
119
120 cupsdLogMessage(CUPSD_LOG_DEBUG2,
121 "cupsdResumeListening: Setting input bits...");
122
123 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
124 lis;
125 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
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
140 void
141 cupsdStartListening(void)
142 {
143 int status; /* Bind result */
144 int p, /* Port number */
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
158 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
159 cupsArrayCount(Listeners));
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,
170 "Unable to find IP address for server name \"%s\"!\n",
171 ServerName);
172
173 /*
174 * Setup socket listeners...
175 */
176
177 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
178 have_domain = NULL;
179 lis;
180 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
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 /*
197 * If needed, create a socket for listening...
198 */
199
200 if (lis->fd == -1)
201 {
202 /*
203 * Create a socket for listening...
204 */
205
206 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
207
208 if (lis->fd == -1)
209 {
210 cupsdLogMessage(CUPSD_LOG_ERROR,
211 "Unable to open listen socket for address %s:%d - %s.",
212 s, p, strerror(errno));
213 continue;
214 }
215
216 /*
217 * Set things up to reuse the local address for this port.
218 */
219
220 val = 1;
221 #ifdef __sun
222 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
223 #else
224 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
225 #endif /* __sun */
226
227 /*
228 * Bind to the port we found...
229 */
230
231 #ifdef AF_INET6
232 if (lis->address.addr.sa_family == AF_INET6)
233 {
234 # ifdef IPV6_V6ONLY
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 */
240
241 val = 1;
242 # ifdef __sun
243 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
244 # else
245 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
246 # endif /* __sun */
247 # endif /* IPV6_V6ONLY */
248
249 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
250 httpAddrLength(&(lis->address)));
251 }
252 else
253 #endif /* AF_INET6 */
254 #ifdef AF_LOCAL
255 if (lis->address.addr.sa_family == AF_LOCAL)
256 {
257 mode_t mask; /* Umask setting */
258
259
260 /*
261 * Remove any existing domain socket file...
262 */
263
264 unlink(lis->address.un.sun_path);
265
266 /*
267 * Save the curent umask and set it to 0...
268 */
269
270 mask = umask(0);
271
272 /*
273 * Bind the domain socket...
274 */
275
276 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
277 httpAddrLength(&(lis->address)));
278
279 /*
280 * Restore the umask...
281 */
282
283 umask(mask);
284 }
285 else
286 #endif /* AF_LOCAL */
287 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
288 sizeof(lis->address.ipv4));
289
290 if (status < 0)
291 {
292 cupsdLogMessage(CUPSD_LOG_ERROR,
293 "Unable to bind socket for address %s:%d - %s.",
294 s, p, strerror(errno));
295 close(lis->fd);
296 lis->fd = -1;
297 continue;
298 }
299
300 /*
301 * Listen for new clients.
302 */
303
304 if (listen(lis->fd, ListenBackLog) < 0)
305 {
306 cupsdLogMessage(CUPSD_LOG_ERROR,
307 "Unable to listen for clients on address %s:%d - %s.",
308 s, p, strerror(errno));
309 exit(errno);
310 }
311 }
312
313 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
314
315 if (p)
316 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
317 s, p, lis->fd);
318 else
319 {
320 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
321 s, lis->fd);
322
323 if (chmod(s, 0140777))
324 cupsdLogMessage(CUPSD_LOG_ERROR,
325 "Unable to change permisssions on domain socket "
326 "\"%s\" - %s", s, strerror(errno));
327 }
328
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
401 void
402 cupsdStopListening(void)
403 {
404 cupsd_listener_t *lis; /* Current listening socket */
405
406
407 cupsdLogMessage(CUPSD_LOG_DEBUG2,
408 "cupsdStopListening: closing all listen sockets.");
409
410 cupsdPauseListening();
411
412 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
413 lis;
414 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
415 {
416 if (lis->fd != -1)
417 {
418 #ifdef WIN32
419 closesocket(lis->fd);
420 #else
421 close(lis->fd);
422 #endif /* WIN32 */
423
424 #ifdef AF_LOCAL
425 /*
426 * Remove domain sockets...
427 */
428
429 # ifdef HAVE_LAUNCH_H
430 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
431 # else
432 if (lis->address.addr.sa_family == AF_LOCAL)
433 # endif /* HAVE_LAUNCH_H */
434 unlink(lis->address.un.sun_path);
435 #endif /* AF_LOCAL */
436 }
437 }
438 }
439
440
441 /*
442 * End of "$Id: listen.c 5083 2006-02-06 02:57:43Z mike $".
443 */