]> 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/*
2 * "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $"
3 *
4 * Server listening routines for the Common UNIX Printing System (CUPS)
5 * scheduler.
6 *
7 * Copyright 1997-2005 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
54void
55cupsdPauseListening(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
86void
87cupsdResumeListening(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
116void
117cupsdStartListening(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 * Create a socket for listening...
173 */
174
175 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
176
177 if (lis->fd == -1)
178 {
179 cupsdLogMessage(CUPSD_LOG_ERROR,
180 "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.",
181 s, p, strerror(errno));
182 continue;
183 }
184
185 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
186
187 /*
188 * Set things up to reuse the local address for this port.
189 */
190
191 val = 1;
192#ifdef __sun
193 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
194#else
195 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
196#endif /* __sun */
197
198 /*
199 * Bind to the port we found...
200 */
201
202#ifdef AF_INET6
203 if (lis->address.addr.sa_family == AF_INET6)
204 {
205# ifdef IPV6_V6ONLY
206 /*
207 * Accept only IPv6 connections on this socket, to avoid
208 * potential security issues and to make all platforms behave
209 * the same.
210 */
211
212 val = 1;
213# ifdef __sun
214 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
215# else
216 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
217# endif /* __sun */
218# endif /* IPV6_V6ONLY */
219
220 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
221 httpAddrLength(&(lis->address)));
222 }
223 else
224#endif /* AF_INET6 */
225#ifdef AF_LOCAL
226 if (lis->address.addr.sa_family == AF_LOCAL)
227 {
228 mode_t mask; /* Umask setting */
229
230
231 /*
232 * Remove any existing domain socket file...
233 */
234
235 unlink(lis->address.un.sun_path);
236
237 /*
238 * Save the curent umask and set it to 0...
239 */
240
241 mask = umask(0);
242
243 /*
244 * Bind the domain socket...
245 */
246
247 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
248 httpAddrLength(&(lis->address)));
249
250 /*
251 * Restore the umask...
252 */
253
254 umask(mask);
255 }
256 else
257#endif /* AF_LOCAL */
258 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
259 sizeof(lis->address.ipv4));
260
261 if (status < 0)
262 {
263 cupsdLogMessage(CUPSD_LOG_ERROR,
264 "cupsdStartListening: Unable to bind socket for address %s:%d - %s.",
265 s, p, strerror(errno));
266 close(lis->fd);
267 lis->fd = -1;
268 continue;
269 }
270
271 /*
272 * Listen for new clients.
273 */
274
275 if (listen(lis->fd, ListenBackLog) < 0)
276 {
277 cupsdLogMessage(CUPSD_LOG_ERROR,
278 "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.",
279 s, p, strerror(errno));
280 exit(errno);
281 }
282
283 if (p)
284 cupsdLogMessage(CUPSD_LOG_INFO,
285 "cupsdStartListening: Listening to %s:%d on fd %d...",
286 s, p, lis->fd);
287 else
288 cupsdLogMessage(CUPSD_LOG_INFO,
289 "cupsdStartListening: Listening to %s on fd %d...",
290 s, lis->fd);
291
292 /*
293 * Save the first port that is bound to the local loopback or
294 * "any" address...
295 */
296
297 if (!LocalPort && p > 0 &&
298 (httpAddrLocalhost(&(lis->address)) ||
299 httpAddrAny(&(lis->address))))
300 {
301 LocalPort = p;
302 LocalEncryption = lis->encryption;
303 }
304
305#ifdef AF_LOCAL
306 if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
307 have_domain = lis->address.un.sun_path;
308#endif /* AF_LOCAL */
309 }
310
311 /*
312 * Make sure that we are listening on localhost!
313 */
314
315 if (!LocalPort && !have_domain)
316 {
317 cupsdLogMessage(CUPSD_LOG_EMERG,
318 "No Listen or Port lines were found to allow access via localhost!");
319
320 /*
321 * Commit suicide...
322 */
323
324 cupsdEndProcess(getpid(), 0);
325 }
326
327 /*
328 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
329 * the listeners...
330 */
331
332 if (have_domain)
333 {
334 /*
335 * Use domain sockets for the local connection...
336 */
337
338 cupsdSetEnv("CUPS_SERVER", have_domain);
339 }
340 else
341 {
342 /*
343 * Use the default local loopback address for the server...
344 */
345
346 cupsdSetEnv("CUPS_SERVER", "localhost");
347 }
348
349 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
350 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
351
352 /*
353 * Resume listening for connections...
354 */
355
356 cupsdResumeListening();
357}
358
359
360/*
361 * 'cupsdStopListening()' - Close all listening sockets...
362 */
363
364void
365cupsdStopListening(void)
366{
367 int i; /* Looping var */
368 cupsd_listener_t *lis; /* Current listening socket */
369
370
371 cupsdLogMessage(CUPSD_LOG_DEBUG,
372 "cupsdStopListening: closing all listen sockets.");
373
374 cupsdPauseListening();
375
376 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
377 {
378#ifdef WIN32
379 closesocket(lis->fd);
380#else
381 close(lis->fd);
382#endif /* WIN32 */
383
384#ifdef AF_LOCAL
385 /*
386 * Remove domain sockets...
387 */
388
389 if (lis->address.addr.sa_family == AF_LOCAL)
390 unlink(lis->address.un.sun_path);
391#endif /* AF_LOCAL */
392 }
393}
394
395
396/*
397 * End of "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $".
398 */