Don't complain about a socket EOF unless it affects a read.
authorWayne Davison <wayned@samba.org>
Sun, 15 Nov 2009 20:49:09 +0000 (12:49 -0800)
committerWayne Davison <wayned@samba.org>
Sun, 15 Nov 2009 20:54:55 +0000 (12:54 -0800)
Make sure a write error drains any messages in the input buffer.

cleanup.c
io.c

index 5d0b92f..ae185d4 100644 (file)
--- a/cleanup.c
+++ b/cleanup.c
@@ -214,7 +214,7 @@ NORETURN void _exit_cleanup(int code, const char *file, int line)
 #include "case_N.h"
 
                if (exit_code && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1
-                && (protocol_version >= 31 || am_server || (!am_sender && !am_generator))) {
+                && (protocol_version >= 31 || (!am_sender && !am_generator))) {
                        if (line > 0)
                                send_msg_int(MSG_ERROR_EXIT, exit_code);
                        noop_io_until_death();
diff --git a/io.c b/io.c
index 08afdd9..679b564 100644 (file)
--- a/io.c
+++ b/io.c
@@ -136,6 +136,7 @@ enum festatus { FES_SUCCESS, FES_REDO, FES_NO_SEND };
 
 static flist_ndx_list redo_list, hlink_list;
 
+static void drain_multiplex_messages(void);
 static void sleep_for_bwlimit(int bytes_written);
 
 static void check_timeout(void)
@@ -173,9 +174,9 @@ static void check_timeout(void)
  * There is another case for older protocol versions (< 24) where the module
  * listing was not terminated, so we must ignore an EOF error in that case and
  * exit.  In this situation, kluge_around_eof will be > 0. */
-static NORETURN void whine_about_eof(int fd)
+static NORETURN void whine_about_eof(BOOL allow_kluge)
 {
-       if (kluge_around_eof && fd == sock_f_in) {
+       if (kluge_around_eof && allow_kluge) {
                int i;
                if (kluge_around_eof > 0)
                        exit_cleanup(0);
@@ -661,11 +662,19 @@ static char *perform_io(size_t needed, int flags)
                if (max_fd < 0) {
                        switch (flags & PIO_NEED_FLAGS) {
                        case PIO_NEED_INPUT:
+                               iobuf.in.len = 0;
+                               if (kluge_around_eof == 2)
+                                       exit_cleanup(0);
+                               if (iobuf.in_fd == -2)
+                                       whine_about_eof(True);
                                rprintf(FERROR, "error in perform_io: no fd for input.\n");
                                exit_cleanup(RERR_PROTOCOL);
                        case PIO_NEED_OUTROOM:
                        case PIO_NEED_MSGROOM:
                                msgs2stderr = 1;
+                               drain_multiplex_messages();
+                               if (iobuf.out_fd == -2)
+                                       whine_about_eof(True);
                                rprintf(FERROR, "error in perform_io: no fd for output.\n");
                                exit_cleanup(RERR_PROTOCOL);
                        default:
@@ -709,8 +718,9 @@ static char *perform_io(size_t needed, int flags)
                        int n;
                        if ((n = read(iobuf.in_fd, iobuf.in.buf + pos, len)) <= 0) {
                                if (n == 0) {
+                                       /* Signal that input has become invalid. */
                                        if (!read_batch || batch_fd < 0 || am_generator)
-                                               whine_about_eof(iobuf.in_fd); /* Doesn't return. */
+                                               iobuf.in_fd = -2;
                                        batch_fd = -1;
                                        continue;
                                }
@@ -752,8 +762,10 @@ static char *perform_io(size_t needed, int flags)
                                else {
                                        /* Don't write errors on a dead socket. */
                                        msgs2stderr = 1;
-                                       out->len = iobuf.raw_flushing_ends_before = out->pos = 0;
+                                       iobuf.out_fd = -2;
+                                       iobuf.out.len = iobuf.msg.len = iobuf.raw_flushing_ends_before = 0;
                                        rsyserr(FERROR_SOCKET, errno, "[%s] write error", who_am_i());
+                                       drain_multiplex_messages();
                                        exit_cleanup(RERR_STREAMIO);
                                }
                        }
@@ -806,7 +818,7 @@ void noop_io_until_death(void)
 {
        char buf[1024];
 
-       kluge_around_eof = 1;
+       kluge_around_eof = 2;
        /* For protocol 31: setting an I/O timeout ensures that if something
         * inexplicably weird happens, we won't hang around forever.  For older
         * protocols: we can't tell the other side to die, so we linger a brief
@@ -1475,6 +1487,23 @@ static void read_a_msg(void)
        }
 }
 
+static void drain_multiplex_messages(void)
+{
+       while (IN_MULTIPLEXED && iobuf.in.len) {
+               if (iobuf.raw_input_ends_before) {
+                       size_t raw_len = iobuf.raw_input_ends_before - iobuf.in.pos;
+                       iobuf.raw_input_ends_before = 0;
+                       if (raw_len >= iobuf.in.len) {
+                               iobuf.in.len = 0;
+                               break;
+                       }
+                       iobuf.in.pos += raw_len;
+                       iobuf.in.len -= raw_len;
+               }
+               read_a_msg();
+       }
+}
+
 void wait_for_receiver(void)
 {
        if (!iobuf.raw_input_ends_before)
@@ -1628,7 +1657,7 @@ void read_buf(int f, char *buf, size_t len)
 {
        if (f != iobuf.in_fd) {
                if (safe_read(f, buf, len) != len)
-                       whine_about_eof(f); /* Doesn't return. */
+                       whine_about_eof(False); /* Doesn't return. */
                goto batch_copy;
        }