ph10 2005/05/24 15:56:27 BST
Modified files:
exim-doc/doc-txt ChangeLog
exim-src/src transport.c
Added files:
exim-test-orig/AutoTest/confs 615
exim-test-orig/AutoTest/log 615
exim-test-orig/AutoTest/scripts 615
exim-test-orig/AutoTest/stderr 615
exim-test-orig/AutoTest/stdout 615
Log:
Reduce the timeout when writing a block has to be done in several
write() calls.
Revision Changes Path
1.144 +7 -0 exim/exim-doc/doc-txt/ChangeLog
1.9 +40 -13 exim/exim-src/src/transport.c
1.1 +49 -0 exim/exim-test-orig/AutoTest/confs/615 (new)
1.1 +3 -0 exim/exim-test-orig/AutoTest/log/615 (new)
1.1 +26 -0 exim/exim-test-orig/AutoTest/scripts/615 (new)
1.1 +22 -0 exim/exim-test-orig/AutoTest/stderr/615 (new)
1.1 +21 -0 exim/exim-test-orig/AutoTest/stdout/615 (new)
Index: ChangeLog
===================================================================
RCS file: /home/cvs/exim/exim-doc/doc-txt/ChangeLog,v
retrieving revision 1.143
retrieving revision 1.144
diff -u -r1.143 -r1.144
--- ChangeLog 24 May 2005 10:57:10 -0000 1.143
+++ ChangeLog 24 May 2005 14:56:26 -0000 1.144
@@ -1,4 +1,4 @@
-$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.143 2005/05/24 10:57:10 ph10 Exp $
+$Cambridge: exim/exim-doc/doc-txt/ChangeLog,v 1.144 2005/05/24 14:56:26 ph10 Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -47,6 +47,13 @@
preserve the sysexits.h value, by assumimg that macro definitions were
scanned for macro replacements. I have been disabused of this notion,
so now the code just undefines EX_OK before #including unistd.h.
+
+PH/06 There is a timeout for writing blocks of data, set by, e.g. data_timeout
+ in the smtp transport. When a block could not be written in a single
+ write() function, the timeout was being re-applied to each part-write.
+ This seems wrong - if the receiver was accepting one byte at a time it
+ would take for ever. The timeout is now adjusted when this happens. It
+ doesn't have to be particularly precise.
Exim version 4.51
Index: transport.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/transport.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- transport.c 3 May 2005 14:20:01 -0000 1.8
+++ transport.c 24 May 2005 14:56:27 -0000 1.9
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/transport.c,v 1.8 2005/05/03 14:20:01 ph10 Exp $ */
+/* $Cambridge: exim/exim-src/src/transport.c,v 1.9 2005/05/24 14:56:27 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -199,26 +199,42 @@
transport_write_block(int fd, uschar *block, int len)
{
int i, rc, save_errno;
+int local_timeout = transport_write_timeout;
+
+/* This loop is for handling incomplete writes and other retries. In most
+normal cases, it is only ever executed once. */
for (i = 0; i < 100; i++)
{
DEBUG(D_transport)
debug_printf("writing data block fd=%d size=%d timeout=%d\n",
- fd, len, transport_write_timeout);
- if (transport_write_timeout > 0) alarm(transport_write_timeout);
+ fd, len, local_timeout);
- #ifdef SUPPORT_TLS
- if (tls_active == fd) rc = tls_write(block, len); else
- #endif
+ /* This code makes use of alarm() in order to implement the timeout. This
+ isn't a very tidy way of doing things. Using non-blocking I/O with select()
+ provides a neater approach. However, I don't know how to do this when TLS is
+ in use. */
- rc = write(fd, block, len);
- save_errno = errno;
+ if (transport_write_timeout <= 0) /* No timeout wanted */
+ {
+ #ifdef SUPPORT_TLS
+ if (tls_active == fd) rc = tls_write(block, len); else
+ #endif
+ rc = write(fd, block, len);
+ save_errno = errno;
+ }
- /* Cancel the alarm and deal with a timeout */
+ /* Timeout wanted. */
- if (transport_write_timeout > 0)
+ else
{
- alarm(0);
+ alarm(local_timeout);
+ #ifdef SUPPORT_TLS
+ if (tls_active == fd) rc = tls_write(block, len); else
+ #endif
+ rc = write(fd, block, len);
+ save_errno = errno;
+ local_timeout = alarm(0);
if (sigalrm_seen)
{
errno = ETIMEDOUT;
@@ -230,7 +246,8 @@
if (rc == len) { transport_count += len; return TRUE; }
- /* A non-negative return code is an incomplete write. Try again. */
+ /* A non-negative return code is an incomplete write. Try again for the rest
+ of the block. If we have exactly hit the timeout, give up. */
if (rc >= 0)
{
@@ -238,7 +255,7 @@
block += rc;
transport_count += rc;
DEBUG(D_transport) debug_printf("write incomplete (%d)\n", rc);
- continue;
+ goto CHECK_TIMEOUT; /* A few lines below */
}
/* A negative return code with an EINTR error is another form of
@@ -248,7 +265,7 @@
{
DEBUG(D_transport)
debug_printf("write interrupted before anything written\n");
- continue;
+ goto CHECK_TIMEOUT; /* A few lines below */
}
/* A response of EAGAIN from write() is likely only in the case of writing
@@ -259,6 +276,16 @@
DEBUG(D_transport)
debug_printf("write temporarily locked out, waiting 1 sec\n");
sleep(1);
+
+ /* Before continuing to try another write, check that we haven't run out of
+ time. */
+
+ CHECK_TIMEOUT:
+ if (transport_write_timeout > 0 && local_timeout <= 0)
+ {
+ errno = ETIMEDOUT;
+ return FALSE;
+ }
continue;
}
Index: 615
====================================================================
# Exim test configuration 615
# Macros are set externally in order to get the path
# of the Exim that is being tested, and the directory
# in which the test data lives.
exim_path = EXIM_PATH
primary_hostname = myhost.test.ex
spool_directory = DIR/spool
# ----- Main settings -----
acl_smtp_rcpt = accept
# ----- Routers -----
begin routers
r0:
driver = redirect
senders = :
data = /dev/null
user = CALLER
r1:
driver = accept
transport = t1
# ----- Transports -----
begin transports
t1:
driver = smtp
hosts = 127.0.0.1
port = 1225
allow_localhost
data_timeout = 1s
# ----- Retry -----
begin retry
* * F,1d,1h
# End
Index: 615
====================================================================
1999-03-02 09:44:33 10HmaX-0005vi-00 <= ph10@??? U=ph10 P=local-smtp S=1600260
1999-03-02 09:44:33 10HmaX-0005vi-00 SMTP timeout while connected to 127.0.0.1 [127.0.0.1] after sending data block (188349 bytes written): Connection timed out
1999-03-02 09:44:33 10HmaX-0005vi-00 == def@pqr R=r1 T=t1 defer (110): Connection timed out: SMTP timeout while connected to 127.0.0.1 [127.0.0.1] after sending data block (188349 bytes written)
Index: 615
====================================================================
0 Timeout while actually writing the data for a message
server 1225
220 Welcome
EHLO
250 Hi
MAIL FROM
250 OK
RCPT TO
250 OK
DATA
354 SEND
*sleep 3
****
0
write test-data 20000x80
mail from:<abc@xyz>
RCPT TO:<def@pqr>
DATA
++++
.
quit
****
0
exim -v -odi -bs <test-data
****
no_msglog_check
Index: 615
====================================================================
LOG: smtp_connection MAIN
SMTP connection from ph10
LOG: MAIN
<= ph10@??? U=ph10 P=local-smtp S=1600260
delivering 10HmaX-0005vi-00
Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
SMTP<< 220 Welcome
SMTP>> EHLO myhost.test.ex
SMTP<< 250 Hi
SMTP>> MAIL FROM:<ph10@???>
SMTP<< 250 OK
SMTP>> RCPT TO:<def@pqr>
SMTP<< 250 OK
SMTP>> DATA
SMTP<< 354 SEND
SMTP>> writing message and terminating "."
LOG: MAIN
SMTP timeout while connected to 127.0.0.1 [127.0.0.1] after sending data block (188349 bytes written): Connection timed out
LOG: MAIN
== def@pqr R=r1 T=t1 defer (110): Connection timed out: SMTP timeout while connected to 127.0.0.1 [127.0.0.1] after sending data block (188349 bytes written)
LOG: smtp_connection MAIN
SMTP connection from ph10 closed by QUIT
Index: 615
====================================================================
220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
250 OK
250 Accepted
354 Enter message, ending with "." on a line by itself
250 OK id=10HmaX-0005vi-00
221 myhost.test.ex closing connection
******** SERVER ********
Listening on port 1225 ...
Connection request from [127.0.0.1]
220 Welcome
EHLO myhost.test.ex
250 Hi
MAIL FROM:<ph10@???>
250 OK
RCPT TO:<def@pqr>
250 OK
DATA
354 SEND
*sleep 3
End of script