1/*
2 * "$Id: listen.c 11093 2013-07-03 20:48:42Z 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
45void
46cupsdDeleteAllListeners(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
65void
66cupsdPauseListening(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
97void
98cupsdResumeListening(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
123void
124cupsdStartListening(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
389void
390cupsdStopListening(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 11093 2013-07-03 20:48:42Z msweet $".
431 */
432