Testsuite: delays for debug output ordering
[exim.git] / src / src / transports / smtp.c
index ca06bf6bd8a7609dac1a72e6c26e8ececd8c8028..ef9309c471a0f296126cfb9aad2bbd9f0c8cf4d7 100644 (file)
@@ -623,34 +623,34 @@ return FALSE;
 /* This writes to the main log and to the message log.
 
 Arguments:
-  addr     the address item containing error information
   host     the current host
+  detail  the current message (addr_item->message)
+  basic_errno the errno (addr_item->basic_errno)
 
 Returns:   nothing
 */
 
 static void
-write_logs(address_item *addr, host_item *host)
+write_logs(const host_item *host, const uschar *suffix, int basic_errno)
 {
-uschar * message = LOGGING(outgoing_port)
+
+
+uschar *message = LOGGING(outgoing_port)
   ? string_sprintf("H=%s [%s]:%d", host->name, host->address,
                    host->port == PORT_NONE ? 25 : host->port)
   : string_sprintf("H=%s [%s]", host->name, host->address);
 
-if (addr->message)
+if (suffix)
   {
-  message = string_sprintf("%s: %s", message, addr->message);
-  if (addr->basic_errno > 0)
-    message = string_sprintf("%s: %s", message, strerror(addr->basic_errno));
-  log_write(0, LOG_MAIN, "%s", message);
-  deliver_msglog("%s %s\n", tod_stamp(tod_log), message);
+  message = string_sprintf("%s: %s", message, suffix);
+  if (basic_errno > 0)
+    message = string_sprintf("%s: %s", message, strerror(basic_errno));
   }
 else
-  {
-  const uschar * s = exim_errstr(addr->basic_errno);
-  log_write(0, LOG_MAIN, "%s %s", message, s);
-  deliver_msglog("%s %s %s\n", tod_stamp(tod_log), message, s);
-  }
+  message = string_sprintf("%s %s", message, exim_errstr(basic_errno));
+
+log_write(0, LOG_MAIN, "%s", message);
+deliver_msglog("%s %s\n", tod_stamp(tod_log), message);
 }
 
 static void
@@ -2580,29 +2580,38 @@ return 0;
 * Proxy TLS connection for another transport process *
 ******************************************************/
 /*
-Use the given buffer as a staging area, and select on both the given fd
-and the TLS'd client-fd for data to read (per the coding in ip_recv() and
-fd_ready() this is legitimate).  Do blocking full-size writes, and reads
-under a timeout.
+Close the unused end of the pipe, fork once more, then use the given buffer
+as a staging area, and select on both the given fd and the TLS'd client-fd for
+data to read (per the coding in ip_recv() and fd_ready() this is legitimate).
+Do blocking full-size writes, and reads under a timeout.  Once both input
+channels are closed, exit the process.
 
 Arguments:
   buf          space to use for buffering
   bufsiz       size of buffer
-  proxy_fd     comms to proxied process
+  pfd          pipe filedescriptor array; [0] is comms to proxied process
   timeout      per-read timeout, seconds
 */
 
 void
-smtp_proxy_tls(uschar * buf, size_t bsize, int proxy_fd, int timeout)
+smtp_proxy_tls(uschar * buf, size_t bsize, int * pfd, int timeout)
 {
 fd_set rfds, efds;
-int max_fd = MAX(proxy_fd, tls_out.active) + 1;
+int max_fd = MAX(pfd[0], tls_out.active) + 1;
 int rc, i, fd_bits, nbytes;
 
+close(pfd[1]);
+if ((rc = fork()))
+  {
+  DEBUG(D_transport) debug_printf("proxy-proc final-pid %d\n", rc);
+  _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+  }
+
+if (running_in_test_harness) millisleep(100); /* let parent debug out */
 set_process_info("proxying TLS connection for continued transport");
 FD_ZERO(&rfds);
 FD_SET(tls_out.active, &rfds);
-FD_SET(proxy_fd, &rfds);
+FD_SET(pfd[0], &rfds);
 
 for (fd_bits = 3; fd_bits; )
   {
@@ -2624,17 +2633,17 @@ for (fd_bits = 3; fd_bits; )
     if (rc <= 0)
       {
       DEBUG(D_transport) if (rc == 0) debug_printf("%s: timed out\n", __FUNCTION__);
-      return;
+      goto done;
       }
 
-    if (FD_ISSET(tls_out.active, &efds) || FD_ISSET(proxy_fd, &efds))
+    if (FD_ISSET(tls_out.active, &efds) || FD_ISSET(pfd[0], &efds))
       {
       DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
-       FD_ISSET(proxy_fd, &efds) ? "proxy" : "tls");
-      return;
+       FD_ISSET(pfd[0], &efds) ? "proxy" : "tls");
+      goto done;
       }
     }
-  while (rc < 0 || !(FD_ISSET(tls_out.active, &rfds) || FD_ISSET(proxy_fd, &rfds)));
+  while (rc < 0 || !(FD_ISSET(tls_out.active, &rfds) || FD_ISSET(pfd[0], &rfds)));
 
   /* handle inbound data */
   if (FD_ISSET(tls_out.active, &rfds))
@@ -2642,20 +2651,20 @@ for (fd_bits = 3; fd_bits; )
       {
       fd_bits &= ~1;
       FD_CLR(tls_out.active, &rfds);
-      shutdown(proxy_fd, SHUT_WR);
+      shutdown(pfd[0], SHUT_WR);
       timeout = 5;
       }
     else
       {
       for (nbytes = 0; rc - nbytes > 0; nbytes += i)
-       if ((i = write(proxy_fd, buf + nbytes, rc - nbytes)) < 0) return;
+       if ((i = write(pfd[0], buf + nbytes, rc - nbytes)) < 0) goto done;
       }
   else if (fd_bits & 1)
     FD_SET(tls_out.active, &rfds);
 
   /* handle outbound data */
-  if (FD_ISSET(proxy_fd, &rfds))
-    if ((rc = read(proxy_fd, buf, bsize)) <= 0)
+  if (FD_ISSET(pfd[0], &rfds))
+    if ((rc = read(pfd[0], buf, bsize)) <= 0)
       {
       fd_bits = 0;
       tls_close(FALSE, TRUE);
@@ -2664,11 +2673,15 @@ for (fd_bits = 3; fd_bits; )
       {
       for (nbytes = 0; rc - nbytes > 0; nbytes += i)
        if ((i = tls_write(FALSE, buf + nbytes, rc - nbytes, FALSE)) < 0)
-         return;
+         goto done;
       }
   else if (fd_bits & 2)
-    FD_SET(proxy_fd, &rfds);
+    FD_SET(pfd[0], &rfds);
   }
+
+done:
+  if (running_in_test_harness) millisleep(100);        /* let logging complete */
+  exim_exit(0, US"TLS proxy");
 }
 #endif
 
@@ -3153,7 +3166,7 @@ else
         else
           sprintf(CS sx.buffer, "%.500s\n", addr->unique);
 
-        DEBUG(D_deliver) debug_printf("S:journalling %s", sx.buffer);
+        DEBUG(D_deliver) debug_printf("S:journalling %s\n", sx.buffer);
         len = Ustrlen(CS sx.buffer);
         if (write(journal_fd, sx.buffer, len) != len)
           log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
@@ -3307,8 +3320,9 @@ if (!sx.ok)
        set_rc = DEFER;
         if (save_errno > 0)
           message = US string_sprintf("%s: %s", message, strerror(save_errno));
-        if (host->next != NULL) log_write(0, LOG_MAIN, "%s", message);
-       msglog_line(host, message);
+
+        write_logs(host, message, sx.first_addr ? sx.first_addr->basic_errno : 0);
+
         *message_defer = TRUE;
         }
       }
@@ -3485,7 +3499,8 @@ propagate it from the initial
        {
         sx.send_quit = FALSE;
 
-       /* If TLS is still active, we need to proxy it for the transport we
+       /* We have passed the client socket to a fresh transport process.
+       If TLS is still active, we need to proxy it for the transport we
        just passed the baton to.  Fork a child to to do it, and return to
        get logging done asap.  Which way to place the work makes assumptions
        about post-fork prioritisation which may not hold on all platforms. */
@@ -3493,10 +3508,19 @@ propagate it from the initial
        if (tls_out.active >= 0)
          {
          int pid = fork();
+         if (pid == 0)         /* child; fork again to disconnect totally */
+           {
+           if (running_in_test_harness) millisleep(100); /* let parent debug out */
+           /* does not return */
+           smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd,
+                           sx.ob->command_timeout);
+           }
+
          if (pid > 0)          /* parent */
            {
            DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid);
            close(pfd[0]);
+           /* tidy the inter-proc to disconn the proxy proc */
            waitpid(pid, NULL, 0);
            tls_close(FALSE, FALSE);
            (void)close(sx.inblock.sock);
@@ -3504,18 +3528,7 @@ propagate it from the initial
            continue_hostname = NULL;
            return yield;
            }
-         else if (pid == 0)    /* child; fork again to disconnect totally */
-           {
-           close(pfd[1]);
-           if ((pid = fork()))
-             {
-             DEBUG(D_transport) debug_printf("proxy-prox final-pid %d\n", pid);
-             _exit(pid < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
-             }
-           smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd[0], sx.ob->command_timeout);
-           if (running_in_test_harness) millisleep(100);       /* let logging complete */
-           exim_exit(0, US"TLS proxy");
-           }
+         log_write(0, LOG_PANIC_DIE, "fork failed");
          }
 #endif
        }
@@ -4317,7 +4330,7 @@ for (cutoff_retry = 0;
 
       if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL
                      && first_addr->basic_errno != ERRNO_TLSFAILURE)
-        write_logs(first_addr, host);
+        write_logs(host, first_addr->message, first_addr->basic_errno);
 
 #ifndef DISABLE_EVENT
       if (rc == DEFER)
@@ -4347,7 +4360,7 @@ for (cutoff_retry = 0;
         rc = smtp_deliver(addrlist, thost, host_af, defport, interface, tblock,
           &message_defer, TRUE);
         if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
-          write_logs(first_addr, host);
+          write_logs(host, first_addr->message, first_addr->basic_errno);
 # ifndef DISABLE_EVENT
         if (rc == DEFER)
           deferred_event_raise(first_addr, host);