-/* $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.16 2006/10/30 16:41:04 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2006 */
/* See the file NOTICE for conditions of use and distribution. */
/* General functions concerned with transportation, and generic options for all
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;
}
int wwritten = 0;
uschar *dk_signature = NULL;
- snprintf(CS dk_spool_name, 256, "%s/input/%s/%s-K",
+ (void)string_format(dk_spool_name, 256, "%s/input/%s/%s-K",
spool_directory, message_subdir, message_id);
dk_fd = Uopen(dk_spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE);
if (dk_fd < 0)
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
Old records should eventually get swept up by the exim_tidydb utility.
Arguments:
- hostlist list of hosts that this message could be sent to;
- the update_waiting flag is set if a host is to be noted
+ hostlist list of hosts that this message could be sent to
tpname name of the transport
Returns: nothing
if (dbm_file == NULL) return;
/* Scan the list of hosts for which this message is waiting, and ensure
-that the message id is in each host record for those that have the
-update_waiting flag set. */
+that the message id is in each host record. */
for (host = hostlist; host!= NULL; host = host->next)
{
uschar *s;
int i, host_length;
- /* Skip if the update_waiting flag is not set. */
-
- if (!host->update_waiting) continue;
-
/* Skip if this is the same host as we just processed; otherwise remember
the name for next time. */
automatic comparison. */
if ((pid = fork()) != 0) _exit(EXIT_SUCCESS);
- if (running_in_test_harness) millisleep(500);
+ if (running_in_test_harness) sleep(1);
/* Set up the calling arguments; use the standard function for the basics,
but we have a number of extras that may be added. */
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);