Imported Upstream version 1.6.4
[platform/upstream/cups.git] / scheduler / listen.c
1 /*
2  * "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $"
3  *
4  *   Server listening routines for the CUPS scheduler.
5  *
6  *   Copyright 2007-2010 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  * Contents:
16  *
17  *   cupsdDeleteAllListeners() - Delete all listeners.
18  *   cupsdPauseListening()     - Clear input polling on all listening sockets...
19  *   cupsdResumeListening()    - Set input polling on all listening sockets...
20  *   cupsdStartListening()     - Create all listening sockets...
21  *   cupsdStopListening()      - Close all listening sockets...
22  */
23
24 /*
25  * Include necessary headers...
26  */
27
28 #include "cupsd.h"
29
30
31 /*
32  * Make sure the IPV6_V6ONLY is defined on Linux - older versions of
33  * glibc don't define it even if the kernel supports it...
34  */
35
36 #if defined(__linux) && !defined(IPV6_V6ONLY)
37 #  define IPV6_V6ONLY 26
38 #endif /* __linux && !IPV6_V6ONLY */
39
40
41 /*
42  * 'cupsdDeleteAllListeners()' - Delete all listeners.
43  */
44
45 void
46 cupsdDeleteAllListeners(void)
47 {
48   cupsd_listener_t      *lis;           /* Current listening socket */
49
50
51   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
52        lis;
53        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
54     free(lis);
55
56   cupsArrayDelete(Listeners);
57   Listeners = NULL;
58 }
59
60
61 /*
62  * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
63  */
64
65 void
66 cupsdPauseListening(void)
67 {
68   cupsd_listener_t      *lis;           /* Current listening socket */
69
70
71   if (cupsArrayCount(Listeners) < 1)
72     return;
73
74   if (cupsArrayCount(Clients) == MaxClients)
75     cupsdLogMessage(CUPSD_LOG_WARN,
76                     "Max clients reached, holding new connections...");
77   else if (errno == ENFILE || errno == EMFILE)
78     cupsdLogMessage(CUPSD_LOG_WARN,
79                     "Too many open files, holding new connections for "
80                     "30 seconds...");
81
82   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
83
84   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
85        lis;
86        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
87     cupsdRemoveSelect(lis->fd);
88
89   ListeningPaused = time(NULL) + 30;
90 }
91
92
93 /*
94  * 'cupsdResumeListening()' - Set input polling on all listening sockets...
95  */
96
97 void
98 cupsdResumeListening(void)
99 {
100   cupsd_listener_t      *lis;           /* Current listening socket */
101
102
103   if (cupsArrayCount(Listeners) < 1)
104     return;
105
106   cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
107   cupsdLogMessage(CUPSD_LOG_DEBUG2,
108                   "cupsdResumeListening: Setting input bits...");
109
110   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
111        lis;
112        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
113     cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
114
115   ListeningPaused = 0;
116 }
117
118
119 /*
120  * 'cupsdStartListening()' - Create all listening sockets...
121  */
122
123 void
124 cupsdStartListening(void)
125 {
126   int                   status;         /* Bind result */
127   int                   p,              /* Port number */
128                         val;            /* Parameter value */
129   cupsd_listener_t      *lis;           /* Current listening socket */
130   char                  s[256];         /* String addresss */
131   const char            *have_domain;   /* Have a domain socket? */
132   static const char * const encryptions[] =
133                 {                       /* Encryption values */
134                   "IfRequested",
135                   "Never",
136                   "Required",
137                   "Always"
138                 };
139
140
141   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
142                   cupsArrayCount(Listeners));
143
144  /*
145   * Setup socket listeners...
146   */
147
148   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
149            have_domain = NULL;
150        lis;
151        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
152   {
153     httpAddrString(&(lis->address), s, sizeof(s));
154     p = _httpAddrPort(&(lis->address));
155
156    /*
157     * If needed, create a socket for listening...
158     */
159
160     if (lis->fd == -1)
161     {
162      /*
163       * Create a socket for listening...
164       */
165
166       lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
167
168       if (lis->fd == -1)
169       {
170         cupsdLogMessage(CUPSD_LOG_ERROR,
171                         "Unable to open listen socket for address %s:%d - %s.",
172                         s, p, strerror(errno));
173
174 #ifdef AF_INET6
175        /*
176         * IPv6 is often disabled while DNS returns IPv6 addresses...
177         */
178
179         if (lis->address.addr.sa_family != AF_INET6 &&
180             (FatalErrors & CUPSD_FATAL_LISTEN))
181           cupsdEndProcess(getpid(), 0);
182 #else
183         if (FatalErrors & CUPSD_FATAL_LISTEN)
184           cupsdEndProcess(getpid(), 0);
185 #endif /* AF_INET6 */
186
187         continue;
188       }
189
190      /*
191       * Set things up to reuse the local address for this port.
192       */
193
194       val = 1;
195 #ifdef __sun
196       setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
197 #else
198       setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
199 #endif /* __sun */
200
201      /*
202       * Bind to the port we found...
203       */
204
205 #ifdef AF_INET6
206       if (lis->address.addr.sa_family == AF_INET6)
207       {
208 #  ifdef IPV6_V6ONLY
209        /*
210         * Accept only IPv6 connections on this socket, to avoid
211         * potential security issues and to make all platforms behave
212         * the same.
213         */
214
215         val = 1;
216 #    ifdef __sun
217         setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
218 #    else
219         setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
220 #    endif /* __sun */
221 #  endif /* IPV6_V6ONLY */
222
223         status = bind(lis->fd, (struct sockaddr *)&(lis->address),
224                       httpAddrLength(&(lis->address)));
225       }
226       else
227 #endif /* AF_INET6 */
228 #ifdef AF_LOCAL
229       if (lis->address.addr.sa_family == AF_LOCAL)
230       {
231         mode_t  mask;                   /* Umask setting */
232
233
234        /*
235         * Remove any existing domain socket file...
236         */
237
238         unlink(lis->address.un.sun_path);
239
240        /*
241         * Save the current umask and set it to 0 so that all users can access
242         * the domain socket...
243         */
244
245         mask = umask(0);
246
247        /*
248         * Bind the domain socket...
249         */
250
251         status = bind(lis->fd, (struct sockaddr *)&(lis->address),
252                       httpAddrLength(&(lis->address)));
253
254        /*
255         * Restore the umask...
256         */
257
258         umask(mask);
259       }
260       else
261 #endif /* AF_LOCAL */
262       status = bind(lis->fd, (struct sockaddr *)&(lis->address),
263                     sizeof(lis->address.ipv4));
264
265       if (status < 0)
266       {
267         cupsdLogMessage(CUPSD_LOG_ERROR,
268                         "Unable to bind socket for address %s:%d - %s.",
269                         s, p, strerror(errno));
270         close(lis->fd);
271         lis->fd = -1;
272
273         if (FatalErrors & CUPSD_FATAL_LISTEN)
274           cupsdEndProcess(getpid(), 0);
275
276         continue;
277       }
278
279      /*
280       * Listen for new clients.
281       */
282
283       if (listen(lis->fd, ListenBackLog) < 0)
284       {
285         cupsdLogMessage(CUPSD_LOG_ERROR,
286                         "Unable to listen for clients on address %s:%d - %s.",
287                         s, p, strerror(errno));
288
289         close(lis->fd);
290         lis->fd = -1;
291
292         if (FatalErrors & CUPSD_FATAL_LISTEN)
293           cupsdEndProcess(getpid(), 0);
294
295         continue;
296       }
297     }
298
299     fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
300
301     if (p)
302       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
303                       s, p, lis->fd);
304     else
305     {
306       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
307                       s, lis->fd);
308
309       if (chmod(s, 0140777))
310         cupsdLogMessage(CUPSD_LOG_ERROR,
311                         "Unable to change permisssions on domain socket "
312                         "\"%s\" - %s", s, strerror(errno));
313     }
314
315    /*
316     * Save the first port that is bound to the local loopback or
317     * "any" address...
318     */
319
320     if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
321         (httpAddrLocalhost(&(lis->address)) ||
322          httpAddrAny(&(lis->address))))
323     {
324       LocalPort       = p;
325       LocalEncryption = lis->encryption;
326     }
327
328 #ifdef AF_LOCAL
329     if (lis->address.addr.sa_family == AF_LOCAL && !have_domain)
330       have_domain = lis->address.un.sun_path;
331 #endif /* AF_LOCAL */
332   }
333
334  /*
335   * Make sure that we are listening on localhost!
336   */
337
338   if (!LocalPort && !have_domain)
339   {
340     cupsdLogMessage(CUPSD_LOG_EMERG,
341                     "No Listen or Port lines were found to allow access via "
342                     "localhost!");
343
344     if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
345       cupsdEndProcess(getpid(), 0);
346   }
347
348  /*
349   * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on
350   * the listeners...
351   */
352
353   if (have_domain)
354   {
355    /*
356     * Use domain sockets for the local connection...
357     */
358
359     cupsdSetEnv("CUPS_SERVER", have_domain);
360
361     LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
362   }
363   else
364   {
365    /*
366     * Use the default local loopback address for the server...
367     */
368
369     cupsdSetEnv("CUPS_SERVER", "localhost");
370   }
371
372   cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
373
374   if (LocalPort)
375     cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
376
377  /*
378   * Resume listening for connections...
379   */
380
381   cupsdResumeListening();
382 }
383
384
385 /*
386  * 'cupsdStopListening()' - Close all listening sockets...
387  */
388
389 void
390 cupsdStopListening(void)
391 {
392   cupsd_listener_t      *lis;           /* Current listening socket */
393
394
395   cupsdLogMessage(CUPSD_LOG_DEBUG2,
396                   "cupsdStopListening: closing all listen sockets.");
397
398   cupsdPauseListening();
399
400   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
401        lis;
402        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
403   {
404     if (lis->fd != -1)
405     {
406 #ifdef WIN32
407       closesocket(lis->fd);
408 #else
409       close(lis->fd);
410 #endif /* WIN32 */
411
412 #ifdef AF_LOCAL
413      /*
414       * Remove domain sockets...
415       */
416
417 #  ifdef HAVE_LAUNCH_H
418       if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
419 #  else
420       if (lis->address.addr.sa_family == AF_LOCAL)
421 #  endif /* HAVE_LAUNCH_H */
422         unlink(lis->address.un.sun_path);
423 #endif /* AF_LOCAL */
424     }
425   }
426 }
427
428
429 /*
430  * End of "$Id: listen.c 11173 2013-07-23 12:31:34Z msweet $".
431  */