X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fdeliver.c;h=de552f4cc0931642af59e2c227b878aa51111714;hb=4783307727d83aee3cd8d746618dce5266188e0f;hp=b036a846afe4eef11968c9054e4b631d20567b83;hpb=c29da374ab4ea587c810bdc0395443d6b6164fea;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/deliver.c b/src/src/deliver.c index b036a846a..de552f4cc 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 - 2017 */ /* See the file NOTICE for conditions of use and distribution. */ /* The main code for delivering a message. */ @@ -80,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 * *************************************************/ @@ -3312,8 +3358,7 @@ 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 " SSIZE_T_FMT " of %d bytes (pipeheader) " "from transport process %d for transport %s", @@ -3349,8 +3394,7 @@ 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 " SSIZE_T_FMT " of " SIZE_T_FMT " bytes (pipedata) from transport process %d for transport %s", @@ -8508,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 */