]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
ntp_io.c:
authorFrank Kardel <kardel@ntp.org>
Sat, 24 Jun 2006 16:46:25 +0000 (16:46 +0000)
committerFrank Kardel <kardel@ntp.org>
Sat, 24 Jun 2006 16:46:25 +0000 (16:46 +0000)
  implement fix for bug 614
  socket fds will be moved out of the stdio reserved
  space if at all possible

bk: 449d6c61hsDl6gE6lehWYGMOZnmugw

ntpd/ntp_io.c

index a89eeae762442d2b4c37cc613bc626d77d215037..083d6584978cf5277a2128cd9d327b00af124f93 100644 (file)
@@ -149,13 +149,7 @@ static     void    close_socket    P((SOCKET));
 #ifdef REFCLOCK
 static void    close_file      P((SOCKET));
 #endif
-#if !defined(SYS_WINNT) && defined(F_DUPFD)
 static int     move_fd         P((int));
-#ifndef FOPEN_MAX
-#define FOPEN_MAX      20
-#endif
-#endif
-
 static char *  fdbits          P((int, fd_set *));
 static void    set_reuseaddr   P((int));
 static isc_boolean_t   socket_broadcast_enable  P((struct interface *, SOCKET, struct sockaddr_storage *));
@@ -248,28 +242,113 @@ connection_reset_fix(SOCKET fd) {
 }
 #endif
 
-#if !defined(SYS_WINNT) && defined(F_DUPFD)
-static int move_fd(int fd)
+/*
+ * on Unix systems the stdio library typically
+ * makes use of file descriptor in the lower
+ * integer range. stdio usually will make use
+ * of the file descriptor in the range of
+ * [0..FOPEN_MAX)
+ * in order to keep this range clean for socket
+ * file descriptions to attempt to move them above
+ * FOPEM_MAX. This is not as easy as it sounds as
+ * FOPEN_MAX changes from implementation to implementation
+ * and may exceed to current file decriptor limits.
+ * We are using following strategy:
+ * - keep a current socket fd boundary initialized with
+ *   max(0, min(getdtablesize() - FD_CHUNK, FOPEN_MAX))
+ * - attempt to move the descriptor to the boundary or
+ *   above.
+ *   - if that fails and boundary > 0 set boundary
+ *     to min(0, socket_fd_boundary - FD_CHUNK)
+ *     -> retry
+ *     if failure and boundary == 0 return old fd
+ *   - on success close old fd return new fd
+ *
+ * effects:
+ *   - fds will be moved above the socket fd boundary
+ *     if at all possible.
+ *   - the socket boundary will be reduced until
+ *     allocation is possible or 0 is reached - at this
+ *     point the algrithm will be disabled
+ */
+static int move_fd(SOCKET fd)
 {
-       int newfd;
-        /*
-         * Leave a space for stdio to work in.
-         */
-        if (fd >= 0 && fd < FOPEN_MAX) {
-                newfd = fcntl(fd, F_DUPFD, FOPEN_MAX);
-
-                if (newfd == -1)
-               {
-                       msyslog(LOG_ERR, "Error duplicating file descriptor: %m");
-                        return (fd);
-               }
-                (void)close(fd);
-                return (newfd);
-        }
-       else
-               return (fd);
-}
+#if !defined(SYS_WINNT) && defined(F_DUPFD)
+#ifndef FD_CHUNK
+#define FD_CHUNK       10
+#endif
+/*
+ * number of fds we would like to have for
+ * stdio FILE* available.
+ * we can pick a "low" number as our use of
+ * FILE* is limited to log files and temporarily
+ * to data and config files. Except for log files
+ * we don't keep the other FILE* open beyond the
+ * scope of the function that opened it.
+ */
+#ifndef FD_PREFERRED_SOCKBOUNDARY
+#define FD_PREFERRED_SOCKBOUNDARY 48
+#endif
+
+#ifndef HAVE_GETDTABLESIZE
+/*
+ * if we have no idea about the max fd value set up things
+ * so we will start at FOPEN_MAX
+ */
+#define getdtablesize() (FOPEN_MAX+FD_CHUNK)
+#endif
+
+#ifndef FOPEN_MAX
+#define FOPEN_MAX      20      /* assume that for the lack of anything better */
+#endif
+       static SOCKET socket_boundary = -1;
+       SOCKET newfd;
+
+       /*
+        * check whether boundary has be set up
+        * already
+        */
+       if (socket_boundary == -1) {
+               socket_boundary = max(0, min(getdtablesize() - FD_CHUNK, 
+                                            min(FOPEN_MAX, FD_PREFERRED_SOCKBOUNDARY)));
+#ifdef DEBUG
+               msyslog(LOG_DEBUG, "ntp_io: estimated max descriptors: %d, initial socket boundary: %d",
+                       getdtablesize(), socket_boundary);
+#endif
+       }
+
+       /*
+        * with socket_boundary == 0 we stop attempting to move fds
+        */
+       if (socket_boundary > 0) {
+               /*
+                * Leave a space for stdio to work in. potentially moving the
+                * socket_boundary lower until allocation succeeds.
+                */
+               do {
+                       if (fd >= 0 && fd < socket_boundary) {
+                               /* inside reserved range: attempt to move fd */
+                               newfd = fcntl(fd, F_DUPFD, socket_boundary);
+                               
+                               if (newfd != -1) {
+                                       /* success: drop the old one - return the new one */
+                                       (void)close(fd);
+                                       return (newfd);
+                               }
+                       } else {
+                               /* outside reserved range: no work - return the original one */
+                               return (fd);
+                       }
+                       socket_boundary = max(0, socket_boundary - FD_CHUNK);
+#ifdef DEBUG
+                       msyslog(LOG_DEBUG, "ntp_io: selecting new socket boundary: %d",
+                               socket_boundary);
 #endif
+               } while (socket_boundary > 0);
+       }
+#endif /* !defined(SYS_WINNT) && defined(F_DUPFD) */
+       return (fd);
+}
 
 
 
@@ -1529,6 +1608,9 @@ open_socket(
                    errval == WSAEPFNOSUPPORT)
 #endif
                        return (INVALID_SOCKET);
+
+               msyslog(LOG_ERR, "socket for address %s could not be created - check error above - TERMINATING",
+                       stoa(addr));
                exit(1);
                /*NOTREACHED*/
        }
@@ -1539,13 +1621,11 @@ open_socket(
        }
 #endif /* SYS_WINNT */
 
-#if !defined(SYS_WINNT) && defined(F_DUPFD)
        /*
         * Fixup the file descriptor for some systems
         * See bug #530 for details of the issue.
         */
        fd = move_fd(fd);
-#endif
 
        /*
         * set SO_REUSEADDR since we will be binding the same port