]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/listen.c
4 * Server listening routines for the Common UNIX Printing System (CUPS)
7 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
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
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
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...
34 * Include necessary headers...
41 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
45 cupsdPauseListening(void)
47 int i
; /* Looping var */
48 cupsd_listener_t
*lis
; /* Current listening socket */
51 if (NumListeners
< 1 || !FD_ISSET(Listeners
[0].fd
, InputSet
))
54 if (NumClients
== MaxClients
)
55 cupsdLogMessage(CUPSD_LOG_WARN
,
56 "Max clients reached, holding new connections...");
58 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdPauseListening: Clearing input bits...");
60 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
62 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
63 "cupsdPauseListening: Removing fd %d from InputSet...",
66 FD_CLR(lis
->fd
, InputSet
);
72 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
76 cupsdResumeListening(void)
78 int i
; /* Looping var */
79 cupsd_listener_t
*lis
; /* Current listening socket */
82 if (NumListeners
< 1 || FD_ISSET(Listeners
[0].fd
, InputSet
))
85 if (NumClients
>= (MaxClients
- 1))
86 cupsdLogMessage(CUPSD_LOG_WARN
, "Resuming new connection processing...");
88 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdResumeListening: Setting input bits...");
90 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
92 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
93 "cupsdResumeListening: Adding fd %d to InputSet...",
95 FD_SET(lis
->fd
, InputSet
);
101 * 'cupsdStartListening()' - Create all listening sockets...
105 cupsdStartListening(void)
107 int status
; /* Bind result */
108 int i
, /* Looping var */
110 val
; /* Parameter value */
111 cupsd_listener_t
*lis
; /* Current listening socket */
112 char s
[256]; /* String addresss */
113 const char *have_domain
; /* Have a domain socket? */
114 static const char * const encryptions
[] =
115 { /* Encryption values */
123 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdStartListening: NumListeners=%d",
127 * Get the server's IP address...
131 httpAddrFreeList(ServerAddrs
);
133 if ((ServerAddrs
= httpAddrGetList(ServerName
, AF_UNSPEC
, NULL
)) == NULL
)
136 * Didn't find it! Use an address of 0...
139 cupsdLogMessage(CUPSD_LOG_ERROR
,
140 "cupsdStartListening: Unable to find IP address for server name \"%s\"!\n",
145 * Setup socket listeners...
148 for (i
= NumListeners
, lis
= Listeners
, LocalPort
= 0, have_domain
= NULL
;
151 httpAddrString(&(lis
->address
), s
, sizeof(s
));
154 if (lis
->address
.addr
.sa_family
== AF_INET6
)
155 p
= ntohs(lis
->address
.ipv6
.sin6_port
);
157 #endif /* AF_INET6 */
159 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
161 have_domain
= lis
->address
.un
.sun_path
;
165 #endif /* AF_LOCAL */
166 p
= ntohs(lis
->address
.ipv4
.sin_port
);
169 * Save the first port that is bound to the local loopback or
173 if (!LocalPort
&& p
> 0 &&
174 (httpAddrLocalhost(&(lis
->address
)) ||
175 httpAddrAny(&(lis
->address
))))
178 LocalEncryption
= lis
->encryption
;
182 * Create a socket for listening...
185 lis
->fd
= socket(lis
->address
.addr
.sa_family
, SOCK_STREAM
, 0);
188 if (lis
->fd
== -1 && lis
->address
.addr
.sa_family
== AF_INET6
&&
189 (httpAddrLocalhost(&(lis
->address
)) || httpAddrAny(&(lis
->address
))))
192 * Try binding to an IPv4 address instead...
195 cupsdLogMessage(CUPSD_LOG_NOTICE
,
196 "cupsdStartListening: Unable to use IPv6 address, trying IPv4...");
198 p
= ntohs(lis
->address
.ipv6
.sin6_port
);
200 if (httpAddrAny(&(lis
->address
)))
201 lis
->address
.ipv4
.sin_addr
.s_addr
= htonl(0x00000000);
203 lis
->address
.ipv4
.sin_addr
.s_addr
= htonl(0x7f000001);
205 lis
->address
.ipv4
.sin_port
= htons(p
);
206 lis
->address
.addr
.sa_family
= AF_INET
;
208 lis
->fd
= socket(lis
->address
.addr
.sa_family
, SOCK_STREAM
, 0);
210 #endif /* AF_INET6 */
214 cupsdLogMessage(CUPSD_LOG_ERROR
,
215 "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.",
216 s
, p
, strerror(errno
));
220 fcntl(lis
->fd
, F_SETFD
, fcntl(lis
->fd
, F_GETFD
) | FD_CLOEXEC
);
223 * Set things up to reuse the local address for this port.
228 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
, sizeof(val
));
230 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
234 * Bind to the port we found...
238 if (lis
->address
.addr
.sa_family
== AF_INET6
)
240 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
241 httpAddrLength(&(lis
->address
)));
245 (httpAddrLocalhost(&(lis
->address
)) || httpAddrAny(&(lis
->address
))))
248 * Make sure that wildcard and loopback addresses accept
249 * connections from both IPv6 and IPv4 clients.
251 * NOTE: This DOES NOT WORK for OpenBSD, since they adopted a
252 * stricter behavior in the name of security. For OpenBSD,
253 * you must list IPv4 and IPv6 listen addresses separately.
258 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
260 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &val
, sizeof(val
));
263 #endif /* IPV6_V6ONLY */
266 #endif /* AF_INET6 */
268 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
270 mode_t mask
; /* Umask setting */
274 * Remove any existing domain socket file...
277 unlink(lis
->address
.un
.sun_path
);
280 * Save the curent umask and set it to 0...
286 * Bind the domain socket...
289 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
290 httpAddrLength(&(lis
->address
)));
293 * Restore the umask...
299 #endif /* AF_LOCAL */
300 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
301 sizeof(lis
->address
.ipv4
));
305 cupsdLogMessage(CUPSD_LOG_ERROR
,
306 "cupsdStartListening: Unable to bind socket for address %s:%d - %s.",
307 s
, p
, strerror(errno
));
312 * Listen for new clients.
315 if (listen(lis
->fd
, ListenBackLog
) < 0)
317 cupsdLogMessage(CUPSD_LOG_ERROR
,
318 "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.",
319 s
, p
, strerror(errno
));
324 cupsdLogMessage(CUPSD_LOG_INFO
,
325 "cupsdStartListening: Listening to %s:%d on fd %d...",
328 cupsdLogMessage(CUPSD_LOG_INFO
,
329 "cupsdStartListening: Listening to %s on fd %d...",
334 * Make sure that we are listening on localhost!
337 if (!LocalPort
&& !have_domain
)
339 cupsdLogMessage(CUPSD_LOG_EMERG
,
340 "No Listen or Port lines were found to allow access via localhost!");
346 cupsdEndProcess(getpid(), 0);
350 * Set the CUPS_SERVER and IPP_PORT variables based on the listeners...
356 * Use domain sockets for the local connection...
359 cupsdSetEnv("CUPS_SERVER", have_domain
);
364 * Use the default local loopback address for the server...
367 cupsdSetEnv("CUPS_SERVER", "localhost");
368 cupsdSetEnvf("IPP_PORT", "%d", LocalPort
);
369 cupsdSetEnv("CUPS_ENCRYPTION", encryptions
[LocalEncryption
]);
373 * Resume listening for connections...
376 cupsdResumeListening();
381 * 'cupsdStopListening()' - Close all listening sockets...
385 cupsdStopListening(void)
387 int i
; /* Looping var */
388 cupsd_listener_t
*lis
; /* Current listening socket */
391 cupsdLogMessage(CUPSD_LOG_DEBUG
,
392 "cupsdStopListening: closing all listen sockets.");
394 cupsdPauseListening();
396 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
399 closesocket(lis
->fd
);
406 * Remove domain sockets...
409 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
410 unlink(lis
->address
.un
.sun_path
);
411 #endif /* AF_LOCAL */