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