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