[Raw Msg Headers][Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Another not-so-nice problem



Rationale for this patch to the SMTP transport: The dreaded "I can't send
the message and I'm stuck" case.
Because of networking problems, my system couldn't send a message out fast
enough, so appendlet() reported an error. The old code then sent RSET (ok),
but then proceeded with "." -- thereby telling the other side that the
message has been completed successfully?!? Not a good idea.
The better idea is to consider the connection broken and to close it.
The other side will either timeout or see our FIN packet and discard the
message, and we can reopen the SMTP connection if necessary.

This means that deliver() has to return an error code and that process()
needs channel and host info to be able to reopen the connection.

TODO: The smtpwrite() code should be extended to get the first digit of the
expected return message as a parameter. Right now, a synchronization problem
is possibly undetected until several SMTP exchanges later.

Unrelated TODO: libsh/interpret.c has some tables which limit recursion depth
and, worse, crash the router when exceeded.
These should probably be limit-checked, and either be configurable (several
tables have size 30, but they seem to be used differently) or allocated
dynamically.

--- smtp.c.orig	Tue Dec 22 01:42:52 1992
+++ smtp.c	Tue Dec 22 02:00:52 1992
@@ -280,7 +280,7 @@
 			continue;
 		if (smtpstatus == EX_DATAERR)
 			smtpstatus = smtpopen(channel, host, smtpfp);
-		smtpstatus = process(dp, smtpstatus, smtpfp);
+		smtpstatus = process(dp, smtpstatus, channel,host,smtpfp);
 		ctlclose(dp);
 	}
 	if (smtpstatus == EX_OK) {
@@ -297,14 +297,15 @@
 }
 
 int
-process(dp, smtpstatus, smtpfp)
+process(dp, smtpstatus, channel,host, smtpfp)
 	struct ctldesc *dp;
 	int smtpstatus;
+	const char *channel, *host;
 	FILE *smtpfp[];
 {
 	struct rcpt *rp, *rphead;
 	int loggedid;
-	extern void deliver();
+	extern int deliver();
 
 	readalready = 0; /* ignore any previous message data cache */
 	loggedid = 0;
@@ -322,8 +323,13 @@
 						       dp->logident);
 					(void) fflush(logfp);
 				}
-				deliver(smtpfp, rphead, rp->next,
+				smtpstatus = deliver(smtpfp, rphead, rp->next,
 						dp->msgfd, dp->msgbodyoffset);
+				if(smtpstatus != EX_OK) {
+					(void)fclose(smtpfp[0]);
+					(void)fclose(smtpfp[1]);
+					smtpstatus = smtpopen(channel, host, smtpfp);
+				}
 				rphead = rp->next;
 			} else {
 				while (rphead != rp->next) {
@@ -342,7 +348,7 @@
  *	     errors and requests for further processing in the structure
  */
 
-void
+int
 deliver(smtpfp, startrp, endrp, messagefd, msgoffset)
 	FILE *smtpfp[2];
 	struct rcpt *startrp, *endrp;
@@ -362,7 +368,7 @@
 			diagnostic(rp, r, "%s", remotemsg);
 		/* Odd errors in here at the times. Do RSET. [mea] 28/Jan/92 */
 		(void) smtpwrite(smtpfp, "RSET", (char *)NULL);
-		return;
+		return EX_OK;
 	}
 	nrcpt = 0;
 	for (rp = startrp; rp != endrp; rp = rp->next) {
@@ -377,7 +383,7 @@
 	if (nrcpt == 0) {
 		/* all the RCPT To addresses were rejected, so reset server */
 		(void) smtpwrite(smtpfp, "RSET", (char *)NULL);
-		return;
+		return EX_OK;
 	}
 	if ((r = smtpwrite(smtpfp, "DATA", (char *)NULL)) != EX_OK) {
 		for (rp = startrp; rp != endrp; rp = rp->next)
@@ -384,7 +390,7 @@
 			if (rp->status == EX_OK)
 				diagnostic(rp, EX_TEMPFAIL, "%s", remotemsg);
 		(void) smtpwrite(smtpfp, "RSET", (char *)NULL);
-		return;
+		return EX_OK;
 	}
 	hsize = strlen(startrp->newmsgheader);
 	(void) writebuf(smtpfp[1], (char *)NULL, 0);	/* magic init. */
@@ -396,7 +402,7 @@
 					      "header write error");
 		/* When it fails, RSET the state... [mea] */
 		(void) smtpwrite(smtpfp, "RSET", (char *)NULL);
-		return;
+		return EX_UNAVAILABLE;
 	}
 	++hsize;
 	/* append message body itself */
@@ -421,6 +427,14 @@
 		 * also harmless.
 		 */
 		(void) smtpwrite(smtpfp, "RSET", (char *)NULL);
+		/*
+		 * OK, now what? In case 1 we now have sent a partial message
+		 * across the line. We do NOT want to terminate this message
+		 * with an end-of-message indication!
+		 * Instead, we close the connection and try again with the
+		 * next address.
+		 */
+		 return EX_UNAVAILABLE;
 	}
 	/*
 	 * This is the one place where we *have* to wait forever because
@@ -442,7 +456,7 @@
 	for (rp = startrp; rp != endrp; rp = rp->next)
 		if (rp->status == EX_OK)
 			diagnostic(rp, r, "%s", remotemsg);
-	return;
+	return r;
 }
 
 /*

-- 
The vast majority of successful major crimes against property are
perpetrated by individuals abusing positions of trust.
				-- Lawrence Dalzell
-- 
Matthias Urlichs  --  urlichs@smurf.sub.org -- urlichs@smurf.ira.uka.de   /(o\
Humboldtstrasse 7 -- 7500 Karlsruhe 1 -- Germany  --  +49-721-9612521     \o)/