-/* $Cambridge: exim/src/src/transport.c,v 1.7 2005/03/22 16:44:04 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transport.c,v 1.12 2005/06/27 14:29:44 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
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;
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)
{
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
{
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
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;
}
uschar *dk_strict_result = expand_string(dk_strict);
if (dk_strict_result != NULL)
{
- if ( (strcmpic(dk_strict,"1") == 0) ||
- (strcmpic(dk_strict,"true") == 0) )
+ if ( (strcmpic(dk_strict,US"1") == 0) ||
+ (strcmpic(dk_strict,US"true") == 0) )
{
save_errno = errno;
rc = FALSE;
/* write the chunk */
DK_WRITE:
#ifdef SUPPORT_TLS
- if (tls_active == fd) wwritten = tls_write(p, sread); else
+ if (tls_active == fd) wwritten = tls_write(US p, sread); else
#endif
wwritten = write(fd,p,sread);
if (wwritten == -1)
CLEANUP:
/* unlink -K file */
- close(dk_fd);
+ (void)close(dk_fd);
Uunlink(dk_spool_name);
errno = save_errno;
return rc;
int pfd[2];
pid_t filter_pid, write_pid;
+transport_filter_timed_out = FALSE;
+
/* If there is no filter command set up, call the internal function that does
the actual work, passing it the incoming fd, and return its result. */
yield = FALSE;
write_pid = (pid_t)(-1);
-fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+(void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
filter_pid = child_open(transport_filter_argv, NULL, 077, &fd_write, &fd_read,
FALSE);
-fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC);
+(void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) & ~FD_CLOEXEC);
if (filter_pid < 0) goto TIDY_UP; /* errno set */
DEBUG(D_transport)
if ((write_pid = fork()) == 0)
{
BOOL rc;
- close(fd_read);
- close(pfd[pipe_read]);
+ (void)close(fd_read);
+ (void)close(pfd[pipe_read]);
nl_check_length = nl_escape_length = 0;
rc = internal_transport_write_message(addr, fd_write,
(options & ~(topt_use_crlf | topt_end_dot)),
size_limit, add_headers, remove_headers, NULL, NULL,
rewrite_rules, rewrite_existflags);
save_errno = errno;
- write(pfd[pipe_write], (void *)&rc, sizeof(BOOL));
- write(pfd[pipe_write], (void *)&save_errno, sizeof(int));
- write(pfd[pipe_write], (void *)&(addr->more_errno), sizeof(int));
+ (void)write(pfd[pipe_write], (void *)&rc, sizeof(BOOL));
+ (void)write(pfd[pipe_write], (void *)&save_errno, sizeof(int));
+ (void)write(pfd[pipe_write], (void *)&(addr->more_errno), sizeof(int));
_exit(0);
}
save_errno = errno;
/* Parent process: close our copy of the writing subprocess' pipes. */
-close(pfd[pipe_write]);
-close(fd_write);
+(void)close(pfd[pipe_write]);
+(void)close(fd_write);
fd_write = -1;
/* Writing process creation failed */
if (sigalrm_seen)
{
errno = ETIMEDOUT;
+ transport_filter_timed_out = TRUE;
goto TIDY_UP;
}
TIDY_UP:
save_errno = errno;
-close(fd_read);
-if (fd_write > 0) close(fd_write);
+(void)close(fd_read);
+if (fd_write > 0) (void)close(fd_write);
if (!yield)
{
if (rc == 0)
{
BOOL ok;
- read(pfd[pipe_read], (void *)&ok, sizeof(BOOL));
+ (void)read(pfd[pipe_read], (void *)&ok, sizeof(BOOL));
if (!ok)
{
- read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
- read(pfd[pipe_read], (void *)&(addr->more_errno), sizeof(int));
+ (void)read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
+ (void)read(pfd[pipe_read], (void *)&(addr->more_errno), sizeof(int));
yield = FALSE;
}
}
}
}
}
-close(pfd[pipe_read]);
+(void)close(pfd[pipe_read]);
/* If there have been no problems we can now add the terminating "." if this is
SMTP output, turning off escaping beforehand. If the last character from the
if (socket_fd != 0)
{
- dup2(socket_fd, 0);
- close(socket_fd);
+ (void)dup2(socket_fd, 0);
+ (void)close(socket_fd);
}
DEBUG(D_exec) debug_print_argv(argv);