From 800186e3873690997bdbd7e1b60c83ca2d9819cd Mon Sep 17 00:00:00 2001
From: "Eric S. Raymond" <esr@thyrsus.com>
Date: Tue, 29 Oct 1996 01:54:58 +0000
Subject: Only open one conneection per host in daemon mode.

svn path=/trunk/; revision=414
---
 NEWS        |  1 +
 driver.c    | 60 +++++++++++++++++++++++++++---------------------------------
 fetchmail.c | 38 ++++++++++++++++++++++++++++++++++++--
 fetchmail.h |  6 ++++--
 4 files changed, 68 insertions(+), 37 deletions(-)

diff --git a/NEWS b/NEWS
index 5a464d3b..2cce085e 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@
 
 pl 1.9.4 ():
 * Correct status interpretation in closemailpipe() (thanks to Neil Harkins).
+* Tweak SMTP forwarding to only open one listener per SMTP host in daemon mode.
 
 pl 1.9.3 (Sun Oct 27 22:35:33 EST 1996):
 * Handle nested parens in RFC822 comments.
diff --git a/driver.c b/driver.c
index a1a68f59..f4f3b110 100644
--- a/driver.c
+++ b/driver.c
@@ -49,7 +49,6 @@ char tag[TAGLEN];
 static int tagnum;
 #define GENSYM	(sprintf(tag, "a%04d", ++tagnum), tag)
 
-static int mboxfd;	/* desc to which retrieved message will be written */
 static char *shroud;	/* string to shroud in debug output, if  non-NULL */
 
 static int strcrlf(dst, src, count)
@@ -449,29 +448,26 @@ struct idlist **xmit_names;	/* list of recipient names parsed out */
 }
 #endif /* HAVE_GETHOSTBYNAME */
 
-int smtp_open(host)
-/* try to open a socket to given host's SMTP server */ 
-char *host;
+static int smtp_open(ctl)
+/* try to open a socket to the appropriate SMTP server for this query */ 
+struct query *ctl;
 {
-    if ((mboxfd = Socket(host, SMTP_PORT)) < 0
-	|| SMTP_ok(mboxfd, NULL) != SM_OK
-	|| SMTP_helo(mboxfd, "localhost") != SM_OK)
-    {
-	close(mboxfd);
-	mboxfd = -1;
-    }
-
-    return(mboxfd);
-}
+    ctl = ctl->leader; /* go to the SMTP leader for this query */
 
-void smtp_close()
-/* close the current SMTP connection */
-{
-    if (mboxfd != -1)
+    /* if no socket to this host is already set up, try to open one */
+    if (ctl->smtp_socket == -1)
     {
-	SMTP_quit(mboxfd);
-	close(mboxfd);
+	if ((ctl->smtp_socket = Socket(ctl->smtphost, SMTP_PORT)) == -1)
+	    return(-1);
+	else if (SMTP_ok(ctl->smtp_socket, NULL) != SM_OK
+		 || SMTP_helo(ctl->smtp_socket, ctl->servername) != SM_OK)
+	{
+	    close(ctl->smtp_socket);
+	    ctl->smtp_socket = -1;
+	}
     }
+
+    return(ctl->smtp_socket);
 }
 
 static int gen_readmsg (socket, len, delimited, ctl)
@@ -483,7 +479,7 @@ struct query *ctl;	/* query control record */
 {
     char buf [MSGBUFSIZE+1]; 
     char *bufp, *headers, *fromhdr, *tohdr, *cchdr, *bcchdr;
-    int n, oldlen;
+    int n, oldlen, mboxfd;
     int inheaders,lines,sizeticker;
 
     /* read the message content from the server */
@@ -643,7 +639,7 @@ struct query *ctl;	/* query control record */
 	    }
 	    else
 	    {
-		if (ctl->mda[0] == '\0' && (smtp_open(ctl->smtphost) < 0))
+		if (ctl->mda[0] == '\0'	&& ((mboxfd = smtp_open(ctl)) < 0))
 		{
 		    free_uid_list(&xmit_names);
 		    fprintf(stderr, "fetchmail: SMTP connect failed\n");
@@ -826,7 +822,6 @@ const struct method *proto;	/* protocol method table */
     tagnum = 0;
     tag[0] = '\0';	/* nuke any tag hanging out from previous query */
     ok = 0;
-    mboxfd = -1;
 
     if (setjmp(restart) == 1)
 	fprintf(stderr,
@@ -946,14 +941,6 @@ const struct method *proto;	/* protocol method table */
 			    fputc(' ', stderr);
 		    }
 
-		    /*
-		     * If we're forwarding via SMTP, mboxfd is initialized
-		     * at this point (it was set at start of retrieval). 
-		     * If we're using an MDA it's not set -- gen_readmsg()
-		     * may have to parse message headers to know what
-		     * delivery addresses should be passed to the MDA
-		     */
-
 		    /* read the message and ship it to the output sink */
 		    ok = gen_readmsg(socket,
 				     len, 
@@ -1029,11 +1016,18 @@ const struct method *proto;	/* protocol method table */
     signal(SIGALRM, sigsave);
 
 closeUp:
-    if (!ctl->mda[0])
-	smtp_close();
     return(ok);
 }
 
+void smtp_close(mboxfd)
+/* close the current SMTP connection */
+int	mboxfd;
+{
+    if (mboxfd != -1)
+    {
+	close(mboxfd);
+    }
+}
 #if defined(HAVE_STDARG_H)
 void gen_send(int socket, char *fmt, ... )
 /* assemble command in printf(3) style and send to the server */
diff --git a/fetchmail.c b/fetchmail.c
index d6b8349d..5f76b8c2 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -63,7 +63,6 @@ char *user;		/* the name of the invoking user */
 static void termhook();
 static char *lockfile;
 static int popstatus;
-static struct query *ctl;
 
 RETSIGTYPE donothing(sig) int sig; {signal(sig, donothing);}
 
@@ -72,7 +71,7 @@ int argc;
 char **argv;
 { 
     int st, lossage, bkgd = FALSE;
-    struct query def_opts;
+    struct query def_opts, *ctl, *mp;
     int parsestatus, implicitmode;
     char *home, *tmpdir, tmpbuf[BUFSIZ]; 
     struct passwd *pw;
@@ -175,6 +174,7 @@ char **argv;
 
     /* merge in wired defaults, do sanity checks and prepare internal fields */
     for (ctl = querylist; ctl; ctl = ctl->next)
+    {
 	if (ctl->active && !(implicitmode && ctl->skip))
 	{
 #ifdef HAVE_GETHOSTBYNAME
@@ -232,6 +232,30 @@ char **argv;
 	    }
 #endif /* HAVE_GETHOSTBYNAME */
 
+	    /*
+	     * Assign SMTP leaders.  We want to allow all query blocks
+	     * sharing the same SMTP host to use the same SMTP connection.
+	     * To accomplish this, we initialize each query block's leader
+	     * field to point to the first block in the list with a matching 
+	     * SMTP host.
+	     *
+	     * In the typical case, there will be only one SMTP host (the
+	     * client machine) and thus just one SMTP leader (and one listener
+	     * process) through the entire run.
+	     */
+	    if (!ctl->mda[0])
+	    {
+		for (mp = querylist; mp && mp != ctl; mp = mp->next)
+		    if (strcmp(mp->smtphost, ctl->smtphost) == 0)
+		    {
+			ctl->leader = mp->leader;
+			goto no_new_leader;
+		    }
+		ctl->leader = ctl;
+		ctl->smtp_socket = -1;
+	    no_new_leader:;
+	    }
+
 	    /* sanity checks */
 	    if (ctl->port < 0)
 	    {
@@ -263,6 +287,9 @@ char **argv;
 		    ctl->mda_argv[1] = argp + 1 ;
 	    }
 	}
+    }
+
+    
 
     /* set up to do lock protocol */
     if ((tmpdir = getenv("TMPDIR")) == (char *)NULL)
@@ -499,9 +526,16 @@ char **argv;
 void termhook(int sig)
 /* to be executed on normal or signal-induced termination */
 {
+    struct query	*ctl;
+
     if (sig != 0)
 	fprintf(stderr, "terminated with signal %d\n", sig);
 
+    /* terminate all SMTP connections cleanly */
+    for (ctl = querylist; ctl; ctl = ctl->next)
+	if (ctl->leader == ctl && ctl->smtp_socket != -1)
+	    SMTP_quit(ctl->smtp_socket);
+
     if (!check_only)
 	write_saved_lists(querylist, idfile);
 
diff --git a/fetchmail.h b/fetchmail.h
index b03899d0..4022f625 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -92,9 +92,11 @@ struct query
 
     /* internal use */
     int active;
-    struct query *next;	/* next host in chain */
+    struct query *next;		/* next query control block in chain */
+    struct query *leader;	/* pointer to this query's SMTP leader */
+    int smtp_socket;		/* socket descriptor for SMTP connection */
     unsigned int uid;		/* UID of user to deliver to */
-    char digest [DIGESTLEN];
+    char digest [DIGESTLEN];	/* md5 digest buffer */
 #ifdef HAVE_GETHOSTBYNAME
     char *canonical_name;	/* DNS canonical name of server host */
 #endif /* HAVE_GETHOSTBYNAME */
-- 
cgit v1.2.3