X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Ftransport.c;h=02994d2ca2981a20530068bf08f6a8bc766ea969;hb=258dfd012173250b20520c8fb24329eb8998970a;hp=ce02adbf2b60e77915bc03f422af5444ccec6d42;hpb=f3ebb786e451da973560f1c9d8cdb151d25108b5;p=exim.git diff --git a/src/src/transport.c b/src/src/transport.c index ce02adbf2..02994d2ca 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -15,75 +15,76 @@ transports. */ data blocks and which therefore have the opt_public flag set. Note that there are other options living inside this structure which can be set only from certain transports. */ +#define LOFF(field) OPT_OFF(transport_instance, field) optionlist optionlist_transports[] = { /* name type value */ { "*expand_group", opt_stringptr|opt_hidden|opt_public, - (void *)offsetof(transport_instance, expand_gid) }, + LOFF(expand_gid) }, { "*expand_user", opt_stringptr|opt_hidden|opt_public, - (void *)offsetof(transport_instance, expand_uid) }, + LOFF(expand_uid) }, { "*headers_rewrite_flags", opt_int|opt_public|opt_hidden, - (void *)offsetof(transport_instance, rewrite_existflags) }, + LOFF(rewrite_existflags) }, { "*headers_rewrite_rules", opt_void|opt_public|opt_hidden, - (void *)offsetof(transport_instance, rewrite_rules) }, + LOFF(rewrite_rules) }, { "*set_group", opt_bool|opt_hidden|opt_public, - (void *)offsetof(transport_instance, gid_set) }, + LOFF(gid_set) }, { "*set_user", opt_bool|opt_hidden|opt_public, - (void *)offsetof(transport_instance, uid_set) }, + LOFF(uid_set) }, { "body_only", opt_bool|opt_public, - (void *)offsetof(transport_instance, body_only) }, + LOFF(body_only) }, { "current_directory", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, current_dir) }, + LOFF(current_dir) }, { "debug_print", opt_stringptr | opt_public, - (void *)offsetof(transport_instance, debug_string) }, + LOFF(debug_string) }, { "delivery_date_add", opt_bool|opt_public, - (void *)(offsetof(transport_instance, delivery_date_add)) }, + LOFF(delivery_date_add) }, { "disable_logging", opt_bool|opt_public, - (void *)(offsetof(transport_instance, disable_logging)) }, + LOFF(disable_logging) }, { "driver", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, driver_name) }, + LOFF(driver_name) }, { "envelope_to_add", opt_bool|opt_public, - (void *)(offsetof(transport_instance, envelope_to_add)) }, + LOFF(envelope_to_add) }, #ifndef DISABLE_EVENT { "event_action", opt_stringptr | opt_public, - (void *)offsetof(transport_instance, event_action) }, + LOFF(event_action) }, #endif { "group", opt_expand_gid|opt_public, - (void *)offsetof(transport_instance, gid) }, + LOFF(gid) }, { "headers_add", opt_stringptr|opt_public|opt_rep_str, - (void *)offsetof(transport_instance, add_headers) }, + LOFF(add_headers) }, { "headers_only", opt_bool|opt_public, - (void *)offsetof(transport_instance, headers_only) }, + LOFF(headers_only) }, { "headers_remove", opt_stringptr|opt_public|opt_rep_str, - (void *)offsetof(transport_instance, remove_headers) }, + LOFF(remove_headers) }, { "headers_rewrite", opt_rewrite|opt_public, - (void *)offsetof(transport_instance, headers_rewrite) }, + LOFF(headers_rewrite) }, { "home_directory", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, home_dir) }, + LOFF(home_dir) }, { "initgroups", opt_bool|opt_public, - (void *)offsetof(transport_instance, initgroups) }, + LOFF(initgroups) }, { "max_parallel", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, max_parallel) }, + LOFF(max_parallel) }, { "message_size_limit", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, message_size_limit) }, + LOFF(message_size_limit) }, { "rcpt_include_affixes", opt_bool|opt_public, - (void *)offsetof(transport_instance, rcpt_include_affixes) }, + LOFF(rcpt_include_affixes) }, { "retry_use_local_part", opt_bool|opt_public, - (void *)offsetof(transport_instance, retry_use_local_part) }, + LOFF(retry_use_local_part) }, { "return_path", opt_stringptr|opt_public, - (void *)(offsetof(transport_instance, return_path)) }, + LOFF(return_path) }, { "return_path_add", opt_bool|opt_public, - (void *)(offsetof(transport_instance, return_path_add)) }, + LOFF(return_path_add) }, { "shadow_condition", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, shadow_condition) }, + LOFF(shadow_condition) }, { "shadow_transport", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, shadow) }, + LOFF(shadow) }, { "transport_filter", opt_stringptr|opt_public, - (void *)offsetof(transport_instance, filter_command) }, + LOFF(filter_command) }, { "transport_filter_timeout", opt_time|opt_public, - (void *)offsetof(transport_instance, filter_timeout) }, + LOFF(filter_timeout) }, { "user", opt_expand_uid|opt_public, - (void *)offsetof(transport_instance, uid) } + LOFF(uid) } }; int optionlist_transports_size = nelem(optionlist_transports); @@ -172,6 +173,20 @@ for (transport_instance * t = transports; t; t = t->next) * Write block of data * *************************************************/ +static int +tpt_write(int fd, uschar * block, int len, BOOL more, int options) +{ +return +#ifndef DISABLE_TLS + tls_out.active.sock == fd + ? tls_write(tls_out.active.tls_ctx, block, len, more) : +#endif +#ifdef MSG_MORE + more && !(options & topt_not_socket) ? send(fd, block, len, MSG_MORE) : +#endif + write(fd, block, len); +} + /* Subroutine called by write_chunk() and at the end of the message actually to write a data block. Also called directly by some transports to write additional data to the file descriptor (e.g. prefix, suffix). @@ -215,10 +230,11 @@ Returns: TRUE on success, FALSE on failure (with errno preserved); */ static BOOL -transport_write_block_fd(transport_ctx * tctx, uschar *block, int len, BOOL more) +transport_write_block_fd(transport_ctx * tctx, uschar * block, int len, BOOL more) { int rc, save_errno; int local_timeout = transport_write_timeout; +int connretry = 1; int fd = tctx->u.fd; /* This loop is for handling incomplete writes and other retries. In most @@ -230,48 +246,42 @@ for (int i = 0; i < 100; i++) debug_printf("writing data block fd=%d size=%d timeout=%d%s\n", fd, len, local_timeout, more ? " (more expected)" : ""); - /* 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. */ + /* When doing TCP Fast Open we may get this far before the 3-way handshake + is complete, and write returns ENOTCONN. Detect that, wait for the socket + to become writable, and retry once only. */ - if (transport_write_timeout <= 0) /* No timeout wanted */ + for(;;) { - rc = -#ifndef DISABLE_TLS - tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) : -#endif -#ifdef MSG_MORE - more && !(tctx->options & topt_not_socket) - ? send(fd, block, len, MSG_MORE) : -#endif - write(fd, block, len); - save_errno = errno; - } - - /* Timeout wanted. */ + fd_set fds; + /* 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. */ - else - { - ALARM(local_timeout); - - rc = -#ifndef DISABLE_TLS - tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) : -#endif -#ifdef MSG_MORE - more && !(tctx->options & topt_not_socket) - ? send(fd, block, len, MSG_MORE) : -#endif - write(fd, block, len); - - save_errno = errno; - local_timeout = ALARM_CLR(0); - if (sigalrm_seen) + if (transport_write_timeout <= 0) /* No timeout wanted */ { - errno = ETIMEDOUT; - return FALSE; + rc = tpt_write(fd, block, len, more, tctx->options); + save_errno = errno; + } + else /* Timeout wanted. */ + { + ALARM(local_timeout); + rc = tpt_write(fd, block, len, more, tctx->options); + save_errno = errno; + local_timeout = ALARM_CLR(0); + if (sigalrm_seen) + { + errno = ETIMEDOUT; + return FALSE; + } } + + if (rc >= 0 || errno != ENOTCONN || connretry <= 0) + break; + + FD_ZERO(&fds); FD_SET(fd, &fds); + select(fd+1, NULL, &fds, NULL, NULL); /* could set timout? */ + connretry--; } /* Hopefully, the most common case is success, so test that first. */ @@ -728,10 +738,17 @@ for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old) return FALSE; } len = s ? Ustrlen(s) : 0; - if (strncmpic(h->text, s, len) != 0) continue; - ss = h->text + len; - while (*ss == ' ' || *ss == '\t') ss++; - if (*ss == ':') break; + if (len && s[len-1] == '*') /* trailing glob */ + { + if (strncmpic(h->text, s, len-1) == 0) break; + } + else + { + if (strncmpic(h->text, s, len) != 0) continue; + ss = h->text + len; + while (*ss == ' ' || *ss == '\t') ss++; + if (*ss == ':') break; + } } if (s) { include_header = FALSE; break; } } @@ -1251,8 +1268,8 @@ if ((write_pid = fork()) == 0) != sizeof(int) || write(pfd[pipe_write], (void *)&tctx->addr->more_errno, sizeof(int)) != sizeof(int) - || write(pfd[pipe_write], (void *)&tctx->addr->delivery_usec, sizeof(int)) - != sizeof(int) + || write(pfd[pipe_write], (void *)&tctx->addr->delivery_time, sizeof(struct timeval)) + != sizeof(struct timeval) ) rc = FALSE; /* compiler quietening */ exim_underbar_exit(0); @@ -1275,7 +1292,7 @@ if (write_pid < 0) /* When testing, let the subprocess get going */ -if (f.running_in_test_harness) millisleep(250); +testharness_pause_ms(250); DEBUG(D_transport) debug_printf("process %d writing to transport filter\n", (int)write_pid); @@ -1378,7 +1395,7 @@ if (write_pid > 0) { int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int)); dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int)); - dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_usec, sizeof(int)); + dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_time, sizeof(struct timeval)); dummy = dummy; /* compiler quietening */ yield = FALSE; } @@ -1722,16 +1739,14 @@ while (1) for (i = msgq_count - 1; i >= 0; --i) if (msgq[i].bKeep) { uschar subdir[2]; + uschar * mid = msgq[i].message_id; - subdir[0] = split_spool_directory ? msgq[i].message_id[5] : 0; - subdir[1] = 0; - - if (Ustat(spool_fname(US"input", subdir, msgq[i].message_id, US"-D"), - &statbuf) != 0) + set_subdir_str(subdir, mid, 0); + if (Ustat(spool_fname(US"input", subdir, mid, US"-D"), &statbuf) != 0) msgq[i].bKeep = FALSE; - else if (!oicf_func || oicf_func(msgq[i].message_id, oicf_data)) + else if (!oicf_func || oicf_func(mid, oicf_data)) { - Ustrcpy_nt(new_message_id, msgq[i].message_id); + Ustrcpy_nt(new_message_id, mid); msgq[i].bKeep = FALSE; bFound = TRUE; break; @@ -1946,7 +1961,7 @@ if ((pid = fork()) == 0) DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid); _exit(EXIT_SUCCESS); } - if (f.running_in_test_harness) sleep(1); + testharness_pause_ms(1000); transport_do_pass_socket(transport_name, hostname, hostaddress, id, socket_fd);