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