]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 987] Wake up the resolver thread/process when a new interface has become available.
authorMartin Burnicki <burnicki@ntp.org>
Thu, 3 Apr 2008 14:19:03 +0000 (10:19 -0400)
committerMartin Burnicki <burnicki@ntp.org>
Thu, 3 Apr 2008 14:19:03 +0000 (10:19 -0400)
bk: 47f4e757z3I3nlyDUQoP-n-sEqW5IA

ChangeLog
include/ntpd.h
ntpd/ntp_config.c
ntpd/ntp_intres.c
ntpd/ntp_io.c

index 79dde815a82d72fef10d90b8f194d34e03aeaa25..7f6072800e6cb43260dee3ea5bfb0a7ba407c313 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+* [Bug 987] Wake up the resolver thread/process when a new interface has become available.
 * Correctly apply negative-sawtooth for oncore 12 channel receiver.
 * Startup code for original LinuxPPS removed.  LinuxPPS now conforms to
   the PPSAPI.
index 3495cc85d4d83455ce051a7272151d3462e57380..d0957191becb96b50f503879d756d2cf5a91b901 100644 (file)
@@ -283,6 +283,11 @@ extern u_long      numasyncmsgs;           /* number of async messages we've sent */
 /* ntp_intres.c */
 extern keyid_t req_keyid;              /* request keyid */
 extern char *  req_file;               /* name of the file with configuration info */
+#ifdef SYS_WINNT
+extern HANDLE ResolverEventHandle;
+#else
+extern int resolver_pipe_fd[2];  /* used to let the resolver process alert the parent process */
+#endif /* SYS_WINNT */
 
 /*
  * Other statistics of possible interest
index 05af3ffc2074d549e903e694405c32aec7f90ee1..13dc599da95f890b4d065cea9e67bb76bebd6e77 100644 (file)
 
 #ifdef SYS_WINNT
 # include <io.h>
-HANDLE ResolverThreadHandle = NULL;
+static HANDLE ResolverThreadHandle = NULL;
+HANDLE ResolverEventHandle;
+#else
+int resolver_pipe_fd[2];  /* used to let the resolver process alert the parent process */
 #endif /* SYS_WINNT */
 
 /*
@@ -2432,7 +2435,22 @@ do_resolve_internal(void)
        (void) signal_no_reset(SIGCHLD, catchchild);
 
 #ifndef SYS_VXWORKS
+       /* the parent process will write to the pipe
+        * in order to wake up to child process
+        * which may be waiting in a select() call
+        * on the read fd */
+       if (pipe(resolver_pipe_fd) < 0) {
+               msyslog(LOG_ERR,
+                       "unable to open resolver pipe");
+               exit(1);
+       }
+
        i = fork();
+       /* Shouldn't the code below be re-ordered?
+        * I.e. first check if the fork() returned an error, then
+        * check whether we're parent or child.
+        *     Martin Burnicki
+        */
        if (i == 0) {
                /*
                 * this used to close everything
@@ -2467,6 +2485,9 @@ do_resolve_internal(void)
                 * THUS:
                 */
 
+               /* This is the child process who will read the pipe,
+                * so we close the write fd */
+               close(resolver_pipe_fd[1]);
                closelog();
                kill_asyncio(0);
 
@@ -2515,6 +2536,11 @@ do_resolve_internal(void)
                (void) signal_no_reset(SIGCHLD, SIG_DFL);
                abort_resolve();
        }
+       else {
+               /* This is the parent process who will write to the pipe,
+                * so we close the read fd */
+               close(resolver_pipe_fd[0]);
+       }
 #else /* SYS_WINNT */
        {
                /* NT's equivalent of fork() is _spawn(), but the start point
@@ -2523,6 +2549,11 @@ do_resolve_internal(void)
                 */
                DWORD dwThreadId;
                fflush(stdout);
+               ResolverEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+               if (ResolverEventHandle == NULL) {
+                       msyslog(LOG_ERR, "Unable to create resolver event object, can't start ntp_intres");
+                       abort_resolve();
+               }
                ResolverThreadHandle = CreateThread(
                        NULL,                            /* no security attributes      */
                        0,                               /* use default stack size      */
@@ -2532,6 +2563,8 @@ do_resolve_internal(void)
                        &dwThreadId);                    /* returns the thread identifier */
                if (ResolverThreadHandle == NULL) {
                        msyslog(LOG_ERR, "CreateThread() failed, can't start ntp_intres");
+                       CloseHandle(ResolverEventHandle);
+                       ResolverEventHandle = NULL;
                        abort_resolve();
                }
        }
index 830ef437aff2664155567cb4e6f3e16332dd7d3f..345e42577db3568f35a37a2947fe1278910bdce5 100644 (file)
@@ -142,7 +142,6 @@ char *req_file;             /* name of the file with configuration info */
 /* end stuff to be filled in */
 
 
-static RETSIGTYPE bong         P((int));
 static void    checkparent     P((void));
 static void    removeentry     P((struct conf_entry *));
 static void    addentry        P((char *, int, int, int, int, u_int,
@@ -183,9 +182,11 @@ static void        resolver_exit P((int));
 static void resolver_exit (int code)
 {
 #ifdef SYS_WINNT
-       ExitThread (code);      /* Just to kill the thread not the process */
+       CloseHandle(ResolverEventHandle);
+       ResolverEventHandle = NULL;
+       ExitThread(code);       /* Just to kill the thread not the process */
 #else
-       exit (code);            /* fill the forked process */
+       exit(code);             /* kill the forked process */
 #endif
 }
 
@@ -215,11 +216,13 @@ void
 ntp_intres(void)
 {
        FILE *in;
-#ifdef HAVE_SIGSUSPEND
-       sigset_t set;
-
-       sigemptyset(&set);
-#endif /* HAVE_SIGSUSPEND */
+       struct timeval tv;
+       fd_set fdset;
+#ifdef SYS_WINNT
+       DWORD rc;
+#else
+       int rc;
+#endif
 
 #ifdef DEBUG
        if (debug > 1) {
@@ -257,91 +260,81 @@ ntp_intres(void)
        /*
         * Sleep a little to make sure the server is completely up
         */
-
        sleep(SLEEPTIME);
 
        /*
-        * Make a first cut at resolving the bunch
+        * Set up the timers to do first try immediately.
         */
-       doconfigure(1);
-       if (confentries == NULL) {
-               resolver_exit(0);
-       }
-       
-       /*
-        * Here we've got some problem children.  Set up the timer
-        * and wait for it.
-        */
-       resolve_value = resolve_timer = MINRESOLVE;
+       resolve_timer = 0;
+       resolve_value = MINRESOLVE;
        config_timer = CONFIG_TIME;
-#ifndef SYS_WINNT
-       (void) signal_no_reset(SIGALRM, bong);
-       alarm(ALARM_TIME);
-#endif /* SYS_WINNT */
 
        for (;;) {
-               if (confentries == NULL)
-                   resolver_exit(0);
-
                checkparent();
 
                if (resolve_timer == 0) {
-                       if (resolve_value < MAXRESOLVE)
-                           resolve_value <<= 1;
+                       doconfigure(1);
+
+                       /* prepare retry, in case there's more work to do */
                        resolve_timer = resolve_value;
 #ifdef DEBUG
                        if (debug > 2)
                                msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
 #endif
+                       if (resolve_value < MAXRESOLVE)
+                               resolve_value <<= 1;
+
                        config_timer = CONFIG_TIME;
-                       doconfigure(1);
-                       continue;
-               } else if (config_timer == 0) {
+               } else if (config_timer == 0) {  /* MB: in which case would this be required ? */
+                       doconfigure(0);
+                       /* MB: should we check now if we could exit, similar to the code above? */
                        config_timer = CONFIG_TIME;
 #ifdef DEBUG
                        if (debug > 2)
                                msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
 #endif
-                       doconfigure(0);
-                       continue; 
                }
-#ifndef SYS_WINNT
-               /*
-                * There is a race in here.  Is okay, though, since
-                * all it does is delay things by 30 seconds.
-                */
-# ifdef HAVE_SIGSUSPEND
-               sigsuspend(&set);
-# else
-               sigpause(0);
-# endif /* HAVE_SIGSUSPEND */
-#else
+
+               if (confentries == NULL)
+                       resolver_exit(0);   /* done */
+
+#ifdef SYS_WINNT
+               rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME);  /* in milliseconds */
+
+               if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */
+                       resolve_timer = 0;         /* retry resolving immediately */
+                       continue;
+               }
+
+               if ( rc != WAIT_TIMEOUT ) /* not timeout: error */
+                       resolver_exit(1);
+
+#else  /* not SYS_WINNT */
+               tv.tv_sec = ALARM_TIME;
+               tv.tv_usec = 0;
+               FD_ZERO(&fdset);
+               FD_SET(resolver_pipe_fd[0], &fdset);
+               rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv);
+
+               if (rc > 0) {  /* parent process has written to the pipe */
+                       read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc));  /* make pipe empty */
+                       resolve_timer = 0;   /* retry resolving immediately */
+                       continue;
+               }
+
+               if ( rc < 0 )  /* select() returned error */
+                       resolver_exit(1);
+#endif
+
+               /* normal timeout, keep on waiting */
                if (config_timer > 0)
-                   config_timer--;
+                       config_timer--;
                if (resolve_timer > 0)
-                   resolve_timer--;
-               sleep(ALARM_TIME);
-#endif /* SYS_WINNT */
+                       resolve_timer--;
        }
 }
 
 
-#ifndef SYS_WINNT
-/*
- * bong - service and reschedule an alarm() interrupt
- */
-static RETSIGTYPE
-bong(
-       int sig
-       )
-{
-       if (config_timer > 0)
-           config_timer--;
-       if (resolve_timer > 0)
-           resolve_timer--;
-       alarm(ALARM_TIME);
-}
-#endif /* SYS_WINNT */
 
 /*
  * checkparent - see if our parent process is still running
@@ -1104,6 +1097,12 @@ doconfigure(
        register struct conf_entry *ce;
        register struct conf_entry *ceremove;
 
+#ifdef DEBUG
+               if (debug > 1)
+                       msyslog(LOG_INFO, "Running doconfigure %s DNS",
+                           dores ? "with" : "without" );
+#endif
+
        ce = confentries;
        while (ce != NULL) {
 #ifdef DEBUG
index 81ea2de27b27a927475baec968801180fa212130..faa46461f484e2f34b1329dc3d953ca1b41acfcb 100644 (file)
@@ -172,7 +172,7 @@ static  u_char          sys_interphase = 0;
 
 static  struct interface *new_interface P((struct interface *));
 static  void add_interface P((struct interface *));
-static  void update_interfaces P((u_short, interface_receiver_t, void *));
+static  int 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 *));
 
@@ -1051,9 +1051,25 @@ void
 interface_update(interface_receiver_t receiver, void *data)
 {
        if (!disable_dynamic_updates) {
+               int new_interface_found;
+
                BLOCKIO();
-               update_interfaces(htons(NTP_PORT), receiver, data);
+               new_interface_found = update_interfaces(htons(NTP_PORT), receiver, data);
                UNBLOCKIO();
+
+               if (new_interface_found) {
+#ifdef DEBUG
+                       msyslog(LOG_DEBUG, "new interface(s) found: waking up resolver");
+#endif
+#ifdef SYS_WINNT
+                       /* wake up the resolver thread */
+                       if (ResolverEventHandle != NULL)
+                               SetEvent(ResolverEventHandle);
+#else
+                       /* write any single byte to the pipe to wake up the resolver process */
+                       write( resolver_pipe_fd[1], &new_interface_found, 1 );
+#endif
+               }
        }
 }
 
@@ -1146,7 +1162,7 @@ set_wildcard_reuse(int family, int on)
  *
  */
 
-static void
+static int
 update_interfaces(
        u_short port,
        interface_receiver_t receiver,
@@ -1159,6 +1175,7 @@ update_interfaces(
        isc_boolean_t scan_ipv4 = ISC_FALSE;
        isc_boolean_t scan_ipv6 = ISC_FALSE;
        isc_result_t result;
+       int new_interface_found = 0;
 
        DPRINTF(3, ("update_interfaces(%d)\n", ntohs( (u_short) port)));
 
@@ -1195,7 +1212,7 @@ update_interfaces(
        result = isc_interfaceiter_create(mctx, &iter);
 
        if (result != ISC_R_SUCCESS)
-               return;
+               return 0;
 
        sys_interphase ^= 0x1;  /* toggle system phase for finding untouched (to be deleted) interfaces */
        
@@ -1298,6 +1315,8 @@ update_interfaces(
                                if (receiver)
                                        receiver(data, &ifi);
 
+                               new_interface_found = 1;
+
                                DPRINT_INTERFACE(3, (iface, "updating ", " new - created\n"));
                        }
                        else
@@ -1371,8 +1390,9 @@ update_interfaces(
         * phase 3 - re-configure as the world has changed if necessary
         */
        refresh_all_peerinterfaces();
+       return new_interface_found;
 }
-               
+
 
 /*
  * create_sockets - create a socket for each interface plus a default