]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/listen.c
Use httpAddrListen and new httpAddrClose in cupsd and other places that need it.
[thirdparty/cups.git] / scheduler / listen.c
index 176251cdcd820de2fc48884b2e96ed05b4aa5287..7ef4a3c92970db6862d59db03f3be6b571d4d82e 100644 (file)
@@ -1,33 +1,16 @@
 /*
- * "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $"
+ * "$Id$"
  *
- *   Server listening routines for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ * Server listening routines for the CUPS scheduler.
  *
- *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2013 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
- *
- * Contents:
- *
- *   cupsdPauseListening()  - Clear input polling on all listening sockets...
- *   cupsdResumeListening() - Set input polling on all listening sockets...
- *   cupsdStartListening()  - Create all listening sockets...
- *   cupsdStopListening()   - Close all listening sockets...
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file.  If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
 #endif /* __linux && !IPV6_V6ONLY */
 
 
+/*
+ * 'cupsdDeleteAllListeners()' - Delete all listeners.
+ */
+
+void
+cupsdDeleteAllListeners(void)
+{
+  cupsd_listener_t     *lis;           /* Current listening socket */
+
+
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+    free(lis);
+
+  cupsArrayDelete(Listeners);
+  Listeners = NULL;
+}
+
+
 /*
  * 'cupsdPauseListening()' - Clear input polling on all listening sockets...
  */
 void
 cupsdPauseListening(void)
 {
-  int                  i;              /* Looping var */
   cupsd_listener_t     *lis;           /* Current listening socket */
 
 
-  if (NumListeners < 1)
+  if (cupsArrayCount(Listeners) < 1)
     return;
 
-  if (NumClients == MaxClients)
+  if (cupsArrayCount(Clients) == MaxClients)
     cupsdLogMessage(CUPSD_LOG_WARN,
                     "Max clients reached, holding new connections...");
+  else if (errno == ENFILE || errno == EMFILE)
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Too many open files, holding new connections for "
+                   "30 seconds...");
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdPauseListening: Clearing input bits...");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdPauseListening: Clearing input bits...");
 
-  for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdPauseListening: Removing fd %d from InputSet...",
-                      lis->fd);
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+    cupsdRemoveSelect(lis->fd);
 
-      FD_CLR(lis->fd, InputSet);
-    }
+  ListeningPaused = time(NULL) + 30;
 }
 
 
@@ -86,26 +89,22 @@ cupsdPauseListening(void)
 void
 cupsdResumeListening(void)
 {
-  int                  i;              /* Looping var */
   cupsd_listener_t     *lis;           /* Current listening socket */
 
 
-  if (NumListeners < 1)
+  if (cupsArrayCount(Listeners) < 1)
     return;
 
-  if (NumClients >= (MaxClients - 1))
-    cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing...");
+  cupsdLogMessage(CUPSD_LOG_INFO, "Resuming new connection processing...");
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdResumeListening: Setting input bits...");
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdResumeListening: Setting input bits...");
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+    cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
 
-  for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdResumeListening: Adding fd %d to InputSet...",
-                      lis->fd);
-      FD_SET(lis->fd, InputSet);
-    }
+  ListeningPaused = 0;
 }
 
 
@@ -116,10 +115,7 @@ cupsdResumeListening(void)
 void
 cupsdStartListening(void)
 {
-  int                  status;         /* Bind result */
-  int                  i,              /* Looping var */
-                       p,              /* Port number */
-                       val;            /* Parameter value */
+  int                  p;              /* Port number */
   cupsd_listener_t     *lis;           /* Current listening socket */
   char                 s[256];         /* String addresss */
   const char           *have_domain;   /* Have a domain socket? */
@@ -132,161 +128,61 @@ cupsdStartListening(void)
                };
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartListening: NumListeners=%d",
-                  NumListeners);
-
- /*
-  * Get the server's IP address...
-  */
-
-  if (ServerAddrs)
-    httpAddrFreeList(ServerAddrs);
-
-  if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "cupsdStartListening: Unable to find IP address for "
-                   "server name \"%s\"!\n", ServerName);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
+                  cupsArrayCount(Listeners));
 
  /*
   * Setup socket listeners...
   */
 
-  for (i = NumListeners, lis = Listeners, LocalPort = 0, have_domain = NULL;
-       i > 0; i --, lis ++)
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners), LocalPort = 0,
+           have_domain = NULL;
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
   {
     httpAddrString(&(lis->address), s, sizeof(s));
-
-#ifdef AF_INET6
-    if (lis->address.addr.sa_family == AF_INET6)
-      p = ntohs(lis->address.ipv6.sin6_port);
-    else
-#endif /* AF_INET6 */
-#ifdef AF_LOCAL
-    if (lis->address.addr.sa_family == AF_LOCAL)
-      p = 0;
-    else
-#endif /* AF_LOCAL */
-    p = ntohs(lis->address.ipv4.sin_port);
+    p = httpAddrPort(&(lis->address));
 
    /*
-    * Create a socket for listening...
+    * If needed, create a socket for listening...
     */
 
-    lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
-
     if (lis->fd == -1)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.",
-                      s, p, strerror(errno));
-      continue;
-    }
-
-    fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
-
-   /*
-    * Set things up to reuse the local address for this port.
-    */
-
-    val = 1;
-#ifdef __sun
-    setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
-#else
-    setsockopt(lis->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-#endif /* __sun */
-
-   /*
-    * Bind to the port we found...
-    */
-
-#ifdef AF_INET6
-    if (lis->address.addr.sa_family == AF_INET6)
-    {
-#  ifdef IPV6_V6ONLY
      /*
-      * Accept only IPv6 connections on this socket, to avoid
-      * potential security issues and to make all platforms behave
-      * the same.
+      * Create a socket for listening...
       */
 
-      val = 1;
-#    ifdef __sun
-      setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
-#    else
-      setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
-#    endif /* __sun */
-#  endif /* IPV6_V6ONLY */
+      lis->fd = httpAddrListen(&(lis->address), p);
 
-      status = bind(lis->fd, (struct sockaddr *)&(lis->address),
-                   httpAddrLength(&(lis->address)));
-    }
-    else
-#endif /* AF_INET6 */
-#ifdef AF_LOCAL
-    if (lis->address.addr.sa_family == AF_LOCAL)
-    {
-      mode_t   mask;                   /* Umask setting */
-
-
-     /*
-      * Remove any existing domain socket file...
-      */
-
-      unlink(lis->address.un.sun_path);
-
-     /*
-      * Save the curent umask and set it to 0...
-      */
-
-      mask = umask(0);
-
-     /*
-      * Bind the domain socket...
-      */
-
-      status = bind(lis->fd, (struct sockaddr *)&(lis->address),
-                   httpAddrLength(&(lis->address)));
+      if (lis->fd == -1)
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to open listen socket for address %s:%d - %s.",
+                       s, p, strerror(errno));
 
-     /*
-      * Restore the umask...
-      */
-
-      umask(mask);
-    }
-    else
-#endif /* AF_LOCAL */
-    status = bind(lis->fd, (struct sockaddr *)&(lis->address),
-                  sizeof(lis->address.ipv4));
-
-    if (status < 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdStartListening: Unable to bind socket for address %s:%d - %s.",
-                      s, p, strerror(errno));
-      close(lis->fd);
-      lis->fd = -1;
-      continue;
-    }
+#ifdef AF_INET6
+       /*
+        * IPv6 is often disabled while DNS returns IPv6 addresses...
+       */
 
-   /*
-    * Listen for new clients.
-    */
+       if (lis->address.addr.sa_family != AF_INET6 &&
+           (FatalErrors & CUPSD_FATAL_LISTEN))
+         cupsdEndProcess(getpid(), 0);
+#else
+       if (FatalErrors & CUPSD_FATAL_LISTEN)
+         cupsdEndProcess(getpid(), 0);
+#endif /* AF_INET6 */
 
-    if (listen(lis->fd, ListenBackLog) < 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.",
-                      s, p, strerror(errno));
-      exit(errno);
+       continue;
+      }
     }
 
     if (p)
-      cupsdLogMessage(CUPSD_LOG_INFO,
-                      "cupsdStartListening: Listening to %s:%d on fd %d...",
+      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
                      s, p, lis->fd);
     else
-      cupsdLogMessage(CUPSD_LOG_INFO,
-                      "cupsdStartListening: Listening to %s on fd %d...",
+      cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
                      s, lis->fd);
 
    /*
@@ -294,7 +190,7 @@ cupsdStartListening(void)
     * "any" address...
     */
 
-    if (!LocalPort && p > 0 &&
+    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
         (httpAddrLocalhost(&(lis->address)) ||
          httpAddrAny(&(lis->address))))
     {
@@ -315,13 +211,11 @@ cupsdStartListening(void)
   if (!LocalPort && !have_domain)
   {
     cupsdLogMessage(CUPSD_LOG_EMERG,
-                    "No Listen or Port lines were found to allow access via localhost!");
+                    "No Listen or Port lines were found to allow access via "
+                   "localhost.");
 
-   /*
-    * Commit suicide...
-    */
-
-    cupsdEndProcess(getpid(), 0);
+    if (FatalErrors & (CUPSD_FATAL_CONFIG | CUPSD_FATAL_LISTEN))
+      cupsdEndProcess(getpid(), 0);
   }
 
  /*
@@ -336,6 +230,8 @@ cupsdStartListening(void)
     */
 
     cupsdSetEnv("CUPS_SERVER", have_domain);
+
+    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
   }
   else
   {
@@ -347,7 +243,9 @@ cupsdStartListening(void)
   }
 
   cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]);
-  cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
+
+  if (LocalPort)
+    cupsdSetEnvf("IPP_PORT", "%d", LocalPort);
 
  /*
   * Resume listening for connections...
@@ -364,35 +262,32 @@ cupsdStartListening(void)
 void
 cupsdStopListening(void)
 {
-  int          i;              /* Looping var */
   cupsd_listener_t     *lis;           /* Current listening socket */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "cupsdStopListening: closing all listen sockets.");
 
   cupsdPauseListening();
 
-  for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
   {
-#ifdef WIN32
-    closesocket(lis->fd);
+    if (lis->fd != -1)
+    {
+#ifdef HAVE_LAUNCH_H
+      httpAddrClose(NULL, lis->fd);
 #else
-    close(lis->fd);
-#endif /* WIN32 */
+      httpAddrClose(&(lis->address), lis->fd);
+#endif /* HAVE_LAUNCH */
 
-#ifdef AF_LOCAL
-   /*
-    * Remove domain sockets...
-    */
-
-    if (lis->address.addr.sa_family == AF_LOCAL)
-      unlink(lis->address.un.sun_path);
-#endif /* AF_LOCAL */
+      lis->fd = -1;
+    }
   }
 }
 
 
 /*
- * End of "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $".
+ * End of "$Id$".
  */