Imported Upstream version 2.1.2
[platform/upstream/cups.git] / scheduler / listen.c
1 /*
2  * "$Id: listen.c 12178 2014-09-30 18:56:48Z msweet $"
3  *
4  * Server listening routines for the CUPS scheduler.
5  *
6  * Copyright 2007-2014 by Apple Inc.
7  * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8  *
9  * These coded instructions, statements, and computer programs are the
10  * property of Apple Inc. and are protected by Federal copyright
11  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  * which should have been included with this file.  If this file is
13  * file is missing or damaged, see the license at "http://www.cups.org/".
14  */
15
16 /*
17  * Include necessary headers...
18  */
19
20 #include "cupsd.h"
21
22
23 /*
24  * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
25  * glibc don't define it even if the kernel supports it...
26  */
27
28 #if defined(__linux) && !defined(IPV6_V6ONLY)
29 #  define IPV6_V6ONLY 26
30 #endif /* __linux && !IPV6_V6ONLY */
31
32
33 /*
34  * 'cupsdDeleteAllListeners()' - Delete all listeners.
35  */
36
37 void
38 cupsdDeleteAllListeners(void)
39 {
40   cupsd_listener_t      *lis;           /* Current listening socket */
41
42
43   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
44        lis;
45        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
46 #if defined(HAVE_LAUNCHD) || defined(HAVE_SYSTEMD)
47     if (!lis->on_demand)
48 #endif /* HAVE_LAUNCHD || HAVE_SYSTEMD */
49     {
50       cupsArrayRemove(Listeners, lis);
51       free(lis);
52     }
53
54   if (cupsArrayCount(Listeners) == 0)
55   {
56     cupsArrayDelete(Listeners);
57     Listeners = NULL;
58   }
59 }
60
61
62 /*
63  * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
64  */
65
66 void
67 cupsdPauseListening(void)
68 {
69   cupsd_listener_t      *lis;           /* Current listening socket */
70
71
72   if (cupsArrayCount(Listeners) < 1)
73     return;
74
75   if (cupsArrayCount(Clients) == MaxClients)
76     cupsdLogMessage(CUPSD_LOG_WARN,
77                     "Max clients reached, holding new connections...");
78   else if (errno == ENFILE || errno == EMFILE)
79     cupsdLogMessage(CUPSD_LOG_WARN,
80                     "Too many open files, holding new connections for "
81                     "30 seconds...");
82
83   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
84
85   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
86        lis;
87        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
88     cupsdRemoveSelect(lis->fd);
89
90   ListeningPaused = time(NULL) + 30;
91 }
92
93
94 /*
95  * 'cupsdResumeListening()' - Set input polling on all listening sockets...
96  */
97
98 void
99 cupsdResumeListening(void)
100 {
101   cupsd_listener_t      *lis;           /* Current listening socket */
102
103
104   if (cupsArrayCount(Listeners) < 1)
105     return;
106
107   cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
108   cupsdLogMessage(CUPSD_LOG_DEBUG2,
109                   "cupsdResumeListening: Setting input bits...");
110
111   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
112        lis;
113        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
114     cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
115
116   ListeningPaused = 0;
117 }
118
119
120 /*
121  * 'cupsdStartListening()' - Create all listening sockets...
122  */
123
124 void
125 cupsdStartListening(void)
126 {
127   int                   p;              /* Port number */
128   cupsd_listener_t      *lis;           /* Current listening socket */
129   char                  s[256];         /* String addresss */
130   const char            *have_domain;   /* Have a domain socket? */
131   static const char * const encryptions[] =
132                 {                       /* Encryption values */
133                   "IfRequested",
134                   "Never",
135                   "Required",
136                   "Always"
137                 };
138
139
140   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
141                   cupsArrayCount(Listeners));
142
143  /*
144   * Setup socket listeners...
145   */
146
147   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
148            have_domain = NULL;
149        lis;
150        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
151   {
152     httpAddrString(&(lis->address), s, sizeof(s));
153     p = httpAddrPort(&(lis->address));
154
155    /*
156     * If needed, create a socket for listening...
157     */
158
159     if (lis->fd == -1)
160     {
161      /*
162       * Create a socket for listening...
163       */
164
165       lis->fd = httpAddrListen(&(lis->address), p);
166
167       if (lis->fd == -1)
168       {
169         cupsdLogMessage(CUPSD_LOG_ERROR,
170                         "Unable to open listen socket for address %s:%d - %s.",
171                         s, p, strerror(errno));
172
173 #ifdef AF_INET6
174        /*
175         * IPv6 is often disabled while DNS returns IPv6 addresses...
176         */
177
178         if (lis->address.addr.sa_family != AF_INET6 &&
179             (FatalErrors & CUPSD_FATAL_LISTEN))
180           cupsdEndProcess(getpid(), 0);
181 #else
182         if (FatalErrors & CUPSD_FATAL_LISTEN)
183           cupsdEndProcess(getpid(), 0);
184 #endif /* AF_INET6 */
185
186         continue;
187       }
188     }
189
190     if (p)
191       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
192                       s, p, lis->fd);
193     else
194       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
195                       s, lis->fd);
196
197    /*
198     * Save the first port that is bound to the local loopback or
199     * "any" address...
200     */
201
202     if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
203         (httpAddrLocalhost(&(lis->address)) ||
204          httpAddrAny(&(lis->address))))
205     {
206       LocalPort       = p;
207       LocalEncryption = lis->encryption;
208     }
209
210 #ifdef AF_LOCAL
211     if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
212       have_domain = lis->address.un.sun_path;
213 #endif /* AF_LOCAL */
214   }
215
216  /*
217   * Make sure that we are listening on localhost!
218   */
219
220   if (!LocalPort && !have_domain)
221   {
222     cupsdLogMessage(CUPSD_LOG_EMERG,
223                     "No Listen or Port lines were found to allow access via "
224                     "localhost.");
225
226     if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
227       cupsdEndProcess(getpid(), 0);
228   }
229
230  /*
231   * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
232   * the listeners...
233   */
234
235   if (have_domain)
236   {
237    /*
238     * Use domain sockets for the local connection...
239     */
240
241     cupsdSetEnv("CUPS_SERVER", have_domain);
242
243     LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
244   }
245   else
246   {
247    /*
248     * Use the default local loopback address for the server...
249     */
250
251     cupsdSetEnv("CUPS_SERVER", "localhost");
252   }
253
254   cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
255
256   if (LocalPort)
257     cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
258
259  /*
260   * Resume listening for connections...
261   */
262
263   cupsdResumeListening();
264 }
265
266
267 /*
268  * 'cupsdStopListening()' - Close all listening sockets...
269  */
270
271 void
272 cupsdStopListening(void)
273 {
274   cupsd_listener_t      *lis;           /* Current listening socket */
275
276
277   cupsdLogMessage(CUPSD_LOG_DEBUG2,
278                   "cupsdStopListening: closing all listen sockets.");
279
280   cupsdPauseListening();
281
282   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
283        lis;
284        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
285   {
286 #if defined(HAVE_LAUNCHD) || defined(HAVE_SYSTEMD)
287     if (!lis->on_demand && lis->fd != -1)
288     {
289       httpAddrClose(&(lis->address), lis->fd);
290       lis->fd = -1;
291     }
292
293 #else
294     if (lis->fd != -1)
295     {
296       httpAddrClose(&(lis->address), lis->fd);
297       lis->fd = -1;
298     }
299 #endif /* HAVE_LAUNCHD || HAVE_SYSTEMD */
300   }
301 }
302
303
304 /*
305  * End of "$Id: listen.c 12178 2014-09-30 18:56:48Z msweet $".
306  */