git://git.exim.org
/
exim.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Use writev(2) when sending delivery status to the parent
[exim.git]
/
src
/
src
/
deliver.c
diff --git
a/src/src/deliver.c
b/src/src/deliver.c
index 2713cc56ffb3bddfa64677c0bf6cb872057db7ef..94dabab02a6eaed5188b1b9ffa5d04b72734a199 100644
(file)
--- a/
src/src/deliver.c
+++ b/
src/src/deliver.c
@@
-752,7
+752,12
@@
if (LOGGING(proxy) && proxy_local_address)
}
#endif
}
#endif
-return d_log_interface(s, sp, pp);
+s = d_log_interface(s, sp, pp);
+
+if (testflag(addr, af_tcp_fastopen))
+ s = string_catn(s, sp, pp, US" TFO", 4);
+
+return s;
}
}
@@
-843,7
+848,7
@@
deliver_host = addr->host_used ? addr->host_used->name : NULL;
addr->host_used
|| Ustrcmp(addr->transport->driver_name, "smtp") == 0
|| Ustrcmp(addr->transport->driver_name, "lmtp") == 0
addr->host_used
|| Ustrcmp(addr->transport->driver_name, "smtp") == 0
|| Ustrcmp(addr->transport->driver_name, "lmtp") == 0
- ? addr->message : NULL);
+ ? addr->message : NULL);
deliver_host_port = save_port;
deliver_host_address = save_address;
deliver_host_port = save_port;
deliver_host_address = save_address;
@@
-1058,7
+1063,7
@@
return buf;
}
}
-
static
uschar *
+uschar *
string_timesince(struct timeval * then)
{
struct timeval diff;
string_timesince(struct timeval * then)
{
struct timeval diff;
@@
-1195,11
+1200,11
@@
else
}
#ifndef DISABLE_PRDR
}
#ifndef DISABLE_PRDR
- if (
addr->flags & af_prdr_used
)
+ if (
testflag(addr, af_prdr_used)
)
s = string_catn(s, &size, &ptr, US" PRDR", 5);
#endif
s = string_catn(s, &size, &ptr, US" PRDR", 5);
#endif
- if (
addr->flags & af_chunking_used
)
+ if (
testflag(addr, af_chunking_used)
)
s = string_catn(s, &size, &ptr, US" K", 2);
}
s = string_catn(s, &size, &ptr, US" K", 2);
}
@@
-1233,7
+1238,7
@@
if (LOGGING(queue_time))
if (LOGGING(deliver_time))
{
if (LOGGING(deliver_time))
{
- struct timeval diff = {
addr->more_errno,
addr->delivery_usec};
+ struct timeval diff = {
.tv_sec = addr->more_errno, .tv_usec =
addr->delivery_usec};
s = string_append(s, &size, &ptr, 2, US" DT=", string_timediff(&diff));
}
s = string_append(s, &size, &ptr, 2, US" DT=", string_timediff(&diff));
}
@@
-1657,7
+1662,7
@@
else
later (with a log entry). */
if (!*sender_address && message_age >= ignore_bounce_errors_after)
later (with a log entry). */
if (!*sender_address && message_age >= ignore_bounce_errors_after)
-
setflag(addr, af_ignore_error)
;
+
addr->prop.ignore_error = TRUE
;
/* Freeze the message if requested, or if this is a bounce message (or other
message with null sender) and this address does not have its own errors
/* Freeze the message if requested, or if this is a bounce message (or other
message with null sender) and this address does not have its own errors
@@
-1665,7
+1670,7
@@
else
to ignore occurs later, instead of sending a message. Logging of freezing
occurs later, just before writing the -H file. */
to ignore occurs later, instead of sending a message. Logging of freezing
occurs later, just before writing the -H file. */
- if ( !
testflag(addr, af_ignore_error)
+ if ( !
addr->prop.ignore_error
&& ( addr->special_action == SPECIAL_FREEZE
|| (sender_address[0] == 0 && !addr->prop.errors_address)
) )
&& ( addr->special_action == SPECIAL_FREEZE
|| (sender_address[0] == 0 && !addr->prop.errors_address)
) )
@@
-2216,7
+2221,7
@@
if ( !shadowing
addr->return_filename =
spool_fname(US"msglog", message_subdir, message_id,
string_sprintf("-%d-%d", getpid(), return_count++));
addr->return_filename =
spool_fname(US"msglog", message_subdir, message_id,
string_sprintf("-%d-%d", getpid(), return_count++));
-
+
if ((addr->return_file = open_msglog_file(addr->return_filename, 0400, &error)) < 0)
{
common_error(TRUE, addr, errno, US"Unable to %s file for %s transport "
if ((addr->return_file = open_msglog_file(addr->return_filename, 0400, &error)) < 0)
{
common_error(TRUE, addr, errno, US"Unable to %s file for %s transport "
@@
-2777,7
+2782,8
@@
while (addr_local)
BOOL ok =
tp == next->transport
&& !previously_transported(next, TRUE)
BOOL ok =
tp == next->transport
&& !previously_transported(next, TRUE)
- && (addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file))
+ && testflag(addr, af_pfr) == testflag(next, af_pfr)
+ && testflag(addr, af_file) == testflag(next, af_file)
&& (!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0)
&& (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0)
&& same_strings(next->prop.errors_address, addr->prop.errors_address)
&& (!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0)
&& (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0)
&& same_strings(next->prop.errors_address, addr->prop.errors_address)
@@
-3302,7
+3308,12
@@
Each separate item is written to the pipe in a single write(), and as they are
all short items, the writes will all be atomic and we should never find
ourselves in the position of having read an incomplete item. "Short" in this
case can mean up to about 1K in the case when there is a long error message
all short items, the writes will all be atomic and we should never find
ourselves in the position of having read an incomplete item. "Short" in this
case can mean up to about 1K in the case when there is a long error message
-associated with an address. */
+associated with an address.
+
+write(3) [Linux] says that atomic writes are not interleaved with each other.
+Not more.
+
+*/
DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
(int)p->pid, eop? "ended" : "not ended");
DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
(int)p->pid, eop? "ended" : "not ended");
@@
-3551,12
+3562,16
@@
while (!done)
#ifndef DISABLE_PRDR
case 'P':
#ifndef DISABLE_PRDR
case 'P':
-
addr->flags |= af_prdr_used
;
+
setflag(addr, af_prdr_used)
;
break;
#endif
case 'K':
break;
#endif
case 'K':
- addr->flags |= af_chunking_used;
+ setflag(addr, af_chunking_used);
+ break;
+
+ case 'T':
+ setflag(addr, af_tcp_fastopen);
break;
case 'D':
break;
case 'D':
@@
-3978,7
+3993,6
@@
for (;;) /* Normally we do not repeat this loop */
{
readycount--;
if (par_read_pipe(poffset, FALSE)) /* Finished with this pipe */
{
readycount--;
if (par_read_pipe(poffset, FALSE)) /* Finished with this pipe */
- {
for (;;) /* Loop for signals */
{
pid_t endedpid = waitpid(pid, &status, 0);
for (;;) /* Loop for signals */
{
pid_t endedpid = waitpid(pid, &status, 0);
@@
-3988,7
+4002,6
@@
for (;;) /* Normally we do not repeat this loop */
"%d (errno = %d) from waitpid() for process %d",
(int)endedpid, errno, (int)pid);
}
"%d (errno = %d) from waitpid() for process %d",
(int)endedpid, errno, (int)pid);
}
- }
}
}
}
}
@@
-4122,44
+4135,43
@@
while (parcount > max)
-
static void
rmt_dlv_checked_write(int fd, char id, char subid, void * buf, int size)
{
static void
rmt_dlv_checked_write(int fd, char id, char subid, void * buf, int size)
{
-uschar writebuffer[PIPE_HEADER_SIZE + BIG_BUFFER_SIZE];
-int header_length;
+uschar pipe_header[PIPE_HEADER_SIZE+1];
+size_t total_len = PIPE_HEADER_SIZE + size;
+
+struct iovec iov[2] = {
+ { pipe_header, PIPE_HEADER_SIZE }, /* indication about the data to expect */
+ { buf, size } /* *the* data */
+};
+
int ret;
/* we assume that size can't get larger then BIG_BUFFER_SIZE which currently is set to 16k */
/* complain to log if someone tries with buffer sizes we can't handle*/
int ret;
/* we assume that size can't get larger then BIG_BUFFER_SIZE which currently is set to 16k */
/* complain to log if someone tries with buffer sizes we can't handle*/
-if (size >
99999
)
+if (size >
BIG_BUFFER_SIZE-1
)
{
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
{
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
- "Failed writing transport result to pipe: can't handle buffers > 99999 bytes. truncating!\n");
- size = 99999;
+ "Failed writing transport result to pipe: can't handle buffers > %d bytes. truncating!\n",
+ BIG_BUFFER_SIZE-1);
+ size = BIG_BUFFER_SIZE;
}
}
-/*
to keep the write() atomic we build header in writebuffer and copy buf behind */
-
/* two write() calls would increase the complexity of reading from pipe
*/
+/*
Should we check that we do not write more than PIPE_BUF? What whould
+
that help?
*/
/* convert size to human readable string prepended by id and subid */
/* convert size to human readable string prepended by id and subid */
-header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
-if (header_length != PIPE_HEADER_SIZE)
- {
+if (PIPE_HEADER_SIZE != snprintf(CS pipe_header, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
- writebuffer[0] = '\0';
- }
DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%d,final:%s\n",
DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%d,final:%s\n",
- id, subid, size, writebuffer);
-
-if (buf && size > 0)
- memcpy(writebuffer + PIPE_HEADER_SIZE, buf, size);
+ id, subid, size, pipe_header);
-size += PIPE_HEADER_SIZE;
-if ((ret = write(fd, writebuffer, size)) != size)
-
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe: %s\n"
,
+if ((ret = writev(fd, iov, 2)) != total_len)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe (%d of %d bytes): %s",
+
ret == -1 ? 0 : ret, total_len
,
ret == -1 ? strerror(errno) : "short write");
}
ret == -1 ? strerror(errno) : "short write");
}
@@
-4607,11
+4619,15
@@
for (delivery_count = 0; addr_remote; delivery_count++)
that it can use either of them, though it prefers O_NONBLOCK, which
distinguishes between EOF and no-more-data. */
that it can use either of them, though it prefers O_NONBLOCK, which
distinguishes between EOF and no-more-data. */
+/* The data appears in a timely manner and we already did a select on
+all pipes, so I do not see a reason to use non-blocking IO here
+
#ifdef O_NONBLOCK
(void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK);
#else
(void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY);
#endif
#ifdef O_NONBLOCK
(void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK);
#else
(void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY);
#endif
+*/
/* If the maximum number of subprocesses already exist, wait for a process
to finish. If we ran out of file descriptors, parmax will have been reduced
/* If the maximum number of subprocesses already exist, wait for a process
to finish. If we ran out of file descriptors, parmax will have been reduced
@@
-4848,13
+4864,16
@@
for (delivery_count = 0; addr_remote; delivery_count++)
}
#ifndef DISABLE_PRDR
}
#ifndef DISABLE_PRDR
- if (
addr->flags & af_prdr_used
)
+ if (
testflag(addr, af_prdr_used)
)
rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
#endif
rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
#endif
- if (
addr->flags & af_chunking_used
)
+ if (
testflag(addr, af_chunking_used)
)
rmt_dlv_checked_write(fd, 'K', '0', NULL, 0);
rmt_dlv_checked_write(fd, 'K', '0', NULL, 0);
+ if (testflag(addr, af_tcp_fastopen))
+ rmt_dlv_checked_write(fd, 'T', '0', NULL, 0);
+
memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
@@
-6013,11
+6032,11
@@
else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
uschar *type;
p->uid = uid;
p->gid = gid;
uschar *type;
p->uid = uid;
p->gid = gid;
- setflag(p, af_uid_set
|
- af_gid_set |
- af_allow_file |
- af_allow_pipe |
-
af_allow_reply);
+ setflag(p, af_uid_set
);
+ setflag(p, af_gid_set);
+ setflag(p, af_allow_file);
+ setflag(p, af_allow_pipe);
+
setflag(p,
af_allow_reply);
/* Find the name of the system filter's appropriate pfr transport */
/* Find the name of the system filter's appropriate pfr transport */
@@
-6336,8
+6355,8
@@
while (addr_new) /* Loop until all addresses dealt with */
addr->local_part = addr->address;
addr->message =
US"filter autoreply generated syntactically invalid recipient";
addr->local_part = addr->address;
addr->message =
US"filter autoreply generated syntactically invalid recipient";
-
setflag(addr, af_ignore_error)
;
- (void)post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
+
addr->prop.ignore_error = TRUE
;
+ (void)
post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
continue; /* with the next new address */
}
continue; /* with the next new address */
}
@@
-6831,15
+6850,14
@@
while (addr_new) /* Loop until all addresses dealt with */
addr2->host_list = addr->host_list;
addr2->fallback_hosts = addr->fallback_hosts;
addr2->prop.errors_address = addr->prop.errors_address;
addr2->host_list = addr->host_list;
addr2->fallback_hosts = addr->fallback_hosts;
addr2->prop.errors_address = addr->prop.errors_address;
- copyflag(addr2, addr, af_hide_child | af_local_host_removed);
+ copyflag(addr2, addr, af_hide_child);
+ copyflag(addr2, addr, af_local_host_removed);
DEBUG(D_deliver|D_route)
DEBUG(D_deliver|D_route)
- {
debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
"routing %s\n"
"Routing for %s copied from %s\n",
addr2->address, addr2->address, addr->address);
debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
"routing %s\n"
"Routing for %s copied from %s\n",
addr2->address, addr2->address, addr->address);
- }
}
}
} /* Continue with routing the next address. */
}
}
} /* Continue with routing the next address. */
@@
-7001,7
+7019,7
@@
if (addr_local || addr_remote)
if (journal_fd < 0)
{
uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
if (journal_fd < 0)
{
uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
-
+
if ((journal_fd = Uopen(fname,
#ifdef O_CLOEXEC
O_CLOEXEC |
if ((journal_fd = Uopen(fname,
#ifdef O_CLOEXEC
O_CLOEXEC |
@@
-7266,7
+7284,7
@@
if (addr_senddsn)
FILE *f = fdopen(fd, "wb");
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
uschar * bound;
FILE *f = fdopen(fd, "wb");
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
uschar * bound;
- transport_ctx tctx = {
0
};
+ transport_ctx tctx = {
{0}
};
DEBUG(D_deliver)
debug_printf("sending error message to: %s\n", sender_address);
DEBUG(D_deliver)
debug_printf("sending error message to: %s\n", sender_address);
@@
-7404,19
+7422,18
@@
while (addr_failed)
if (sender_address[0] == 0 && !addr_failed->prop.errors_address)
{
if ( !testflag(addr_failed, af_retry_timedout)
if (sender_address[0] == 0 && !addr_failed->prop.errors_address)
{
if ( !testflag(addr_failed, af_retry_timedout)
- && !testflag(addr_failed, af_ignore_error))
- {
+ && !addr_failed->prop.ignore_error)
log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
"failure is neither frozen nor ignored (it's been ignored)");
log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
"failure is neither frozen nor ignored (it's been ignored)");
- }
-
setflag(addr_failed, af_ignore_error)
;
+
+
addr_failed->prop.ignore_error = TRUE
;
}
/* If the first address on the list has af_ignore_error set, just remove
it from the list, throw away any saved message file, log it, and
mark the recipient done. */
}
/* If the first address on the list has af_ignore_error set, just remove
it from the list, throw away any saved message file, log it, and
mark the recipient done. */
- if (
testflag(addr_failed, af_ignore_error)
+ if (
addr_failed->prop.ignore_error
|| ( addr_failed->dsn_flags & rf_dsnflags
&& (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure
) )
|| ( addr_failed->dsn_flags & rf_dsnflags
&& (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure
) )
@@
-7804,7
+7821,7
@@
wording. */
transport_filter_argv = NULL; /* Just in case */
return_path = sender_address; /* In case not previously set */
{ /* Dummy transport for headers add */
transport_filter_argv = NULL; /* Just in case */
return_path = sender_address; /* In case not previously set */
{ /* Dummy transport for headers add */
- transport_ctx tctx = {
0
};
+ transport_ctx tctx = {
{0}
};
transport_instance tb = {0};
tctx.u.fd = fileno(f);
transport_instance tb = {0};
tctx.u.fd = fileno(f);
@@
-8126,7
+8143,7
@@
else if (addr_defer != (address_item *)(+1))
FILE *wmf = NULL;
FILE *f = fdopen(fd, "wb");
uschar * bound;
FILE *wmf = NULL;
FILE *f = fdopen(fd, "wb");
uschar * bound;
- transport_ctx tctx = {
0
};
+ transport_ctx tctx = {
{0}
};
if (warn_message_file)
if (!(wmf = Ufopen(warn_message_file, "rb")))
if (warn_message_file)
if (!(wmf = Ufopen(warn_message_file, "rb")))
@@
-8514,7
+8531,7
@@
return new_sender_address;
void
delivery_re_exec(int exec_type)
{
void
delivery_re_exec(int exec_type)
{
-uschar *
s
;
+uschar *
where
;
if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
{
if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
{
@@
-8530,15
+8547,15
@@
if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
sending_ip_address = cutthrough.snd_ip;
sending_port = cutthrough.snd_port;
sending_ip_address = cutthrough.snd_ip;
sending_port = cutthrough.snd_port;
-
s
= US"socketpair";
+
where
= US"socketpair";
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0)
goto fail;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0)
goto fail;
-
s
= US"fork";
+
where
= US"fork";
if ((pid = fork()) < 0)
goto fail;
if ((pid = fork()) < 0)
goto fail;
- else if (pid == 0) /* child: fork again to totally d
o
sconnect */
+ else if (pid == 0) /* child: fork again to totally d
i
sconnect */
{
close(pfd[1]);
if ((pid = fork()))
{
close(pfd[1]);
if ((pid = fork()))
@@
-8562,12
+8579,12
@@
else
cancel_cutthrough_connection(TRUE, US"non-continued delivery");
(void) child_exec_exim(exec_type, FALSE, NULL, FALSE, 2, US"-Mc", message_id);
}
cancel_cutthrough_connection(TRUE, US"non-continued delivery");
(void) child_exec_exim(exec_type, FALSE, NULL, FALSE, 2, US"-Mc", message_id);
}
-
/* Control does not return
here. */
+
return; /* compiler quietening; control does not reach
here. */
fail:
log_write(0,
LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
fail:
log_write(0,
LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
- "delivery re-exec
failed: %s"
, strerror(errno));
+ "delivery re-exec
%s failed: %s", where
, strerror(errno));
/* Get here if exec_type == CEE_EXEC_EXIT.
Note: this must be _exit(), not exit(). */
/* Get here if exec_type == CEE_EXEC_EXIT.
Note: this must be _exit(), not exit(). */