Apply Ian Freislich's patch to fix a spamd timeout problem.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Wed, 27 Apr 2005 10:00:18 +0000 (10:00 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Wed, 27 Apr 2005 10:00:18 +0000 (10:00 +0000)
doc/doc-txt/ChangeLog
src/ACKNOWLEDGMENTS
src/src/exim.h
src/src/spam.c
src/src/spam.h

index 75831780155baad7c285ef4710c7328a01f39aa1..0470f493b3f6a0da2b0ed0d0596fc7ec98be8505 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.123 2005/04/07 15:37:13 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.124 2005/04/27 10:00:18 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -230,6 +230,13 @@ PH/37 Exim used to check for duplicate addresses in the middle of routing, on
       still happens during the routing process, since they are not going to be
       routed further.
 
       still happens during the routing process, since they are not going to be
       routed further.
 
+PH/38 Installed a patch from Ian Freislich, with the agreement of Tom Kistner.
+      It corrects a timeout issue with spamd. This is Ian's comment: "The
+      background is that sometimes spamd either never reads data from a
+      connection it has accepted, or it never writes response data. The exiscan
+      spam.[ch] uses a 3600 second timeout on spamd socket reads, further, it
+      blindly assumes that writes won't block so it may never time out."
+
 
 A note about Exim versions 4.44 and 4.50
 ----------------------------------------
 
 A note about Exim versions 4.44 and 4.50
 ----------------------------------------
index 8b7b704fbf011b43c85291fc123908851f4a3994..acba7b7587a71178dbe9cfa36a4d4e0761de75a5 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.22 2005/04/07 10:10:01 ph10 Exp $
+$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.23 2005/04/27 10:00:18 ph10 Exp $
 
 EXIM ACKNOWLEDGEMENTS
 
 
 EXIM ACKNOWLEDGEMENTS
 
@@ -20,7 +20,7 @@ relatively small patches.
 Philip Hazel
 
 Lists created: 20 November 2002
 Philip Hazel
 
 Lists created: 20 November 2002
-Last updated:  07 April 2005
+Last updated:  27 April 2005
 
 
 THE OLD LIST
 
 
 THE OLD LIST
@@ -127,6 +127,7 @@ Tony Finch                Expansion extensions
                             Patch for mxh lookup type in dnsdb
                             Patch for defer_foo in dndsb
                             Patch for ${dlfunc
                             Patch for mxh lookup type in dnsdb
                             Patch for defer_foo in dndsb
                             Patch for ${dlfunc
+Ian Freislich             Patch for spamd timeout problem
 Giuliano Gavazzi          Patches for OSX compilation
 Dominic Germain           Patch for exiqgrep MacOS X bug
 Oliver Gorwits            $load_average patch
 Giuliano Gavazzi          Patches for OSX compilation
 Dominic Germain           Patch for exiqgrep MacOS X bug
 Oliver Gorwits            $load_average patch
index b28edb79bf80ab90ef14b7bec3650f0440f1a6e8..e44cad788f2e671aaca289f0ea1aef5bd31b1eb6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.h,v 1.10 2005/03/22 14:11:54 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.h,v 1.11 2005/04/27 10:00:18 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -92,6 +92,7 @@ making unique names. */
 #include <sys/file.h>
 #include <dirent.h>
 #include <netdb.h>
 #include <sys/file.h>
 #include <dirent.h>
 #include <netdb.h>
+#include <poll.h>
 #include <pwd.h>
 #include <grp.h>
 #include <syslog.h>
 #include <pwd.h>
 #include <grp.h>
 #include <syslog.h>
index 77406cea44a8877589f1c00f1fda9931c6452362..0f6ad1434d8c22448399eadbd17960d37026a1fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/spam.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
+/* $Cambridge: exim/src/src/spam.c,v 1.5 2005/04/27 10:00:18 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -30,14 +30,17 @@ int spam(uschar **listptr) {
   FILE *mbox_file;
   int spamd_sock;
   uschar spamd_buffer[32600];
   FILE *mbox_file;
   int spamd_sock;
   uschar spamd_buffer[32600];
-  int i, j, offset;
+  int i, j, offset, result;
   uschar spamd_version[8];
   uschar spamd_score_char;
   double spamd_threshold, spamd_score;
   int spamd_report_offset;
   uschar *p,*q;
   int override = 0;
   uschar spamd_version[8];
   uschar spamd_score_char;
   double spamd_threshold, spamd_score;
   int spamd_report_offset;
   uschar *p,*q;
   int override = 0;
+  time_t start;
+  size_t read, wrote;
   struct sockaddr_un server;
   struct sockaddr_un server;
+  struct pollfd pollfd;
 
   /* find the username from the option list */
   if ((user_name = string_nextinlist(&list, &sep,
 
   /* find the username from the option list */
   if ((user_name = string_nextinlist(&list, &sep,
@@ -77,6 +80,7 @@ int spam(uschar **listptr) {
     return DEFER;
   };
 
     return DEFER;
   };
 
+  start = time(NULL);
   /* socket does not start with '/' -> network socket */
   if (*spamd_address != '/') {
     time_t now = time(NULL);
   /* socket does not start with '/' -> network socket */
   if (*spamd_address != '/') {
     time_t now = time(NULL);
@@ -203,33 +207,67 @@ int spam(uschar **listptr) {
   };
 
   /* now send the file */
   };
 
   /* now send the file */
+  /* spamd sometimes accepts conections but doesn't read data off
+   * the connection.  We make the file descriptor non-blocking so
+   * that the write will only write sufficient data without blocking
+   * and we poll the desciptor to make sure that we can write without
+   * blocking.  Short writes are gracefully handled and if the whole
+   * trasaction takes too long it is aborted.
+   */
+  pollfd.fd = spamd_sock;
+  pollfd.events = POLLOUT;
+  fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
   do {
   do {
-    j = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
-    if (j > 0) {
-      i = send(spamd_sock,spamd_buffer,j,0);
-      if (i != j) {
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "spam acl condition: error/short send to spamd");
+    read = fread(spamd_buffer,1,sizeof(spamd_buffer),mbox_file);
+    if (read > 0) {
+      offset = 0;
+again:
+      result = poll(&pollfd, 1, 1000);
+      if (result == -1 && errno == EINTR)
+        continue;
+      else if (result < 1) {
+        if (result == -1)
+          log_write(0, LOG_MAIN|LOG_PANIC,
+            "spam acl condition: %s on spamd socket", strerror(errno));
+        else {
+          if (time(NULL) - start < SPAMD_TIMEOUT)
+          goto again;
+          log_write(0, LOG_MAIN|LOG_PANIC,
+            "spam acl condition: timed out writing spamd socket");
+        }
         close(spamd_sock);
         fclose(mbox_file);
         return DEFER;
         close(spamd_sock);
         fclose(mbox_file);
         return DEFER;
-      };
-    };
+      }
+      wrote = send(spamd_sock,spamd_buffer + offset,read - offset,0);
+      if (offset + wrote != read) {
+        offset += wrote;
+        goto again;
+      }
+    }
+  }
+  while (!feof(mbox_file) && !ferror(mbox_file));
+  if (ferror(mbox_file)) {
+    log_write(0, LOG_MAIN|LOG_PANIC,
+      "spam acl condition: error reading spool file: %s", strerror(errno));
+    close(spamd_sock);
+    fclose(mbox_file);
+    return DEFER;
   }
   }
-  while (j > 0);
 
   fclose(mbox_file);
 
   /* we're done sending, close socket for writing */
   shutdown(spamd_sock,SHUT_WR);
 
 
   fclose(mbox_file);
 
   /* we're done sending, close socket for writing */
   shutdown(spamd_sock,SHUT_WR);
 
-  /* read spamd response */
+  /* read spamd response using what's left of the timeout.
+   */
   memset(spamd_buffer, 0, sizeof(spamd_buffer));
   offset = 0;
   while((i = ip_recv(spamd_sock,
                      spamd_buffer + offset,
                      sizeof(spamd_buffer) - offset - 1,
   memset(spamd_buffer, 0, sizeof(spamd_buffer));
   offset = 0;
   while((i = ip_recv(spamd_sock,
                      spamd_buffer + offset,
                      sizeof(spamd_buffer) - offset - 1,
-                     SPAMD_READ_TIMEOUT)) > 0 ) {
+                     SPAMD_TIMEOUT - time(NULL) + start)) > 0 ) {
     offset += i;
   }
 
     offset += i;
   }
 
index b2a12e3475b45da40fc8668c7df9cfae2efe0555..b1c8313c31288e39c448b05bb576f4501b639e92 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/spam.h,v 1.2 2004/12/16 15:11:47 tom Exp $ */
+/* $Cambridge: exim/src/src/spam.h,v 1.3 2005/04/27 10:00:18 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -11,8 +11,8 @@
 
 #ifdef WITH_CONTENT_SCAN
 
 
 #ifdef WITH_CONTENT_SCAN
 
-/* timeout for reading from spamd */
-#define SPAMD_READ_TIMEOUT 3600
+/* timeout for reading and writing spamd */
+#define SPAMD_TIMEOUT 120
 
 /* maximum length of the spam bar */
 #define MAX_SPAM_BAR_CHARS 50
 
 /* maximum length of the spam bar */
 #define MAX_SPAM_BAR_CHARS 50