]>
Commit | Line | Data |
---|---|---|
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 | ||
44 | void | |
45 | PauseListening(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 | ||
73 | void | |
74 | ResumeListening(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 | ||
101 | void | |
102 | StartListening(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 | ||
375 | void | |
376 | StopListening(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 | */ |