]> 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 467dcfdc81dbce4f8bd523a1b71d72a37a8cc49e..7ef4a3c92970db6862d59db03f3be6b571d4d82e 100644 (file)
@@ -1,34 +1,16 @@
 /*
- * "$Id: listen.c 5083 2006-02-06 02:57:43Z mike $"
+ * "$Id$"
  *
- *   Server listening routines for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ * Server listening routines for the CUPS scheduler.
  *
- *   Copyright 1997-2006 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:
- *
- *   cupsdDeleteAllListeners() - Delete all listeners.
- *   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/".
  */
 
 /*
@@ -84,20 +66,19 @@ cupsdPauseListening(void)
   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_DEBUG2, "cupsdPauseListening: Clearing input bits...");
 
   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
        lis;
        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdPauseListening: Removing fd %d from InputSet...",
-                      lis->fd);
+    cupsdRemoveSelect(lis->fd);
 
-      FD_CLR(lis->fd, InputSet);
-    }
+  ListeningPaused = time(NULL) + 30;
 }
 
 
@@ -114,22 +95,16 @@ cupsdResumeListening(void)
   if (cupsArrayCount(Listeners) < 1)
     return;
 
-  if (cupsArrayCount(Clients) >= (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...");
 
   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
        lis;
        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-    if (lis->fd >= 0)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                      "cupsdResumeListening: Adding fd %d to InputSet...",
-                      lis->fd);
-      FD_SET(lis->fd, InputSet);
-    }
+    cupsdAddSelect(lis->fd, (cupsd_selfunc_t)cupsdAcceptClient, NULL, lis);
+
+  ListeningPaused = 0;
 }
 
 
@@ -140,9 +115,7 @@ cupsdResumeListening(void)
 void
 cupsdStartListening(void)
 {
-  int                  status;         /* Bind result */
-  int                  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? */
@@ -158,18 +131,6 @@ cupsdStartListening(void)
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartListening: %d Listeners",
                   cupsArrayCount(Listeners));
 
- /*
-  * Get the server's IP address...
-  */
-
-  if (ServerAddrs)
-    httpAddrFreeList(ServerAddrs);
-
-  if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL)
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "Unable to find IP address for server name \"%s\"!\n",
-                   ServerName);
-
  /*
   * Setup socket listeners...
   */
@@ -180,18 +141,7 @@ cupsdStartListening(void)
        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));
 
    /*
     * If needed, create a socket for listening...
@@ -203,135 +153,44 @@ cupsdStartListening(void)
       * Create a socket for listening...
       */
 
-      lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0);
+      lis->fd = httpAddrListen(&(lis->address), p);
 
       if (lis->fd == -1)
       {
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Unable to open listen socket for address %s:%d - %s.",
                        s, p, strerror(errno));
-       continue;
-      }
-
-     /*
-      * 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.
+        * IPv6 is often disabled while DNS returns IPv6 addresses...
        */
 
-       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 */
-
-       status = bind(lis->fd, (struct sockaddr *)&(lis->address),
-                     httpAddrLength(&(lis->address)));
-      }
-      else
+       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 */
-#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)));
-
-       /*
-       * 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,
-                       "Unable to bind socket for address %s:%d - %s.",
-                       s, p, strerror(errno));
-       close(lis->fd);
-       lis->fd = -1;
        continue;
       }
-
-     /*
-      * Listen for new clients.
-      */
-
-      if (listen(lis->fd, ListenBackLog) < 0)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to listen for clients on address %s:%d - %s.",
-                       s, p, strerror(errno));
-       exit(errno);
-      }
     }
 
-    fcntl(lis->fd, F_SETFD, fcntl(lis->fd, F_GETFD) | FD_CLOEXEC);
-
     if (p)
       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d on fd %d...",
                      s, p, lis->fd);
     else
-    {
       cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s on fd %d...",
                      s, lis->fd);
 
-      if (chmod(s, 0140777))
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to change permisssions on domain socket "
-                       "\"%s\" - %s", s, strerror(errno));
-    }
-
    /*
     * Save the first port that is bound to the local loopback or
     * "any" address...
     */
 
-    if (!LocalPort && p > 0 &&
+    if ((!LocalPort || LocalEncryption == HTTP_ENCRYPT_ALWAYS) && p > 0 &&
         (httpAddrLocalhost(&(lis->address)) ||
          httpAddrAny(&(lis->address))))
     {
@@ -352,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);
   }
 
  /*
@@ -373,6 +230,8 @@ cupsdStartListening(void)
     */
 
     cupsdSetEnv("CUPS_SERVER", have_domain);
+
+    LocalEncryption = HTTP_ENCRYPT_IF_REQUESTED;
   }
   else
   {
@@ -384,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...
@@ -415,29 +276,18 @@ cupsdStopListening(void)
   {
     if (lis->fd != -1)
     {
-#ifdef WIN32
-      closesocket(lis->fd);
+#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...
-      */
-
-#  ifdef HAVE_LAUNCH_H
-      if (lis->address.addr.sa_family == AF_LOCAL && !Launchd)
-#  else
-      if (lis->address.addr.sa_family == AF_LOCAL)
-#  endif /* HAVE_LAUNCH_H */
-       unlink(lis->address.un.sun_path);
-#endif /* AF_LOCAL */
+      lis->fd = -1;
     }
   }
 }
 
 
 /*
- * End of "$Id: listen.c 5083 2006-02-06 02:57:43Z mike $".
+ * End of "$Id$".
  */