From: Frank Kardel Date: Sat, 24 Jun 2006 16:50:45 +0000 (+0000) Subject: ntp_io.c: X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da76966cb23fd39ed6280da9d8130d5cda461093;p=thirdparty%2Fntp.git ntp_io.c: implement fix for bug 614 socket fds will be moved out of the stdio reserved area if at all possible bk: 449d6d65LfduRi_VAkUQvF0_2T2EHA --- diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index b91e71fab3..468522f396 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -151,12 +151,7 @@ static void update_interfaces P((u_short, interface_receiver_t, void *)); static void remove_interface P((struct interface *)); static struct interface *create_interface P((u_short, struct interface *)); -#if !defined(SYS_WINNT) && defined(F_DUPFD) static int move_fd P((int)); -#ifndef FOPEN_MAX -#define FOPEN_MAX 20 -#endif -#endif /* * Multicast functions @@ -287,29 +282,114 @@ 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 !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 - if (newfd == -1) - { - msyslog(LOG_ERR, "Error duplicating file descriptor: %m"); - return (fd); - } - (void)close(fd); - return (newfd); - } - else - return (fd); -} +#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); +} + #ifdef DEBUG_TIMING /* * collect timing information for various processing @@ -2079,13 +2159,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 @@ -3573,6 +3651,7 @@ init_async_notifications() int fd = socket(PF_ROUTE, SOCK_RAW, 0); if (fd >= 0) { + fd = move_fd(fd); init_nonblocking_io(fd); #if defined(HAVE_SIGNALED_IO) init_socket_sig(fd);