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