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