X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fdeliver.c;h=c35f3fa5bbe19661d94fed49220dfdcf31b42034;hb=0e8aed8aab2d2b68d1f6e6b0b2985de2bd6d2a73;hp=0bd67d82345ce3d4387dd61cc785b9732fc7ca69;hpb=acec9514b1006e352ef283f205ecec75a9b6ff0d;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/deliver.c b/src/src/deliver.c index 0bd67d823..c35f3fa5b 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* The main code for delivering a message. */ @@ -10,6 +10,7 @@ #include "exim.h" #include "transports/smtp.h" +#include #include @@ -79,6 +80,52 @@ static uschar *used_return_path = NULL; +/************************************************* +* read as much as requested * +*************************************************/ + +/* The syscall read(2) doesn't always returns as much as we want. For +several reasons it might get less. (Not talking about signals, as syscalls +are restartable). When reading from a network or pipe connection the sender +might send in smaller chunks, with delays between these chunks. The read(2) +may return such a chunk. + +The more the writer writes and the smaller the pipe between write and read is, +the more we get the chance of reading leass than requested. (See bug 2130) + +This function read(2)s until we got all the data we *requested*. + +Note: This function may block. Use it only if you're sure about the +amount of data you will get. + +Argument: + fd the file descriptor to read from + buffer pointer to a buffer of size len + len the requested(!) amount of bytes + +Returns: the amount of bytes read +*/ +static ssize_t +readn(int fd, void * buffer, size_t len) +{ + void * next = buffer; + void * end = buffer + len; + + while (next < end) + { + ssize_t got = read(fd, next, end - next); + + /* I'm not sure if there are signals that can interrupt us, + for now I assume the worst */ + if (got == -1 && errno == EINTR) continue; + if (got <= 0) return next - buffer; + next += got; + } + + return len; +} + + /************************************************* * Make a new address item * *************************************************/ @@ -770,7 +817,7 @@ if (LOGGING(tls_certificate_verified) && addr->cipher) s = string_append(s, 2, US" CV=", testflag(addr, af_cert_verified) ? -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE testflag(addr, af_dane_verified) ? "dane" : @@ -983,10 +1030,8 @@ else and all parents are not being included, don't add on the top address. First of all, do a caseless comparison; if this succeeds, do a caseful comparison on the local parts. */ - /*XXX dodgy coding. the string at "cmp" might not be nul-terminated if - we had to extend the allocation! */ - g->s[g->ptr] = '\0'; + string_from_gstring(g); /* ensure nul-terminated */ if ( strcmpic(cmp, topaddr->address) == 0 && Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0 && !addr->onetime_parent @@ -1042,7 +1087,7 @@ if ((diff->tv_usec -= then->tv_usec) < 0) -static uschar * +uschar * string_timediff(struct timeval * diff) { static uschar buf[sizeof("0.000s")]; @@ -1508,7 +1553,7 @@ if (addr->return_file >= 0 && addr->return_filename) log_write(0, LOG_MAIN, "<%s>: %s transport output: %s", addr->address, tb->name, sp); } - (void)fclose(f); + (void)fclose(f); } /* Handle returning options, but only if there is an address to return @@ -1574,7 +1619,7 @@ if (result == OK) tls_out.cipher = addr->cipher; tls_out.peerdn = addr->peerdn; tls_out.ocsp = addr->ocsp; -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE tls_out.dane_verified = testflag(addr, af_dane_verified); # endif #endif @@ -1587,7 +1632,7 @@ if (result == OK) tls_out.cipher = NULL; tls_out.peerdn = NULL; tls_out.ocsp = OCSP_NOT_REQ; -# ifdef EXPERIMENTAL_DANE +# ifdef SUPPORT_DANE tls_out.dane_verified = FALSE; # endif #endif @@ -3311,14 +3356,13 @@ while (!done) If we get less, we can assume the subprocess do be done and do not expect any further information from it. */ - got = readn(fd, pipeheader, required); - if (got != required) + if ((got = readn(fd, pipeheader, required)) != required) { - msg = string_sprintf("got %d of %d bytes (pipeheader) " - "from transport process %d for transport %s", - got, PIPE_HEADER_SIZE, pid, addr->transport->driver_name); - done = TRUE; - break; + msg = string_sprintf("got " SSIZE_T_FMT " of %d bytes (pipeheader) " + "from transport process %d for transport %s", + got, PIPE_HEADER_SIZE, pid, addr->transport->driver_name); + done = TRUE; + break; } pipeheader[PIPE_HEADER_SIZE] = '\0'; @@ -3348,14 +3392,13 @@ while (!done) /* Same as above, the transport process will write the bytes announced in a timely manner, so we can just wait for the bytes, getting less than expected is considered a problem of the subprocess, we do not expect anything else from it. */ - got = readn(fd, big_buffer, required); - if (got != required) + if ((got = readn(fd, big_buffer, required)) != required) { - msg = string_sprintf("got only %d of %d bytes (pipedata) " - "from transport process %d for transport %s", - got, required, pid, addr->transport->driver_name); - done = TRUE; - break; + msg = string_sprintf("got only " SSIZE_T_FMT " of " SIZE_T_FMT + " bytes (pipedata) from transport process %d for transport %s", + got, required, pid, addr->transport->driver_name); + done = TRUE; + break; } /* Handle each possible type of item, assuming the complete item is @@ -4742,7 +4785,7 @@ all pipes, so I do not see a reason to use non-blocking IO here /* The certificate verification status goes into the flags */ if (tls_out.certificate_verified) setflag(addr, af_cert_verified); -#ifdef EXPERIMENTAL_DANE +#ifdef SUPPORT_DANE if (tls_out.dane_verified) setflag(addr, af_dane_verified); #endif @@ -4945,7 +4988,7 @@ all pipes, so I do not see a reason to use non-blocking IO here if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) { #ifdef SUPPORT_TLS - tls_close(FALSE, FALSE); + tls_close(FALSE, TLS_NO_SHUTDOWN); #endif (void) close(cutthrough.fd); release_cutthrough_connection(US"passed to transport proc"); @@ -6107,7 +6150,7 @@ if (process_recipients != RECIP_IGNORE) new->dsn_flags = r->dsn_flags & rf_dsnflags; new->dsn_orcpt = r->orcpt; DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n", - new->dsn_orcpt, new->dsn_flags); + new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags); switch (process_recipients) { @@ -7176,11 +7219,12 @@ for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next) "DSN: envid: %s ret: %d\n" "DSN: Final recipient: %s\n" "DSN: Remote SMTP server supports DSN: %d\n", - addr_dsntmp->router->name, + addr_dsntmp->router ? addr_dsntmp->router->name : US"(unknown)", addr_dsntmp->address, sender_address, - addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags, - dsn_envid, dsn_ret, + addr_dsntmp->dsn_orcpt ? addr_dsntmp->dsn_orcpt : US"NULL", + addr_dsntmp->dsn_flags, + dsn_envid ? dsn_envid : US"NULL", dsn_ret, addr_dsntmp->address, addr_dsntmp->dsn_aware ); @@ -7676,9 +7720,10 @@ wording. */ addr->address); if ((hu = addr->host_used) && hu->name) { - const uschar * s; fprintf(f, "Remote-MTA: dns; %s\n", hu->name); #ifdef EXPERIMENTAL_DSN_INFO + { + const uschar * s; if (hu->address) { uschar * p = hu->port == 25 @@ -7691,6 +7736,7 @@ wording. */ fprintf(f, "X-Remote-MTA-helo-response: X-str; %s\n", s); if ((s = addr->message) && *s) fprintf(f, "X-Exim-Diagnostic: X-str; %s\n", s); + } #endif print_dsn_diagnostic_code(addr, f); } @@ -7889,8 +7935,7 @@ if (!addr_defer) /* Log the end of this message, with queue time if requested. */ if (LOGGING(queue_time_overall)) - log_write(0, LOG_MAIN, "Completed QT=%s", - string_timesince(&received_time)); + log_write(0, LOG_MAIN, "Completed QT=%s", string_timesince(&received_time)); else log_write(0, LOG_MAIN, "Completed"); @@ -8507,13 +8552,12 @@ if (cutthrough.fd >= 0 && cutthrough.callout_hold_only) else if (pid == 0) /* child: fork again to totally disconnect */ { - close(pfd[1]); - if ((pid = fork())) - _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS); - smtp_proxy_tls(big_buffer, big_buffer_size, pfd[0], 5*60); - exim_exit(0); + if (running_in_test_harness) millisleep(100); /* let parent debug out */ + /* does not return */ + smtp_proxy_tls(big_buffer, big_buffer_size, pfd, 5*60); } + DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid); close(pfd[0]); waitpid(pid, NULL, 0); (void) close(channel_fd); /* release the client socket */