Testsuite: fix content-scanner interface tests
[exim.git] / src / src / daemon.c
index c11e2ed0a3d81b40b8bdeedf1e49164f5e683978..39da13cc84374d813e72d6edfeb294a5d04bc849 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/daemon.c,v 1.27 2009/11/16 19:50:36 nm4 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
@@ -384,7 +382,7 @@ if (pid == 0)
 
   /* Check for a tls-on-connect port */
 
 
   /* Check for a tls-on-connect port */
 
-  if (host_is_tls_on_connect_port(interface_port)) tls_on_connect = TRUE;
+  if (host_is_tls_on_connect_port(interface_port)) tls_in.on_connect = TRUE;
 
   /* Expand smtp_active_hostname if required. We do not do this any earlier,
   because it may depend on the local interface address (indeed, that is most
 
   /* Expand smtp_active_hostname if required. We do not do this any earlier,
   because it may depend on the local interface address (indeed, that is most
@@ -641,7 +639,7 @@ if (pid == 0)
         the data structures if necessary. */
 
         #ifdef SUPPORT_TLS
         the data structures if necessary. */
 
         #ifdef SUPPORT_TLS
-        tls_close(FALSE);
+        tls_close(TRUE, FALSE);
         #endif
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
         #endif
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
@@ -830,8 +828,17 @@ pid_t pid;
 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
   {
   int i;
 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
   {
   int i;
-  DEBUG(D_any) debug_printf("child %d ended: status=0x%x\n", (int)pid,
-    status);
+  DEBUG(D_any)
+    {
+    debug_printf("child %d ended: status=0x%x\n", (int)pid, status);
+#ifdef WCOREDUMP
+    if (WIFEXITED(status))
+      debug_printf("  normal exit, %d\n", WEXITSTATUS(status));
+    else if (WIFSIGNALED(status))
+      debug_printf("  signal exit, signal %d%s\n", WTERMSIG(status),
+          WCOREDUMP(status) ? " (core dumped)" : "");
+#endif
+    }
 
   /* If it's a listening daemon for which we are keeping track of individual
   subprocesses, deal with an accepting process that has terminated. */
 
   /* If it's a listening daemon for which we are keeping track of individual
   subprocesses, deal with an accepting process that has terminated. */
@@ -906,12 +913,67 @@ struct passwd *pw;
 int *listen_sockets = NULL;
 int listen_socket_count = 0;
 ip_address_item *addresses = NULL;
 int *listen_sockets = NULL;
 int listen_socket_count = 0;
 ip_address_item *addresses = NULL;
+time_t last_connection_time = (time_t)0;
 
 /* If any debugging options are set, turn on the D_pid bit so that all
 debugging lines get the pid added. */
 
 DEBUG(D_any|D_v) debug_selector |= D_pid;
 
 
 /* If any debugging options are set, turn on the D_pid bit so that all
 debugging lines get the pid added. */
 
 DEBUG(D_any|D_v) debug_selector |= D_pid;
 
+if (inetd_wait_mode)
+  {
+  int on = 1;
+
+  listen_socket_count = 1;
+  listen_sockets = store_get(sizeof(int *));
+  (void) close(3);
+  if (dup2(0, 3) == -1)
+    {
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+        "failed to dup inetd socket safely away: %s", strerror(errno));
+    }
+  listen_sockets[0] = 3;
+  (void) close(0);
+  (void) close(1);
+  (void) close(2);
+  exim_nullstd();
+
+  if (debug_file == stderr)
+    {
+    /* need a call to log_write before call to open debug_file, so that
+    log.c:file_path has been initialised.  This is unfortunate. */
+    log_write(0, LOG_MAIN, "debugging Exim in inetd wait mode starting");
+
+    fclose(debug_file);
+    debug_file = NULL;
+    exim_nullstd(); /* re-open fd2 after we just closed it again */
+    debug_logging_activate(US"-wait", NULL);
+    }
+
+  DEBUG(D_any) debug_printf("running in inetd wait mode\n");
+
+  /* As per below, when creating sockets ourselves, we handle tcp_nodelay for
+  our own buffering; we assume though that inetd set the socket REUSEADDR. */
+
+  if (tcp_nodelay) setsockopt(3, IPPROTO_TCP, TCP_NODELAY,
+    (uschar *)(&on), sizeof(on));
+  }
+
+
+if (inetd_wait_mode || daemon_listen)
+  {
+  /* If any option requiring a load average to be available during the
+  reception of a message is set, call os_getloadavg() while we are root
+  for those OS for which this is necessary the first time it is called (in
+  order to perform an "open" on the kernel memory file). */
+
+  #ifdef LOAD_AVG_NEEDS_ROOT
+  if (queue_only_load >= 0 || smtp_load_reserve >= 0 ||
+       (deliver_queue_load_max >= 0 && deliver_drop_privilege))
+    (void)os_getloadavg();
+  #endif
+  }
+
 
 /* Do the preparation for setting up a listener on one or more interfaces, and
 possible on various ports. This is controlled by the combination of
 
 /* Do the preparation for setting up a listener on one or more interfaces, and
 possible on various ports. This is controlled by the combination of
@@ -980,28 +1042,17 @@ The preparation code decodes options and sets up the relevant data. We do this
 first, so that we can return non-zero if there are any syntax errors, and also
 write to stderr. */
 
 first, so that we can return non-zero if there are any syntax errors, and also
 write to stderr. */
 
-if (daemon_listen)
+if (daemon_listen && !inetd_wait_mode)
   {
   int *default_smtp_port;
   int sep;
   int pct = 0;
   uschar *s;
   {
   int *default_smtp_port;
   int sep;
   int pct = 0;
   uschar *s;
-  uschar *list;
+  const uschar * list;
   uschar *local_iface_source = US"local_interfaces";
   ip_address_item *ipa;
   ip_address_item **pipa;
 
   uschar *local_iface_source = US"local_interfaces";
   ip_address_item *ipa;
   ip_address_item **pipa;
 
-  /* If any option requiring a load average to be available during the
-  reception of a message is set, call os_getloadavg() while we are root
-  for those OS for which this is necessary the first time it is called (in
-  order to perform an "open" on the kernel memory file). */
-
-  #ifdef LOAD_AVG_NEEDS_ROOT
-  if (queue_only_load >= 0 || smtp_load_reserve >= 0 ||
-       (deliver_queue_load_max >= 0 && deliver_drop_privilege))
-    (void)os_getloadavg();
-  #endif
-
   /* If -oX was used, disable the writing of a pid file unless -oP was
   explicitly used to force it. Then scan the string given to -oX. Any items
   that contain neither a dot nor a colon are used to override daemon_smtp_port.
   /* If -oX was used, disable the writing of a pid file unless -oP was
   explicitly used to force it. Then scan the string given to -oX. Any items
   that contain neither a dot nor a colon are used to override daemon_smtp_port.
@@ -1020,8 +1071,7 @@ if (daemon_listen)
 
     list = override_local_interfaces;
     sep = 0;
 
     list = override_local_interfaces;
     sep = 0;
-    while ((s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size))
-           != NULL)
+    while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
       {
       uschar joinstr[4];
       uschar **ptr;
       {
       uschar joinstr[4];
       uschar **ptr;
@@ -1076,13 +1126,13 @@ if (daemon_listen)
 
   list = daemon_smtp_port;
   sep = 0;
 
   list = daemon_smtp_port;
   sep = 0;
-  while ((s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size)) != NULL)
+  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
     pct++;
   default_smtp_port = store_get((pct+1) * sizeof(int));
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
     pct++;
   default_smtp_port = store_get((pct+1) * sizeof(int));
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
-       (s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size)) != NULL;
+       (s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size));
        pct++)
     {
     if (isdigit(*s))
        pct++)
     {
     if (isdigit(*s))
@@ -1095,13 +1145,38 @@ if (daemon_listen)
     else
       {
       struct servent *smtp_service = getservbyname(CS s, "tcp");
     else
       {
       struct servent *smtp_service = getservbyname(CS s, "tcp");
-      if (smtp_service == NULL)
+      if (!smtp_service)
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
       default_smtp_port[pct] = ntohs(smtp_service->s_port);
       }
     }
   default_smtp_port[pct] = 0;
 
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
       default_smtp_port[pct] = ntohs(smtp_service->s_port);
       }
     }
   default_smtp_port[pct] = 0;
 
+  /* Check the list of TLS-on-connect ports and do name lookups if needed */
+
+  list = tls_in.on_connect_ports;
+  sep = 0;
+  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+    if (!isdigit(*s))
+      {
+      list = tls_in.on_connect_ports;
+      tls_in.on_connect_ports = NULL;
+      sep = 0;
+      while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+       {
+        if (!isdigit(*s))
+         {
+         struct servent *smtp_service = getservbyname(CS s, "tcp");
+         if (!smtp_service)
+           log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
+         s= string_sprintf("%d", (int)ntohs(smtp_service->s_port));
+         }
+       tls_in.on_connect_ports = string_append_listele(tls_in.on_connect_ports,
+           ':', s);
+       }
+      break;
+      }
+
   /* Create the list of local interfaces, possibly with ports included. This
   list may contain references to 0.0.0.0 and ::0 as wildcards. These special
   values are converted below. */
   /* Create the list of local interfaces, possibly with ports included. This
   list may contain references to 0.0.0.0 and ::0 as wildcards. These special
   values are converted below. */
@@ -1201,6 +1276,11 @@ if (daemon_listen)
     listen_socket_count++;
   listen_sockets = store_get(sizeof(int *) * listen_socket_count);
 
     listen_socket_count++;
   listen_sockets = store_get(sizeof(int *) * listen_socket_count);
 
+  } /* daemon_listen but not inetd_wait_mode */
+
+if (daemon_listen)
+  {
+
   /* Do a sanity check on the max connects value just to save us from getting
   a huge amount of store. */
 
   /* Do a sanity check on the max connects value just to save us from getting
   a huge amount of store. */
 
@@ -1226,7 +1306,8 @@ if (daemon_listen)
 /* The variable background_daemon is always false when debugging, but
 can also be forced false in order to keep a non-debugging daemon in the
 foreground. If background_daemon is true, close all open file descriptors that
 /* The variable background_daemon is always false when debugging, but
 can also be forced false in order to keep a non-debugging daemon in the
 foreground. If background_daemon is true, close all open file descriptors that
-we know about, but then re-open stdin, stdout, and stderr to /dev/null.
+we know about, but then re-open stdin, stdout, and stderr to /dev/null.  Also
+do this for inetd_wait mode.
 
 This is protection against any called functions (in libraries, or in
 Perl, or whatever) that think they can write to stderr (or stdout). Before this
 
 This is protection against any called functions (in libraries, or in
 Perl, or whatever) that think they can write to stderr (or stdout). Before this
@@ -1237,7 +1318,7 @@ Then disconnect from the controlling terminal, Most modern Unixes seem to have
 setsid() for getting rid of the controlling terminal. For any OS that doesn't,
 setsid() can be #defined as a no-op, or as something else. */
 
 setsid() for getting rid of the controlling terminal. For any OS that doesn't,
 setsid() can be #defined as a no-op, or as something else. */
 
-if (background_daemon)
+if (background_daemon || inetd_wait_mode)
   {
   log_close_all();    /* Just in case anything was logged earlier */
   search_tidyup();    /* Just in case any were used in reading the config. */
   {
   log_close_all();    /* Just in case anything was logged earlier */
   search_tidyup();    /* Just in case any were used in reading the config. */
@@ -1246,7 +1327,10 @@ if (background_daemon)
   (void)close(2);
   exim_nullstd();     /* Connect stdin/stdout/stderr to /dev/null */
   log_stderr = NULL;  /* So no attempt to copy paniclog output */
   (void)close(2);
   exim_nullstd();     /* Connect stdin/stdout/stderr to /dev/null */
   log_stderr = NULL;  /* So no attempt to copy paniclog output */
+  }
 
 
+if (background_daemon)
+  {
   /* If the parent process of this one has pid == 1, we are re-initializing the
   daemon as the result of a SIGHUP. In this case, there is no need to do
   anything, because the controlling terminal has long gone. Otherwise, fork, in
   /* If the parent process of this one has pid == 1, we are re-initializing the
   daemon as the result of a SIGHUP. In this case, there is no need to do
   anything, because the controlling terminal has long gone. Otherwise, fork, in
@@ -1266,7 +1350,7 @@ if (background_daemon)
 /* We are now in the disconnected, daemon process (unless debugging). Set up
 the listening sockets if required. */
 
 /* We are now in the disconnected, daemon process (unless debugging). Set up
 the listening sockets if required. */
 
-if (daemon_listen)
+if (daemon_listen && !inetd_wait_mode)
   {
   int sk;
   int on = 1;
   {
   int sk;
   int on = 1;
@@ -1506,7 +1590,25 @@ sigalrm_seen = (queue_interval > 0);
 /* Log the start up of a daemon - at least one of listening or queue running
 must be set up. */
 
 /* Log the start up of a daemon - at least one of listening or queue running
 must be set up. */
 
-if (daemon_listen)
+if (inetd_wait_mode)
+  {
+  uschar *p = big_buffer;
+
+  if (inetd_wait_timeout >= 0)
+    sprintf(CS p, "terminating after %d seconds", inetd_wait_timeout);
+  else
+    sprintf(CS p, "with no wait timeout");
+
+  log_write(0, LOG_MAIN,
+    "exim %s daemon started: pid=%d, launched with listening socket, %s",
+    version_string, getpid(), big_buffer);
+  set_process_info("daemon: pre-listening socket");
+
+  /* set up the timeout logic */
+  sigalrm_seen = 1;
+  }
+
+else if (daemon_listen)
   {
   int i, j;
   int smtp_ports = 0;
   {
   int i, j;
   int smtp_ports = 0;
@@ -1597,6 +1699,15 @@ else
     readconf_printtime(queue_interval));
   }
 
     readconf_printtime(queue_interval));
   }
 
+/* Do any work it might be useful to amortize over our children
+(eg: compile regex) */
+
+deliver_init();
+dns_pattern_init();
+
+#ifdef WITH_CONTENT_SCAN
+malware_init();
+#endif
 
 /* Close the log so it can be renamed and moved. In the few cases below where
 this long-running process writes to the log (always exceptional conditions), it
 
 /* Close the log so it can be renamed and moved. In the few cases below where
 this long-running process writes to the log (always exceptional conditions), it
@@ -1624,122 +1735,166 @@ for (;;)
   pid_t pid;
 
   /* This code is placed first in the loop, so that it gets obeyed at the
   pid_t pid;
 
   /* This code is placed first in the loop, so that it gets obeyed at the
-  start, before the first wait. This causes the first queue-runner to be
-  started immediately. */
+  start, before the first wait, for the queue-runner case, so that the first
+  one can be started immediately.
+
+  The other option is that we have an inetd wait timeout specified to -bw. */
 
   if (sigalrm_seen)
     {
 
   if (sigalrm_seen)
     {
-    DEBUG(D_any) debug_printf("SIGALRM received\n");
+    if (inetd_wait_timeout > 0)
+      {
+      time_t resignal_interval = inetd_wait_timeout;
 
 
-    /* Do a full queue run in a child process, if required, unless we already
-    have enough queue runners on the go. If we are not running as root, a
-    re-exec is required. */
+      if (last_connection_time == (time_t)0)
+        {
+        DEBUG(D_any)
+          debug_printf("inetd wait timeout expired, but still not seen first message, ignoring\n");
+        }
+      else
+        {
+        time_t now = time(NULL);
+        if (now == (time_t)-1)
+          {
+          DEBUG(D_any) debug_printf("failed to get time: %s\n", strerror(errno));
+          }
+        else
+          {
+          if ((now - last_connection_time) >= inetd_wait_timeout)
+            {
+            DEBUG(D_any)
+              debug_printf("inetd wait timeout %d expired, ending daemon\n",
+                  inetd_wait_timeout);
+            log_write(0, LOG_MAIN, "exim %s daemon terminating, inetd wait timeout reached.\n",
+                version_string);
+            exit(EXIT_SUCCESS);
+            }
+          else
+            {
+            resignal_interval -= (now - last_connection_time);
+            }
+          }
+        }
 
 
-    if (queue_interval > 0 &&
-       (queue_run_max <= 0 || queue_run_count < queue_run_max))
+      sigalrm_seen = FALSE;
+      alarm(resignal_interval);
+      }
+
+    else
       {
       {
-      if ((pid = fork()) == 0)
-        {
-        int sk;
+      DEBUG(D_any) debug_printf("SIGALRM received\n");
 
 
-        DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n",
-          (int)getpid());
+      /* Do a full queue run in a child process, if required, unless we already
+      have enough queue runners on the go. If we are not running as root, a
+      re-exec is required. */
 
 
-        /* Disable debugging if it's required only for the daemon process. We
-        leave the above message, because it ties up with the "child ended"
-        debugging messages. */
+      if (queue_interval > 0 &&
+         (queue_run_max <= 0 || queue_run_count < queue_run_max))
+        {
+        if ((pid = fork()) == 0)
+          {
+          int sk;
 
 
-        if (debug_daemon) debug_selector = 0;
+          DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n",
+            (int)getpid());
 
 
-        /* Close any open listening sockets in the child */
+          /* Disable debugging if it's required only for the daemon process. We
+          leave the above message, because it ties up with the "child ended"
+          debugging messages. */
 
 
-        for (sk = 0; sk < listen_socket_count; sk++)
-          (void)close(listen_sockets[sk]);
+          if (debug_daemon) debug_selector = 0;
 
 
-        /* Reset SIGHUP and SIGCHLD in the child in both cases. */
+          /* Close any open listening sockets in the child */
 
 
-        signal(SIGHUP,  SIG_DFL);
-        signal(SIGCHLD, SIG_DFL);
+          for (sk = 0; sk < listen_socket_count; sk++)
+            (void)close(listen_sockets[sk]);
 
 
-        /* Re-exec if privilege has been given up, unless deliver_drop_
-        privilege is set. Reset SIGALRM before exec(). */
+          /* Reset SIGHUP and SIGCHLD in the child in both cases. */
 
 
-        if (geteuid() != root_uid && !deliver_drop_privilege)
-          {
-          uschar opt[8];
-          uschar *p = opt;
-          uschar *extra[5];
-          int extracount = 1;
+          signal(SIGHUP,  SIG_DFL);
+          signal(SIGCHLD, SIG_DFL);
 
 
-          signal(SIGALRM, SIG_DFL);
-          *p++ = '-';
-          *p++ = 'q';
-          if (queue_2stage) *p++ = 'q';
-          if (queue_run_first_delivery) *p++ = 'i';
-          if (queue_run_force) *p++ = 'f';
-          if (deliver_force_thaw) *p++ = 'f';
-          if (queue_run_local) *p++ = 'l';
-          *p = 0;
-          extra[0] = opt;
-
-          /* If -R or -S were on the original command line, ensure they get
-          passed on. */
-
-          if (deliver_selectstring != NULL)
-            {
-            extra[extracount++] = deliver_selectstring_regex? US"-Rr" : US"-R";
-            extra[extracount++] = deliver_selectstring;
-            }
+          /* Re-exec if privilege has been given up, unless deliver_drop_
+          privilege is set. Reset SIGALRM before exec(). */
 
 
-          if (deliver_selectstring_sender != NULL)
+          if (geteuid() != root_uid && !deliver_drop_privilege)
             {
             {
-            extra[extracount++] = deliver_selectstring_sender_regex?
-              US"-Sr" : US"-S";
-            extra[extracount++] = deliver_selectstring_sender;
+            uschar opt[8];
+            uschar *p = opt;
+            uschar *extra[5];
+            int extracount = 1;
+
+            signal(SIGALRM, SIG_DFL);
+            *p++ = '-';
+            *p++ = 'q';
+            if (queue_2stage) *p++ = 'q';
+            if (queue_run_first_delivery) *p++ = 'i';
+            if (queue_run_force) *p++ = 'f';
+            if (deliver_force_thaw) *p++ = 'f';
+            if (queue_run_local) *p++ = 'l';
+            *p = 0;
+            extra[0] = opt;
+
+            /* If -R or -S were on the original command line, ensure they get
+            passed on. */
+
+            if (deliver_selectstring != NULL)
+              {
+              extra[extracount++] = deliver_selectstring_regex? US"-Rr" : US"-R";
+              extra[extracount++] = deliver_selectstring;
+              }
+
+            if (deliver_selectstring_sender != NULL)
+              {
+              extra[extracount++] = deliver_selectstring_sender_regex?
+                US"-Sr" : US"-S";
+              extra[extracount++] = deliver_selectstring_sender;
+              }
+
+            /* Overlay this process with a new execution. */
+
+            (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, extracount,
+              extra[0], extra[1], extra[2], extra[3], extra[4]);
+
+            /* Control never returns here. */
             }
 
             }
 
-          /* Overlay this process with a new execution. */
-
-          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, extracount,
-            extra[0], extra[1], extra[2], extra[3], extra[4]);
+          /* No need to re-exec; SIGALRM remains set to the default handler */
 
 
-          /* Control never returns here. */
+          queue_run(NULL, NULL, FALSE);
+          _exit(EXIT_SUCCESS);
           }
 
           }
 
-        /* No need to re-exec; SIGALRM remains set to the default handler */
-
-        queue_run(NULL, NULL, FALSE);
-        _exit(EXIT_SUCCESS);
-        }
-
-      if (pid < 0)
-        {
-        log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fork of queue-runner "
-          "process failed: %s", strerror(errno));
-        log_close_all();
-        }
-      else
-        {
-        int i;
-        for (i = 0; i < queue_run_max; ++i)
+        if (pid < 0)
+          {
+          log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fork of queue-runner "
+            "process failed: %s", strerror(errno));
+          log_close_all();
+          }
+        else
           {
           {
-          if (queue_pid_slots[i] <= 0)
+          int i;
+          for (i = 0; i < queue_run_max; ++i)
             {
             {
-            queue_pid_slots[i] = pid;
-            queue_run_count++;
-            break;
+            if (queue_pid_slots[i] <= 0)
+              {
+              queue_pid_slots[i] = pid;
+              queue_run_count++;
+              break;
+              }
             }
             }
+          DEBUG(D_any) debug_printf("%d queue-runner process%s running\n",
+            queue_run_count, (queue_run_count == 1)? "" : "es");
           }
           }
-        DEBUG(D_any) debug_printf("%d queue-runner process%s running\n",
-          queue_run_count, (queue_run_count == 1)? "" : "es");
         }
         }
-      }
 
 
-    /* Reset the alarm clock */
+      /* Reset the alarm clock */
 
 
-    sigalrm_seen = FALSE;
-    alarm(queue_interval);
-    }
+      sigalrm_seen = FALSE;
+      alarm(queue_interval);
+      }
+
+    } /* sigalrm_seen */
 
 
   /* Sleep till a connection happens if listening, and handle the connection if
 
 
   /* Sleep till a connection happens if listening, and handle the connection if
@@ -1879,8 +2034,12 @@ for (;;)
       /* If select/accept succeeded, deal with the connection. */
 
       if (accept_socket >= 0)
       /* If select/accept succeeded, deal with the connection. */
 
       if (accept_socket >= 0)
+        {
+        if (inetd_wait_timeout)
+          last_connection_time = time(NULL);
         handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,
           (struct sockaddr *)&accepted);
         handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,
           (struct sockaddr *)&accepted);
+        }
       }
     }
 
       }
     }
 
@@ -1939,5 +2098,6 @@ for (;;)
 /* Control never reaches here */
 }
 
 /* Control never reaches here */
 }
 
+/* vi: aw ai sw=2
+*/
 /* End of exim_daemon.c */
 /* End of exim_daemon.c */
-