]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/listen.c
Update scheduler to use new environment variable API - this reduces code
[thirdparty/cups.git] / scheduler / listen.c
CommitLineData
e82646f2 1/*
c9d3f842 2 * "$Id$"
e82646f2 3 *
4 * Server listening routines for the Common UNIX Printing System (CUPS)
5 * scheduler.
6 *
c9d3f842 7 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
e82646f2 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
8784b6a6 18 * 44141 Airport View Drive, Suite 204
8650fcf2 19 * Hollywood, Maryland 20636 USA
e82646f2 20 *
edfd3c3d 21 * Voice: (301) 373-9600
e82646f2 22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * Contents:
26 *
d236cb49 27 * PauseListening() - Clear input polling on all listening sockets...
28 * ResumeListening() - Set input polling on all listening sockets...
29 * StartListening() - Create all listening sockets...
30 * StopListening() - Close all listening sockets...
e82646f2 31 */
32
33/*
34 * Include necessary headers...
35 */
36
37#include "cupsd.h"
38
39
d236cb49 40/*
41 * 'PauseListening()' - Clear input polling on all listening sockets...
42 */
43
44void
45PauseListening(void)
46{
47 int i; /* Looping var */
48 listener_t *lis; /* Current listening socket */
49
50
5073e3f8 51 if (NumListeners < 1 || !FD_ISSET(Listeners[0].fd, InputSet))
d236cb49 52 return;
53
676cde07 54 if (NumClients == MaxClients)
55 LogMessage(L_WARN, "Max clients reached, holding new connections...");
56
18fe941f 57 LogMessage(L_DEBUG, "PauseListening: Clearing input bits...");
d236cb49 58
59 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
18fe941f 60 {
61 LogMessage(L_DEBUG2, "PauseListening: Removing fd %d from InputSet...",
62 lis->fd);
63
f3bc1068 64 FD_CLR(lis->fd, InputSet);
18fe941f 65 }
d236cb49 66}
67
68
69/*
70 * 'ResumeListening()' - Set input polling on all listening sockets...
71 */
72
73void
74ResumeListening(void)
75{
76 int i; /* Looping var */
77 listener_t *lis; /* Current listening socket */
78
79
5073e3f8 80 if (NumListeners < 1 || FD_ISSET(Listeners[0].fd, InputSet))
d236cb49 81 return;
82
676cde07 83 if (NumClients >= (MaxClients - 1))
84 LogMessage(L_WARN, "Resuming new connection processing...");
85
18fe941f 86 LogMessage(L_DEBUG, "ResumeListening: Setting input bits...");
d236cb49 87
88 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
18fe941f 89 {
90 LogMessage(L_DEBUG2, "ResumeListening: Adding fd %d to InputSet...",
91 lis->fd);
f3bc1068 92 FD_SET(lis->fd, InputSet);
18fe941f 93 }
d236cb49 94}
95
96
e82646f2 97/*
98 * 'StartListening()' - Create all listening sockets...
99 */
100
101void
102StartListening(void)
103{
c6075312 104 int status; /* Bind result */
105 int i, /* Looping var */
106 p, /* Port number */
107 val; /* Parameter value */
108 listener_t *lis; /* Current listening socket */
109 struct hostent *host; /* Host entry for server address */
110 char s[256]; /* String addresss */
291355eb 111 const char *have_domain; /* Have a domain socket? */
112 static const char * const encryptions[] =
113 { /* Encryption values */
114 "IfRequested",
115 "Never",
116 "Required",
117 "Always"
118 };
e82646f2 119
120
676cde07 121 LogMessage(L_DEBUG, "StartListening: NumListeners=%d", NumListeners);
d236cb49 122
2bdd1992 123 /*
124 * Get the server's IP address...
125 */
126
127 memset(&ServerAddr, 0, sizeof(ServerAddr));
128
753453e4 129 if ((host = httpGetHostByName(ServerName)) != NULL)
2bdd1992 130 {
131 /*
132 * Found the server's address!
133 */
134
99de6da0 135 httpAddrLoad(host, 0, 0, &ServerAddr);
2bdd1992 136 }
137 else
138 {
139 /*
140 * Didn't find it! Use an address of 0...
141 */
142
7e3ba0af 143 LogMessage(L_ERROR, "StartListening: Unable to find IP address for server name \"%s\" - %s\n",
144 ServerName, hstrerror(h_errno));
2bdd1992 145
99de6da0 146 ServerAddr.ipv4.sin_family = AF_INET;
2bdd1992 147 }
148
e82646f2 149 /*
150 * Setup socket listeners...
151 */
152
291355eb 153 for (i = NumListeners, lis = Listeners, LocalPort = 0, have_domain = NULL;
c6075312 154 i > 0; i --, lis ++)
e82646f2 155 {
99de6da0 156 httpAddrString(&(lis->address), s, sizeof(s));
157
158#ifdef AF_INET6
159 if (lis->address.addr.sa_family == AF_INET6)
11009aea 160 p = ntohs(lis->address.ipv6.sin6_port);
99de6da0 161 else
162#endif /* AF_INET6 */
c6075312 163#ifdef AF_LOCAL
164 if (lis->address.addr.sa_family == AF_LOCAL)
165 {
291355eb 166 have_domain = lis->address.un.sun_path;
c6075312 167 p = 0;
168 }
169 else
170#endif /* AF_LOCAL */
11009aea 171 p = ntohs(lis->address.ipv4.sin_port);
172
173 LogMessage(L_DEBUG, "StartListening: address=%s port=%d", s, p);
99de6da0 174
0f71c41e 175 /*
176 * Save the first port that is bound to the local loopback or
177 * "any" address...
178 */
179
c6075312 180 if (!LocalPort && p > 0 &&
e673c4b4 181 (httpAddrLocalhost(&(lis->address)) ||
182 httpAddrAny(&(lis->address))))
41d6188e 183 {
184 LocalPort = p;
185 LocalEncryption = lis->encryption;
186 }
0f71c41e 187
188 /*
189 * Create a socket for listening...
190 */
191
90aec4f7 192 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
193
194#ifdef AF_INET6
195 if (lis->fd == -1 && lis->address.addr.sa_family == AF_INET6 &&
196 (httpAddrLocalhost(&(lis->address)) || httpAddrAny(&(lis->address))))
197 {
198 /*
199 * Try binding to an IPv4 address instead...
200 */
201
202 LogMessage(L_NOTICE, "StartListening: Unable to use IPv6 address, trying IPv4...");
203
204 p = ntohs(lis->address.ipv6.sin6_port);
205
206 if (httpAddrAny(&(lis->address)))
207 lis->address.ipv4.sin_addr.s_addr = htonl(0x00000000);
208 else
209 lis->address.ipv4.sin_addr.s_addr = htonl(0x7f000001);
210
211 lis->address.ipv4.sin_port = htons(p);
212 lis->address.addr.sa_family = AF_INET;
213
214 lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
215 }
216#endif /* AF_INET6 */
217
218 if (lis->fd == -1)
e82646f2 219 {
11009aea 220 LogMessage(L_ERROR, "StartListening: Unable to open listen socket for address %s:%d - %s.",
221 s, p, strerror(errno));
e82646f2 222 exit(errno);
223 }
224
18fe941f 225 LogMessage(L_DEBUG2, "StartListening: fd=%d", lis->fd);
226
e82646f2 227 fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
228
229 /*
230 * Set things up to reuse the local address for this port.
231 */
232
233 val = 1;
234#ifdef __sun
235 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
236#else
237 setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
238#endif /* __sun */
239
240 /*
241 * Bind to the port we found...
242 */
243
a09840c5 244#ifdef AF_INET6
c6075312 245 if (lis->address.addr.sa_family == AF_INET6)
7c298ddc 246 {
c6075312 247 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
248 sizeof(lis->address.ipv6));
7c298ddc 249
62ca8094 250#ifdef IPV6_V6ONLY
90aec4f7 251 if (status >= 0 &&
252 (httpAddrLocalhost(&(lis->address)) || httpAddrAny(&(lis->address))))
62ca8094 253 {
254 /*
255 * Make sure that wildcard and loopback addresses accept
256 * connections from both IPv6 and IPv4 clients.
257 */
258
259 val = 0;
260# ifdef __sun
261 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
262# else
263 setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
264# endif /* __sun */
265 }
266#endif /* IPV6_V6ONLY */
7c298ddc 267 }
c6075312 268 else
269#endif /* AF_INET6 */
270#ifdef AF_LOCAL
271 if (lis->address.addr.sa_family == AF_LOCAL)
272 {
273 mode_t mask; /* Umask setting */
274
275
276 /*
277 * Remove any existing domain socket file...
278 */
279
280 unlink(lis->address.un.sun_path);
281
282 /*
283 * Save the curent umask and set it to 0...
284 */
285
286 mask = umask(0);
287
288 /*
289 * Bind the domain socket...
290 */
291
292 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
293 SUN_LEN(&(lis->address.un)));
294
295 /*
296 * Restore the umask...
297 */
298
299 umask(mask);
300 }
301 else
302#endif /* AF_LOCAL */
303 status = bind(lis->fd, (struct sockaddr *)&(lis->address),
304 sizeof(lis->address.ipv4));
305
306 if (status < 0)
e82646f2 307 {
11009aea 308 LogMessage(L_ERROR, "StartListening: Unable to bind socket for address %s:%d - %s.",
309 s, p, strerror(errno));
e82646f2 310 exit(errno);
311 }
312
313 /*
314 * Listen for new clients.
315 */
316
27eba2dd 317 if (listen(lis->fd, ListenBackLog) < 0)
e82646f2 318 {
11009aea 319 LogMessage(L_ERROR, "StartListening: Unable to listen for clients on address %s:%d - %s.",
320 s, p, strerror(errno));
e82646f2 321 exit(errno);
322 }
e82646f2 323 }
324
e673c4b4 325 /*
326 * Make sure that we are listening on localhost!
327 */
328
c6075312 329 if (!LocalPort && !have_domain)
e673c4b4 330 {
331 LogMessage(L_EMERG, "No Listen or Port lines were found to allow access via localhost!");
332
333 /*
334 * Commit suicide...
335 */
336
c316e838 337 cupsdEndProcess(getpid(), 0);
e673c4b4 338 }
339
291355eb 340 /*
341 * Set the CUPS_SERVER and IPP_PORT variables based on the listeners...
342 */
343
344 if (have_domain)
345 {
346 /*
347 * Use domain sockets for the local connection...
348 */
349
350 cupsdSetEnv("CUPS_SERVER", have_domain);
351 }
352 else
353 {
354 /*
355 * Use the default local loopback address for the server...
356 */
357
358 cupsdSetEnv("CUPS_SERVER", "localhost");
359 cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
360 cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
361 }
362
363 /*
364 * Resume listening for connections...
365 */
366
d236cb49 367 ResumeListening();
e82646f2 368}
369
370
371/*
372 * 'StopListening()' - Close all listening sockets...
373 */
374
375void
376StopListening(void)
377{
378 int i; /* Looping var */
379 listener_t *lis; /* Current listening socket */
380
381
676cde07 382 LogMessage(L_DEBUG, "StopListening: closing all listen sockets.");
d236cb49 383
384 PauseListening();
385
e82646f2 386 for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
c6075312 387 {
c3026ddc 388#ifdef WIN32
e82646f2 389 closesocket(lis->fd);
390#else
391 close(lis->fd);
c3026ddc 392#endif /* WIN32 */
c6075312 393
394#ifdef AF_LOCAL
395 /*
396 * Remove domain sockets...
397 */
398
399 if (lis->address.addr.sa_family == AF_LOCAL)
400 unlink(lis->address.un.sun_path);
401#endif /* AF_LOCAL */
402 }
e82646f2 403}
404
405
406/*
c9d3f842 407 * End of "$Id$".
e82646f2 408 */