]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/listen.c
2 * "$Id: listen.c 5083 2006-02-06 02:57:43Z mike $"
4 * Server listening routines for the Common UNIX Printing System (CUPS)
7 * Copyright 1997-2006 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 * 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...
35 * Include necessary headers...
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...
46 #if defined(__linux) && !defined(IPV6_V6ONLY)
47 # define IPV6_V6ONLY 26
48 #endif /* __linux && !IPV6_V6ONLY */
52 * 'cupsdDeleteAllListeners()' - Delete all listeners.
56 cupsdDeleteAllListeners(void)
58 cupsd_listener_t
*lis
; /* Current listening socket */
61 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
63 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
66 cupsArrayDelete(Listeners
);
72 * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
76 cupsdPauseListening(void)
78 cupsd_listener_t
*lis
; /* Current listening socket */
81 if (cupsArrayCount(Listeners
) < 1)
84 if (cupsArrayCount(Clients
) == MaxClients
)
85 cupsdLogMessage(CUPSD_LOG_WARN
,
86 "Max clients reached, holding new connections...");
88 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdPauseListening: Clearing input bits...");
90 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
92 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
95 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
96 "cupsdPauseListening: Removing fd %d from InputSet...",
99 FD_CLR(lis
->fd
, InputSet
);
105 * 'cupsdResumeListening()' - Set input polling on all listening sockets...
109 cupsdResumeListening(void)
111 cupsd_listener_t
*lis
; /* Current listening socket */
114 if (cupsArrayCount(Listeners
) < 1)
117 if (cupsArrayCount(Clients
) >= (MaxClients
- 1))
118 cupsdLogMessage(CUPSD_LOG_WARN
, "Resuming new connection processing...");
120 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
121 "cupsdResumeListening: Setting input bits...");
123 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
125 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
128 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
129 "cupsdResumeListening: Adding fd %d to InputSet...",
131 FD_SET(lis
->fd
, InputSet
);
137 * 'cupsdStartListening()' - Create all listening sockets...
141 cupsdStartListening(void)
143 int status
; /* Bind result */
144 int p
, /* Port number */
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 */
158 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartListening: %d Listeners",
159 cupsArrayCount(Listeners
));
162 * Get the server's IP address...
166 httpAddrFreeList(ServerAddrs
);
168 if ((ServerAddrs
= httpAddrGetList(ServerName
, AF_UNSPEC
, NULL
)) == NULL
)
169 cupsdLogMessage(CUPSD_LOG_ERROR
,
170 "Unable to find IP address for server name \"%s\"!\n",
174 * Setup socket listeners...
177 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
), LocalPort
= 0,
180 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
182 httpAddrString(&(lis
->address
), s
, sizeof(s
));
185 if (lis
->address
.addr
.sa_family
== AF_INET6
)
186 p
= ntohs(lis
->address
.ipv6
.sin6_port
);
188 #endif /* AF_INET6 */
190 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
193 #endif /* AF_LOCAL */
194 p
= ntohs(lis
->address
.ipv4
.sin_port
);
197 * If needed, create a socket for listening...
203 * Create a socket for listening...
206 lis
->fd
= socket(lis
->address
.addr
.sa_family
, SOCK_STREAM
, 0);
210 cupsdLogMessage(CUPSD_LOG_ERROR
,
211 "Unable to open listen socket for address %s:%d - %s.",
212 s
, p
, strerror(errno
));
217 * Set things up to reuse the local address for this port.
222 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&val
, sizeof(val
));
224 setsockopt(lis
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
228 * Bind to the port we found...
232 if (lis
->address
.addr
.sa_family
== AF_INET6
)
236 * Accept only IPv6 connections on this socket, to avoid
237 * potential security issues and to make all platforms behave
243 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
245 setsockopt(lis
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &val
, sizeof(val
));
247 # endif /* IPV6_V6ONLY */
249 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
250 httpAddrLength(&(lis
->address
)));
253 #endif /* AF_INET6 */
255 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
257 mode_t mask
; /* Umask setting */
261 * Remove any existing domain socket file...
264 unlink(lis
->address
.un
.sun_path
);
267 * Save the curent umask and set it to 0...
273 * Bind the domain socket...
276 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
277 httpAddrLength(&(lis
->address
)));
280 * Restore the umask...
286 #endif /* AF_LOCAL */
287 status
= bind(lis
->fd
, (struct sockaddr
*)&(lis
->address
),
288 sizeof(lis
->address
.ipv4
));
292 cupsdLogMessage(CUPSD_LOG_ERROR
,
293 "Unable to bind socket for address %s:%d - %s.",
294 s
, p
, strerror(errno
));
301 * Listen for new clients.
304 if (listen(lis
->fd
, ListenBackLog
) < 0)
306 cupsdLogMessage(CUPSD_LOG_ERROR
,
307 "Unable to listen for clients on address %s:%d - %s.",
308 s
, p
, strerror(errno
));
313 fcntl(lis
->fd
, F_SETFD
, fcntl(lis
->fd
, F_GETFD
) | FD_CLOEXEC
);
316 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s:%d on fd %d...",
320 cupsdLogMessage(CUPSD_LOG_INFO
, "Listening to %s on fd %d...",
323 if (chmod(s
, 0140777))
324 cupsdLogMessage(CUPSD_LOG_ERROR
,
325 "Unable to change permisssions on domain socket "
326 "\"%s\" - %s", s
, strerror(errno
));
330 * Save the first port that is bound to the local loopback or
334 if (!LocalPort
&& p
> 0 &&
335 (httpAddrLocalhost(&(lis
->address
)) ||
336 httpAddrAny(&(lis
->address
))))
339 LocalEncryption
= lis
->encryption
;
343 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !have_domain
)
344 have_domain
= lis
->address
.un
.sun_path
;
345 #endif /* AF_LOCAL */
349 * Make sure that we are listening on localhost!
352 if (!LocalPort
&& !have_domain
)
354 cupsdLogMessage(CUPSD_LOG_EMERG
,
355 "No Listen or Port lines were found to allow access via localhost!");
361 cupsdEndProcess(getpid(), 0);
365 * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
372 * Use domain sockets for the local connection...
375 cupsdSetEnv("CUPS_SERVER", have_domain
);
380 * Use the default local loopback address for the server...
383 cupsdSetEnv("CUPS_SERVER", "localhost");
386 cupsdSetEnv("CUPS_ENCRYPTION", encryptions
[LocalEncryption
]);
387 cupsdSetEnvf("IPP_PORT", "%d", LocalPort
);
390 * Resume listening for connections...
393 cupsdResumeListening();
398 * 'cupsdStopListening()' - Close all listening sockets...
402 cupsdStopListening(void)
404 cupsd_listener_t
*lis
; /* Current listening socket */
407 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
408 "cupsdStopListening: closing all listen sockets.");
410 cupsdPauseListening();
412 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
414 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
419 closesocket(lis
->fd
);
426 * Remove domain sockets...
429 # ifdef HAVE_LAUNCH_H
430 if (lis
->address
.addr
.sa_family
== AF_LOCAL
&& !Launchd
)
432 if (lis
->address
.addr
.sa_family
== AF_LOCAL
)
433 # endif /* HAVE_LAUNCH_H */
434 unlink(lis
->address
.un
.sun_path
);
435 #endif /* AF_LOCAL */
442 * End of "$Id: listen.c 5083 2006-02-06 02:57:43Z mike $".