Re: [evolution-patches] [mailer] when starting spamd, use unix domain socket instead of opening tcp port #53109



Hi,

I am attaching new version of patch which uses atexit instead of introducing quit method in session and also respawns spamd when it dies.

Cheers
Radek

On Tue, 2004-10-19 at 19:32 +0800, Not Zed wrote:
On Mon, 2004-10-18 at 19:09 +0200, Radek Doulík wrote:
On Thu, 2004-10-14 at 08:43 +0800, Not Zed wrote:
On Wed, 2004-10-13 at 14:04 +0200, Radek Doulík wrote:
On Wed, 2004-10-13 at 09:14 +0800, Not Zed wrote:

Is there any reason you don't just start it if it isn't started already?
this is what I do. I start it only if there's no system spamd running. we may additionally save socket path to e_mktemp generated file and look for running there, but that sounds overly complicated to me.
Hmm, ok i misread the init code.
  I'm not sure i like the additions of the init stuff, and running it all the time.  What happens if it dies at some point?
when it dies then it will not detect any more junk. testing if spamd runs for each junk test is expensive.
But you can surely detect if its died at some point?
yeah, I can tell that from spamc return code. I can try to relaunch spamd again, but I will have to be careful in case it will crashes continuously. not sure if it's worth it. I have never seen spamd crash so far.

what do you mean by "running it all the time", running what?
Well the only thing you're running at all is spamd, so i couldn't have meant anything else!
I think the init callback is useful and might be even more if we implement more plugins. btw, is it going to be possible to use EPlugin for junk plugins?
Hmm, I guess.  EPlugin would be possible but it would need a junk plugin mechanism.

But the mail session init/quit stuff shouldn't be added.  Mail session is an object and already has an init and a finalise method.  Use those.
I didn't see finalise function before, I can use that, sure. The init function was here before, so I am not introducing it.

Also what happens if quit isn't called, does it keep running?  (e.g. if evo crashes or bad shutdown path).
yeah, it keeps running. there will be still pid file around, so we may kill it in --force-shutdown as we do with e-d-s.
Hmm, thats not very good.  Is it being run async?  Shouldn't it die with the parent if evolution starts it?

This has to be fixed somehow since there's no guarantee evolution will close properly.
So far we start it as daemon. I guess we can modify it to run as evo subprocess, but it's out of scope of that patch. I can cook another patch for that. I have to find out if evo already handles SIGCHLD signal too.

So to summarize it,

  • I will use finalise function
  • I can add spamd respawning if you think it's necessary. Do you?
I think its worth it.  It's easy to just count the restarts and give up if you get them too often.

--
Michael Zucchi <notzed ximian com>
"born to die, live to work, it's all downhill from here"
Novell's Evolution and Free Software Developer
--
Radek Doulík <rodo novell com>
Novell, Inc.
Index: camel/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/camel/ChangeLog,v
retrieving revision 1.2280
diff -u -p -r1.2280 ChangeLog
--- camel/ChangeLog	21 Oct 2004 19:35:21 -0000	1.2280
+++ camel/ChangeLog	27 Oct 2004 12:39:05 -0000
@@ -1,3 +1,9 @@
+2004-10-12  Radek Doulik  <rodo ximian com>
+
+	* camel-junk-plugin.c: new init method implementation
+
+	* camel-junk-plugin.h: added junk plugin init declaration
+
 2004-10-21  Jeffrey Stedfast  <fejj novell com>
 
 	* camel-sasl-gssapi.c: #include "camel-i18n.h"
Index: camel/camel-junk-plugin.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-junk-plugin.c,v
retrieving revision 1.2
diff -u -p -r1.2 camel-junk-plugin.c
--- camel/camel-junk-plugin.c	12 Nov 2003 21:12:48 -0000	1.2
+++ camel/camel-junk-plugin.c	27 Oct 2004 12:39:05 -0000
@@ -73,3 +73,12 @@ camel_junk_plugin_commit_reports (CamelJ
 	if (csp->commit_reports)
 		(*csp->commit_reports) ();
 }
+
+void
+camel_junk_plugin_init (CamelJunkPlugin *csp)
+{
+	d(fprintf (stderr, "camel_junk_plugin_init\n");)
+
+	if (csp->init)
+		(*csp->init) ();
+}
Index: camel/camel-junk-plugin.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-junk-plugin.h,v
retrieving revision 1.2
diff -u -p -r1.2 camel-junk-plugin.h
--- camel/camel-junk-plugin.h	12 Nov 2003 21:12:48 -0000	1.2
+++ camel/camel-junk-plugin.h	27 Oct 2004 12:39:05 -0000
@@ -48,6 +48,9 @@ struct _CamelJunkPlugin
 
 	/* called after one or more junk/ham(s) reported */
 	void (*commit_reports) (void);
+
+	/* called before all other calls to junk plugin for initialization */
+	void (*init) (void);
 };
 
 const char * camel_junk_plugin_get_name (CamelJunkPlugin *csp);
@@ -55,5 +58,6 @@ int camel_junk_plugin_check_junk (CamelJ
 void camel_junk_plugin_report_junk (CamelJunkPlugin *csp, struct _CamelMimeMessage *message);
 void camel_junk_plugin_report_notjunk (CamelJunkPlugin *csp, struct _CamelMimeMessage *message);
 void camel_junk_plugin_commit_reports (CamelJunkPlugin *csp);
+void camel_junk_plugin_init (CamelJunkPlugin *csp);
 
 #endif
Index: mail/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.3486
diff -u -p -r1.3486 ChangeLog
--- mail/ChangeLog	22 Oct 2004 19:33:51 -0000	1.3486
+++ mail/ChangeLog	27 Oct 2004 12:39:09 -0000
@@ -1,3 +1,17 @@
+2004-10-12  Radek Doulik  <rodo ximian com>
+
+	* em-junk-filter.c: when starting new spamd, call it with
+	--socketpath parameter to use unix sockets instead of opening TCP
+	port. kill such started daemon in finalize callback which is
+	installed by atexit. also try to respawn spamd in case spamc
+	returns error, if respawning is too fast (8 restarts in last 5
+	minutes) fallback to spamassassin
+
+	* mail-component.c (impl_quit): call mail_session_quit
+
+	* mail-session.c (mail_session_init): call junk plugin init
+	(mail_session_quit): new method, called on evo exit
+
 2004-10-22  Jeffrey Stedfast  <fejj novell com>
 
 	* em-folder-tree.c: Give the Rename item a different path than the
Index: mail/em-junk-filter.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-junk-filter.c,v
retrieving revision 1.24
diff -u -p -r1.24 em-junk-filter.c
--- mail/em-junk-filter.c	20 Sep 2004 05:59:54 -0000	1.24
+++ mail/em-junk-filter.c	27 Oct 2004 12:39:09 -0000
@@ -33,11 +33,15 @@
 #include <signal.h>
 #include <string.h>
 #include <pthread.h>
+#include <signal.h>
+#include <time.h>
 
 #include <camel/camel-file-utils.h>
 #include <camel/camel-data-wrapper.h>
 #include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-mem.h>
 #include <camel/camel-i18n.h>
+#include <e-util/e-mktemp.h>
 
 #include "mail-session.h"
 #include "em-junk-filter.h"
@@ -48,12 +52,17 @@
 
 static pthread_mutex_t em_junk_sa_init_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t em_junk_sa_report_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t em_junk_sa_preferred_socket_path_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t em_junk_sa_spamd_restart_lock = PTHREAD_MUTEX_INITIALIZER;
 
 static const char *em_junk_sa_get_name (void);
 static gboolean em_junk_sa_check_junk (CamelMimeMessage *msg);
 static void em_junk_sa_report_junk (CamelMimeMessage *msg);
 static void em_junk_sa_report_notjunk (CamelMimeMessage *msg);
 static void em_junk_sa_commit_reports (void);
+static void em_junk_sa_init (void);
+static void em_junk_sa_finalize (void);
+static void em_junk_sa_kill_spamd (void);
 
 static EMJunkPlugin spam_assassin_plugin = {
 	{
@@ -63,6 +72,7 @@ static EMJunkPlugin spam_assassin_plugin
 		em_junk_sa_report_junk,
 		em_junk_sa_report_notjunk,
 		em_junk_sa_commit_reports,
+		em_junk_sa_init,
 	},
 	NULL,
 	NULL
@@ -72,14 +82,24 @@ static gboolean em_junk_sa_tested = FALS
 static gboolean em_junk_sa_spamd_tested = FALSE;
 static gboolean em_junk_sa_use_spamc = FALSE;
 static gboolean em_junk_sa_available = FALSE;
-static int em_junk_sa_spamd_port = -1;
+static gboolean em_junk_sa_system_spamd_available = FALSE;
+static gboolean em_junk_sa_new_daemon_started = FALSE;
+static char *em_junk_sa_socket_path = NULL;
+static char *em_junk_sa_spamd_pidfile = NULL;
 static char *em_junk_sa_spamc_binary = NULL;
 static GConfClient *em_junk_sa_gconf = NULL;
 
 /* volatile so not cached between threads */
 static volatile gboolean em_junk_sa_local_only;
 static volatile gboolean em_junk_sa_use_daemon;
-static volatile int em_junk_sa_daemon_port;
+static char * em_junk_sa_preferred_socket_path;
+
+static char *em_junk_sa_spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
+static char *em_junk_sa_spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
+
+#define SPAMD_RESTARTS_SIZE 8
+static time_t em_junk_sa_spamd_restarts [SPAMD_RESTARTS_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0};
+static int em_junk_sa_spamd_restarts_count = 0;
 
 static const char *
 em_junk_sa_get_name (void)
@@ -88,9 +108,9 @@ em_junk_sa_get_name (void)
 }
 
 static int
-pipe_to_sa_with_error (CamelMimeMessage *msg, const char *in, char **argv, int rv_err)
+pipe_to_sa_full (CamelMimeMessage *msg, const char *in, char **argv, int rv_err, int wait_for_termination, GByteArray *output_buffer)
 {
-	int result, status, errnosav, fds[2];
+	int result, status, errnosav, fds[2], out_fds[2];
 	CamelStream *stream;
 	char *program;
 	pid_t pid;
@@ -120,6 +140,13 @@ pipe_to_sa_with_error (CamelMimeMessage 
 		return rv_err;
 	}
 	
+	if (output_buffer && pipe (out_fds) == -1) {
+		errnosav = errno;
+		d(printf ("failed to create a pipe (for use with spamassassin: %s\n", strerror (errno)));
+		errno = errnosav;
+		return rv_err;
+	}
+	
 	if (!(pid = fork ())) {
 		/* child process */
 		int maxfd, fd, nullfd;
@@ -127,10 +154,14 @@ pipe_to_sa_with_error (CamelMimeMessage 
 		nullfd = open ("/dev/null", O_WRONLY);
 		
 		if (dup2 (fds[0], STDIN_FILENO) == -1 ||
-		    dup2 (nullfd, STDOUT_FILENO) == -1 ||
-		    dup2 (nullfd, STDERR_FILENO) == -1)
+		    dup2 (nullfd, STDERR_FILENO) == -1 ||
+		    (output_buffer == NULL && dup2 (nullfd, STDOUT_FILENO) == -1) ||
+		    (output_buffer != NULL && dup2 (out_fds[1], STDOUT_FILENO) == -1))
 			_exit (rv_err & 0377);
-		
+		close (fds [0]);
+		if (output_buffer)
+			close (out_fds [1]);
+
 		setsid ();
 		
 		maxfd = sysconf (_SC_OPEN_MAX);
@@ -149,6 +180,8 @@ pipe_to_sa_with_error (CamelMimeMessage 
 	
 	/* parent process */
 	close (fds[0]);
+	if (output_buffer)
+		close (out_fds [1]);
 	
 	if (msg) {
 		stream = camel_stream_fs_new_with_fd (fds[1]);
@@ -161,54 +194,92 @@ pipe_to_sa_with_error (CamelMimeMessage 
 		camel_write (fds[1], in, strlen (in));
 		close (fds[1]);
 	}
+
+	if (output_buffer) {
+		CamelStreamMem *memstream;
+
+		stream = camel_stream_fs_new_with_fd (out_fds[0]);
+		
+		memstream = (CamelStreamMem *) camel_stream_mem_new ();
+		camel_stream_mem_set_byte_array (memstream, output_buffer);
+		
+		camel_stream_write_to_stream (stream, (CamelStream *) memstream);
+		camel_object_unref (stream);
+		g_byte_array_append (output_buffer, "", 1);
+
+		d(printf ("child process output: %s len: %d\n", output_buffer->data, output_buffer->len));
+	}
 	
-	result = waitpid (pid, &status, 0);
+	if (wait_for_termination) {
+		d(printf ("wait for child %d termination\n", pid));
+		result = waitpid (pid, &status, 0);
 	
-	if (result == -1 && errno == EINTR) {
-		/* child process is hanging... */
-		kill (pid, SIGTERM);
-		sleep (1);
-		result = waitpid (pid, &status, WNOHANG);
-		if (result == 0) {
-			/* ...still hanging, set phasers to KILL */
-			kill (pid, SIGKILL);
+		d(printf ("child %d terminated with result %d status %d exited %d exitstatus %d\n", pid, result, status, WIFEXITED (status), WEXITSTATUS (status)));
+
+		if (result == -1 && errno == EINTR) {
+			/* child process is hanging... */
+			kill (pid, SIGTERM);
 			sleep (1);
 			result = waitpid (pid, &status, WNOHANG);
+			if (result == 0) {
+				/* ...still hanging, set phasers to KILL */
+				kill (pid, SIGKILL);
+				sleep (1);
+				result = waitpid (pid, &status, WNOHANG);
+			}
 		}
-	}
 	
-	if (result != -1 && WIFEXITED (status))
-		return WEXITSTATUS (status);
-	else
-		return rv_err;
+		if (result != -1 && WIFEXITED (status))
+			return WEXITSTATUS (status);
+		else
+			return rv_err;
+	} else
+		return 0;
 }
 
 static int
 pipe_to_sa (CamelMimeMessage *msg, const char *in, char **argv)
 {
-	return pipe_to_sa_with_error (msg, in, argv, -1);
+	return pipe_to_sa_full (msg, in, argv, -1, 1, NULL);
+}
+
+static char *
+em_junk_sa_get_socket_path ()
+{
+	if (em_junk_sa_preferred_socket_path)
+		return em_junk_sa_preferred_socket_path;
+	else
+		return em_junk_sa_socket_path;
 }
 
 static gboolean
-em_junk_sa_test_spamd_running (char *binary, int port)
+em_junk_sa_test_spamd_running (char *binary, gboolean system)
 {
-	char port_buf[12], *argv[5];
+	char *argv[5];
 	int i = 0;
-	
-	d(fprintf (stderr, "test if spamd is running (port %d) using %s\n", port, binary));
+	gboolean rv;
+
+	pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+
+	d(fprintf (stderr, "test if spamd is running (system %d) or using socket path %s\n", system, em_junk_sa_get_socket_path ()));
 	
 	argv[i++] = binary;
 	argv[i++] = "-x";
 	
-	if (port > 0) {
-		sprintf (port_buf, "%d", port);
-		argv[i++] = "-p";
-		argv[i++] = port_buf;
+	if (!system) {
+		argv[i++] = "-U";
+		argv[i++] = em_junk_sa_get_socket_path ();
 	}
 	
 	argv[i] = NULL;
 	
-	return pipe_to_sa (NULL, "From test 127 0 0 1", argv) == 0;
+	rv = pipe_to_sa (NULL, "From test 127 0 0 1", argv) == 0;
+
+	d(fprintf (stderr, "result: %d (%s)\n", rv, rv ? "success" : "failed"));
+
+	pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+	return rv;
 }
 
 static void
@@ -231,37 +302,93 @@ em_junk_sa_test_spamassassin (void)
 #define MAX_SPAMD_PORTS 1
 
 static gboolean
-em_junk_sa_run_spamd (char *binary, int *port)
+em_junk_sa_run_spamd (char *binary)
 {
-	char *argv[6];
-	char port_buf[12];
-	int i, p = em_junk_sa_daemon_port;
+	char *argv[8];
+	int i;
+	gboolean rv = FALSE;
+
+	pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
 
 	d(fprintf (stderr, "looks like spamd is not running\n"));
 
 	i = 0;
 	argv[i++] = binary;
-	argv[i++] = "--port";
-	argv[i++] = port_buf;
+	argv[i++] = "--socketpath";
+	argv[i++] = em_junk_sa_get_socket_path ();
 		
 	if (em_junk_sa_local_only)
 		argv[i++] = "--local";
 		
-	argv[i++] = "--daemonize";
+	//argv[i++] = "--daemonize";
+	argv[i++] = "--pidfile";
+	argv[i++] = em_junk_sa_spamd_pidfile;
 	argv[i] = NULL;
-		
-	for (i = 0; i < MAX_SPAMD_PORTS; i++, p++) {
-		d(fprintf (stderr, "trying to run %s at port %d\n", binary, p));
+
+	d(fprintf (stderr, "trying to run %s with socket path %s\n", binary, em_junk_sa_get_socket_path ()));
 			
-		snprintf (port_buf, 11, "%d", p);
-		if (!pipe_to_sa (NULL, NULL, argv)) {
-			d(fprintf (stderr, "success at port %d\n", p));
-			*port = p;
-			return TRUE;
+	if (!pipe_to_sa_full (NULL, NULL, argv, -1, 0, NULL)) {
+		int i;
+		struct timespec time_req;
+		struct stat stat_buf;
+
+		d(fprintf (stderr, "success\n"));
+		d(fprintf (stderr, "waiting for spamd to come up\n"));
+
+		time_req.tv_sec = 0;
+		time_req.tv_nsec = 50000000;
+
+		for (i = 0; i < 100; i ++) {
+			if (stat (em_junk_sa_get_socket_path (), &stat_buf) == 0) {
+				d(fprintf (stderr, "socket created\n"));
+				break;
+			}
+			nanosleep (&time_req, NULL);
+		}
+		d(fprintf (stderr, "waiting is over (after %dms)\n", 50*i));
+
+		rv = TRUE;
+	}
+
+	pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+	return rv;
+}
+
+static void
+em_junk_sa_start_own_daemon ()
+{
+	int b;
+
+	em_junk_sa_new_daemon_started = FALSE;
+
+	em_junk_sa_socket_path = e_mktemp ("spamd-socket-path-XXXXXX");
+	em_junk_sa_spamd_pidfile = e_mktemp ("spamd-pid-file-XXXXXX");
+
+	for (b = 0; em_junk_sa_spamd_binaries [b]; b ++) {
+		em_junk_sa_use_spamc = em_junk_sa_run_spamd (em_junk_sa_spamd_binaries [b]);
+		if (em_junk_sa_use_spamc) {
+			em_junk_sa_new_daemon_started = TRUE;
+			break;
 		}
 	}
+}
+
+static void
+em_junk_sa_find_spamc ()
+{
+	if (em_junk_sa_use_spamc && em_junk_sa_new_daemon_started) {
+		int b;
 
-	return FALSE;
+		em_junk_sa_use_spamc = FALSE;
+		for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+			em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+			if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
+				em_junk_sa_use_spamc = TRUE;
+				break;
+			}
+		}
+	}
 }
 
 static void
@@ -270,22 +397,19 @@ em_junk_sa_test_spamd (void)
 	char *argv[4];
 	int i, b;
 	gboolean try_system_spamd = TRUE;
-	gboolean new_daemon_started = FALSE;
-	char *spamc_binaries [3] = {"spamc", "/usr/sbin/spamc", NULL};
-	char *spamd_binaries [3] = {"spamd", "/usr/sbin/spamd", NULL};
 
 	if (em_junk_sa_gconf) {
 		char *binary;
 
 		binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamc_binary", NULL);
 		if (binary) {
-			spamc_binaries [0] = binary;
-			spamc_binaries [1] = NULL;
+			em_junk_sa_spamc_binaries [0] = binary;
+			em_junk_sa_spamc_binaries [1] = NULL;
 		}
 		binary = gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/spamd_binary", NULL);
 		if (binary) {
-			spamd_binaries [0] = binary;
-			spamd_binaries [1] = NULL;
+			em_junk_sa_spamd_binaries [0] = binary;
+			em_junk_sa_spamd_binaries [1] = NULL;
 			try_system_spamd = FALSE;
 		}
 	}
@@ -307,55 +431,36 @@ em_junk_sa_test_spamd (void)
 
 	/* try to use sytem spamd first */
 	if (try_system_spamd) {
-		for (b = 0; spamc_binaries [b]; b ++) {
-			em_junk_sa_spamc_binary = spamc_binaries [b];
-			if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, -1)) {
+		for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+			em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+			if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, TRUE)) {
 				em_junk_sa_use_spamc = TRUE;
-				em_junk_sa_spamd_port = -1;
+				em_junk_sa_system_spamd_available = TRUE;
 				break;
 			}
 		}
 	}
 
-	/* if there's no system spamd running, try to use user one on evo spamd port */
-	if (!em_junk_sa_use_spamc) {
-		int port = em_junk_sa_daemon_port;
-
-		for (i = 0; i < MAX_SPAMD_PORTS; i ++, port ++) {
-			for (b = 0; spamc_binaries [b]; b ++) {
-				em_junk_sa_spamc_binary = spamc_binaries [b];
-				if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, port)) {
-					em_junk_sa_use_spamc = TRUE;
-					em_junk_sa_spamd_port = port;
-					break;
-				}
+	/* if there's no system spamd running, try to use user one with user specified socket */
+	if (!em_junk_sa_use_spamc && em_junk_sa_preferred_socket_path) {
+		for (b = 0; em_junk_sa_spamc_binaries [b]; b ++) {
+			em_junk_sa_spamc_binary = em_junk_sa_spamc_binaries [b];
+			if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, FALSE)) {
+				em_junk_sa_use_spamc = TRUE;
+				em_junk_sa_system_spamd_available = FALSE;
+				break;
 			}
 		}
 	}
 
 	/* unsuccessful? try to run one ourselfs */
 	if (!em_junk_sa_use_spamc)
-		for (b = 0; spamd_binaries [b]; b ++) {
-			em_junk_sa_use_spamc = em_junk_sa_run_spamd (spamd_binaries [b], &em_junk_sa_spamd_port);
-			if (em_junk_sa_use_spamc) {
-				new_daemon_started = TRUE;
-				break;
-			}
-		}
-	
+		em_junk_sa_start_own_daemon ();
+
 	/* new daemon started => let find spamc binary */
-	if (em_junk_sa_use_spamc && new_daemon_started) {
-		em_junk_sa_use_spamc = FALSE;
-		for (b = 0; spamc_binaries [b]; b ++) {
-			em_junk_sa_spamc_binary = spamc_binaries [b];
-			if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_spamd_port)) {
-				em_junk_sa_use_spamc = TRUE;
-				break;
-			}
-		}
-	}
+	em_junk_sa_find_spamc ();
 
-	d(fprintf (stderr, "use spamd %d at port %d with %s\n", em_junk_sa_use_spamc, em_junk_sa_spamd_port, em_junk_sa_spamc_binary));
+	d(fprintf (stderr, "use spamd: %s\n", em_junk_sa_use_spamc ? "yes" : "no"));
 	
 	em_junk_sa_spamd_tested = TRUE;
 }
@@ -377,23 +482,84 @@ em_junk_sa_is_available (void)
 }
 
 static gboolean
+em_junk_sa_check_respawn_too_fast ()
+{
+	time_t time_now = time (NULL);
+	gboolean rv;
+
+	pthread_mutex_lock (&em_junk_sa_spamd_restart_lock);
+
+	if (em_junk_sa_spamd_restarts_count >= SPAMD_RESTARTS_SIZE) {
+		/* all restarts in last 5 minutes */
+		rv = (time_now - em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] < 5*60);
+	} else
+		rv = FALSE;
+
+	em_junk_sa_spamd_restarts [em_junk_sa_spamd_restarts_count % SPAMD_RESTARTS_SIZE] = time_now;
+	em_junk_sa_spamd_restarts_count ++;
+
+	pthread_mutex_unlock (&em_junk_sa_spamd_restart_lock);
+
+	d(printf ("em_junk_sa_check_respawn_too_fast: %d\n", rv));
+
+	return rv;
+}
+
+static gboolean
+em_junk_sa_respawn_spamd ()
+{
+	d(printf ("em_junk_sa_respawn_spamd\n"));
+	if (em_junk_sa_test_spamd_running (em_junk_sa_spamc_binary, em_junk_sa_system_spamd_available)) {
+		/* false alert */
+		d(printf ("false alert, spamd still running\n"));
+
+		return FALSE;
+	}
+
+	d(printf ("going to kill old spamd and start new one\n"));
+	em_junk_sa_kill_spamd ();
+
+	if (em_junk_sa_check_respawn_too_fast ()) {
+		g_warning ("respawning of spamd too fast => fallback to use spamassassin directly");
+
+		em_junk_sa_use_spamc = em_junk_sa_use_daemon = FALSE;
+		return FALSE;
+	}
+
+	em_junk_sa_start_own_daemon ();
+	em_junk_sa_find_spamc ();
+
+	d(printf ("%s\n", em_junk_sa_use_spamc ? "success" : "failed"));
+
+	return em_junk_sa_use_spamc;
+}
+
+static gboolean
 em_junk_sa_check_junk (CamelMimeMessage *msg)
 {
-	char *argv[5], buf[12];
-	int i = 0;
-	
+	GByteArray *out = NULL;
+	char *argv[7], *to_free = NULL;
+	int i = 0, socket_i;
+	gboolean rv;
+
 	d(fprintf (stderr, "em_junk_sa_check_junk\n"));
 	
 	if (!em_junk_sa_is_available ())
 		return FALSE;
-	
+
 	if (em_junk_sa_use_spamc && em_junk_sa_use_daemon) {
+		out = g_byte_array_new ();
 		argv[i++] = em_junk_sa_spamc_binary;
 		argv[i++] = "-c";
-		if (em_junk_sa_spamd_port != -1) {
-			sprintf (buf, "%d", em_junk_sa_spamd_port);
-			argv[i++] = "-p";
-			argv[i++] = buf;
+		argv[i++] = "-t";
+		argv[i++] = "60";
+		if (!em_junk_sa_system_spamd_available) {
+			argv[i++] = "-U";
+
+			pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+			socket_i = i;
+			argv[i++] = to_free = g_strdup (em_junk_sa_get_socket_path ());
+			pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
 		}
 	} else {
 		argv [i++] = "spamassassin";
@@ -404,7 +570,32 @@ em_junk_sa_check_junk (CamelMimeMessage 
 	
 	argv[i] = NULL;
 
-	return pipe_to_sa_with_error (msg, NULL, argv, 0) != 0;
+	rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
+
+	if (!rv && out && !strcmp (out->data, "0/0\n")) {
+		/* an error occured */
+		if (em_junk_sa_respawn_spamd ()) {
+			g_byte_array_set_size (out, 0);
+
+			pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+			g_free (to_free);
+			argv [socket_i] = to_free = g_strdup (em_junk_sa_get_socket_path ());
+			pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+			rv = pipe_to_sa_full (msg, NULL, argv, 0, 1, out) != 0;
+		} else if (!em_junk_sa_use_spamc)
+			/* in case respawning were too fast we fallback to spamassassin */
+			rv = em_junk_sa_check_junk (msg);
+	}
+
+	g_free (to_free);
+
+	d(fprintf (stderr, "em_junk_sa_check_junk rv = %d\n", rv));
+
+	if (out)
+		g_byte_array_free (out, TRUE);
+
+	return rv;
 }
 
 static void
@@ -495,25 +686,81 @@ em_junk_sa_setting_notify(GConfClient *g
 		em_junk_sa_local_only = gconf_value_get_bool(value);
 	else if (!strcmp(tkey, "use_daemon"))
 		em_junk_sa_use_daemon = gconf_value_get_bool(value);
-	else if (!strcmp(tkey, "daemon_port"))
-		em_junk_sa_daemon_port = gconf_value_get_int(value);
+	else if (!strcmp(tkey, "socket_path")) {
+		pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+		g_free (em_junk_sa_preferred_socket_path);
+		em_junk_sa_preferred_socket_path = g_strdup (gconf_value_get_string(value));
+		pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+	}
 }
 
 const EMJunkPlugin *
 em_junk_filter_get_plugin (void)
 {
+	return &spam_assassin_plugin;
+}
+
+static void
+em_junk_sa_init (void)
+{
 	if (!em_junk_sa_gconf) {
 		em_junk_sa_gconf = gconf_client_get_default();
 		gconf_client_add_dir (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
 
 		em_junk_sa_local_only = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/local_only", NULL);
 		em_junk_sa_use_daemon = gconf_client_get_bool (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/use_daemon", NULL);
-		em_junk_sa_daemon_port = gconf_client_get_int (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/daemon_port", NULL);
+
+		pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+		g_free (em_junk_sa_preferred_socket_path);
+		em_junk_sa_preferred_socket_path = g_strdup (gconf_client_get_string (em_junk_sa_gconf, "/apps/evolution/mail/junk/sa/socket_path", NULL));
+		pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
 
 		gconf_client_notify_add(em_junk_sa_gconf, "/apps/evolution/mail/junk/sa",
 					(GConfClientNotifyFunc)em_junk_sa_setting_notify,
 					NULL, NULL, NULL);
 	}
 
-	return &spam_assassin_plugin;
+	atexit (em_junk_sa_finalize);
+}
+
+static void
+em_junk_sa_kill_spamd (void)
+{
+	pthread_mutex_lock (&em_junk_sa_preferred_socket_path_lock);
+	g_free (em_junk_sa_preferred_socket_path);
+	em_junk_sa_preferred_socket_path = NULL;
+	pthread_mutex_unlock (&em_junk_sa_preferred_socket_path_lock);
+
+	if (em_junk_sa_new_daemon_started) {
+		int fd = open (em_junk_sa_spamd_pidfile, O_RDONLY);
+
+		if (fd != -1) {
+			char pid_str [16];
+			int bytes;
+
+			bytes = read (fd, pid_str, 15);
+			if (bytes > 0) {
+				int pid;
+
+				pid_str [bytes] = 0;
+				pid = atoi (pid_str);
+
+				if (pid > 0) {
+					kill (pid, SIGTERM);
+					d(fprintf (stderr, "em_junk_sa_finalize send SIGTERM to daemon with pid %d\n", pid));
+					waitpid (pid, NULL, 0);
+				}
+			}
+
+			close (fd);
+		}
+	}
+}
+
+static void
+em_junk_sa_finalize (void)
+{
+	d(fprintf (stderr, "em_junk_sa_finalize\n"));
+
+	em_junk_sa_kill_spamd ();
 }
Index: mail/mail-session.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-session.c,v
retrieving revision 1.98
diff -u -p -r1.98 mail-session.c
--- mail/mail-session.c	20 Sep 2004 05:59:55 -0000	1.98
+++ mail/mail-session.c	27 Oct 2004 12:39:09 -0000
@@ -641,6 +641,8 @@ mail_session_init (const char *base_dire
 								(GConfClientNotifyFunc) mail_session_check_junk_notify,
 								session, NULL, NULL);
 	session->junk_plugin = CAMEL_JUNK_PLUGIN (em_junk_filter_get_plugin ());
+	if (session->junk_plugin)
+		camel_junk_plugin_init (session->junk_plugin);
 
 	/* The shell will tell us to go online. */
 	camel_session_set_online ((CamelSession *) session, FALSE);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]