]> 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 5053 2006-02-02 18:14:38Z 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 * cupsdPauseListening() - Clear input polling on all listening sockets...
28 * cupsdResumeListening() - Set input polling on all listening sockets...
29 * cupsdStartListening() - Create all listening sockets...
30 * cupsdStopListening() - Close all listening sockets...
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include "cupsd.h"
38
39
40 /*
41 * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
42 * glibc don't define it even if the kernel supports it...
43 */
44
45 #if defined(__linux) && !defined(IPV6_V6ONLY)
46 # define IPV6_V6ONLY 26
47 #endif /* __linux && !IPV6_V6ONLY */
48
49
50 /*
51 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
52 */
53
54 void
55 cupsdPauseListening(void)
56 {
57 int i; /* Looping var */
58 cupsd_listener_t *lis; /* Current listening socket */
59
60
61 if (NumListeners < 1)
62 return;
63
64 if (NumClients == MaxClients)
65 cupsdLogMessage(CUPSD_LOG_WARN,
66 "Max clients reached, holding new connections...");
67
68 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdPauseListening: Clearing input bits...");
69
70 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
71 if (lis->fd >= 0)
72 {
73 cupsdLogMessage(CUPSD_LOG_DEBUG2,
74 "cupsdPauseListening: Removing fd %d from InputSet...",
75 lis->fd);
76
77 FD_CLR(lis->fd, InputSet);
78 }
79 }
80
81
82 /*
83 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
84 */
85
86 void
87 cupsdResumeListening(void)
88 {
89 int i; /* Looping var */
90 cupsd_listener_t *lis; /* Current listening socket */
91
92
93 if (NumListeners < 1)
94 return;
95
96 if (NumClients >= (MaxClients - 1))
97 cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
98
99 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdResumeListening: Setting input bits...");
100
101 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
102 if (lis->fd >= 0)
103 {
104 cupsdLogMessage(CUPSD_LOG_DEBUG2,
105 "cupsdResumeListening: Adding fd %d to InputSet...",
106 lis->fd);
107 FD_SET(lis->fd, InputSet);
108 }
109 }
110
111
112 /*
113 * 'cupsdStartListening()' - Create all listening sockets...
114 */
115
116 void
117 cupsdStartListening(void)
118 {
119 int status; /* Bind result */
120 int i, /* Looping var */
121 p, /* Port number */
122 val; /* Parameter value */
123 cupsd_listener_t *lis; /* Current listening socket */
124 char s[256]; /* String addresss */
125 const char *have_domain; /* Have a domain socket? */
126 static const char * const encryptions[] =
127 { /* Encryption values */
128 "IfRequested",
129 "Never",
130 "Required",
131 "Always"
132 };
133
134
135 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartListening: NumListeners=%d",
136 NumListeners);
137
138 /*
139 * Get the server's IP address...
140 */
141
142 if (ServerAddrs)
143 httpAddrFreeList(ServerAddrs);
144
145 if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
146 cupsdLogMessage(CUPSD_LOG_ERROR,
147 "cupsdStartListening: Unable to find IP address for "
148 "server name \"%s\"!\n", ServerName);
149
150 /*
151 * Setup socket listeners...
152 */
153
154 for (i = NumListeners, lis = Listeners, LocalPort = 0, have_domain = NULL;
155 i > 0; i --, lis ++)
156 {
157 httpAddrString(&(lis->address), s, sizeof(s));
158
159 #ifdef AF_INET6
160 if (lis->address.addr.sa_family == AF_INET6)
161 p = ntohs(lis->address.ipv6.sin6_port);
162 else
163 #endif /* AF_INET6 */
164 #ifdef AF_LOCAL
165 if (lis->address.addr.sa_family == AF_LOCAL)
166 p = 0;
167 else
168 #endif /* AF_LOCAL */
169 p = ntohs(lis->address.ipv4.sin_port);
170
171 /*
172 * If needed, create a socket for listening...
173 */
174
175 if (lis->fd == -1)
176 {
177 /*
178 * Create a socket for listening...
179 */
180
181 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
182
183 if (lis->fd == -1)
184 {
185 cupsdLogMessage(CUPSD_LOG_ERROR,
186 "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.",
187 s, p, strerror(errno));
188 continue;
189 }
190
191 /*
192 * Set things up to reuse the local address for this port.
193 */
194
195 val = 1;
196 #ifdef __sun
197 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
198 #else
199 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
200 #endif /* __sun */
201
202 /*
203 * Bind to the port we found...
204 */
205
206 #ifdef AF_INET6
207 if (lis->address.addr.sa_family == AF_INET6)
208 {
209 # ifdef IPV6_V6ONLY
210 /*
211 * Accept only IPv6 connections on this socket, to avoid
212 * potential security issues and to make all platforms behave
213 * the same.
214 */
215
216 val = 1;
217 # ifdef __sun
218 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
219 # else
220 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
221 # endif /* __sun */
222 # endif /* IPV6_V6ONLY */
223
224 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
225 httpAddrLength(&(lis->address)));
226 }
227 else
228 #endif /* AF_INET6 */
229 #ifdef AF_LOCAL
230 if (lis->address.addr.sa_family == AF_LOCAL)
231 {
232 mode_t mask; /* Umask setting */
233
234
235 /*
236 * Remove any existing domain socket file...
237 */
238
239 unlink(lis->address.un.sun_path);
240
241 /*
242 * Save the curent umask and set it to 0...
243 */
244
245 mask = umask(0);
246
247 /*
248 * Bind the domain socket...
249 */
250
251 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
252 httpAddrLength(&(lis->address)));
253
254 /*
255 * Restore the umask...
256 */
257
258 umask(mask);
259 }
260 else
261 #endif /* AF_LOCAL */
262 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
263 sizeof(lis->address.ipv4));
264
265 if (status < 0)
266 {
267 cupsdLogMessage(CUPSD_LOG_ERROR,
268 "cupsdStartListening: Unable to bind socket for address %s:%d - %s.",
269 s, p, strerror(errno));
270 close(lis->fd);
271 lis->fd = -1;
272 continue;
273 }
274
275 /*
276 * Listen for new clients.
277 */
278
279 if (listen(lis->fd, ListenBackLog) < 0)
280 {
281 cupsdLogMessage(CUPSD_LOG_ERROR,
282 "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.",
283 s, p, strerror(errno));
284 exit(errno);
285 }
286 }
287
288 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
289
290
291 if (p)
292 cupsdLogMessage(CUPSD_LOG_INFO,
293 "cupsdStartListening: Listening to %s:%d on fd %d...",
294 s, p, lis->fd);
295 else
296 {
297 cupsdLogMessage(CUPSD_LOG_INFO,
298 "cupsdStartListening: Listening to %s on fd %d...",
299 s, lis->fd);
300
301 if (chmod(s, 0140777))
302 cupsdLogMessage(CUPSD_LOG_ERROR,
303 "cupsdStartListening: Unable to change permisssions on "
304 "domain socket \"%s\" - %s", s, strerror(errno));
305 }
306
307 /*
308 * Save the first port that is bound to the local loopback or
309 * "any" address...
310 */
311
312 if (!LocalPort && p > 0 &&
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,
333 "No Listen or Port lines were found to allow access via localhost!");
334
335 /*
336 * Commit suicide...
337 */
338
339 cupsdEndProcess(getpid(), 0);
340 }
341
342 /*
343 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
344 * the listeners...
345 */
346
347 if (have_domain)
348 {
349 /*
350 * Use domain sockets for the local connection...
351 */
352
353 cupsdSetEnv("CUPS_SERVER", have_domain);
354 }
355 else
356 {
357 /*
358 * Use the default local loopback address for the server...
359 */
360
361 cupsdSetEnv("CUPS_SERVER", "localhost");
362 }
363
364 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
365 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
366
367 /*
368 * Resume listening for connections...
369 */
370
371 cupsdResumeListening();
372 }
373
374
375 /*
376 * 'cupsdStopListening()' - Close all listening sockets...
377 */
378
379 void
380 cupsdStopListening(void)
381 {
382 int i; /* Looping var */
383 cupsd_listener_t *lis; /* Current listening socket */
384
385
386 cupsdLogMessage(CUPSD_LOG_DEBUG,
387 "cupsdStopListening: closing all listen sockets.");
388
389 cupsdPauseListening();
390
391 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
392 {
393 if (lis->fd != -1)
394 {
395 #ifdef WIN32
396 closesocket(lis->fd);
397 #else
398 close(lis->fd);
399 #endif /* WIN32 */
400
401 #ifdef AF_LOCAL
402 /*
403 * Remove domain sockets...
404 */
405
406 # ifdef HAVE_LAUNCH_H
407 if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
408 # else
409 if (lis->address.addr.sa_family == AF_LOCAL)
410 # endif /* HAVE_LAUNCH_H */
411 unlink(lis->address.un.sun_path);
412 #endif /* AF_LOCAL */
413 }
414 }
415 }
416
417
418 /*
419 * End of "$Id: listen.c 5053 2006-02-02 18:14:38Z mike $".
420 */