X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/b0ad542928c6bde674f3dec96be446a2e2ed0548..7448177753f8a69cb0edf396e05094642b9bcbc8:/io.c diff --git a/io.c b/io.c index 4cf33028..e5574025 100644 --- a/io.c +++ b/io.c @@ -46,7 +46,9 @@ extern int io_timeout; extern int am_server; extern int am_daemon; extern int am_sender; +extern int am_generator; extern int eol_nulls; +extern int csum_length; extern int checksum_seed; extern int protocol_version; extern char *remote_filesfrom_file; @@ -147,7 +149,7 @@ static void check_timeout(void) if (t - last_io >= io_timeout) { if (!am_server && !am_daemon) { - rprintf(FERROR, "io timeout after %d seconds - exiting\n", + rprintf(FERROR, "io timeout after %d seconds -- exiting\n", (int)(t-last_io)); } exit_cleanup(RERR_TIMEOUT); @@ -162,17 +164,17 @@ void io_set_sock_fds(int f_in, int f_out) sock_f_out = f_out; } -/** Setup the fd used to receive MSG_* messages. Only needed when - * we're the generator because the sender and receiver both use the - * multiplexed I/O setup. */ +/* Setup the fd used to receive MSG_* messages. Only needed during the + * early stages of being a local sender (up through the sending of the + * file list) or when we're the generator (to fetch the messages from + * the receiver). */ void set_msg_fd_in(int fd) { msg_fd_in = fd; } -/** Setup the fd used to send our MSG_* messages. Only needed when - * we're the receiver because the generator and the sender both use - * the multiplexed I/O setup. */ +/* Setup the fd used to send our MSG_* messages. Only needed when + * we're the receiver (to send our messages to the generator). */ void set_msg_fd_out(int fd) { msg_fd_out = fd; @@ -205,8 +207,10 @@ void send_msg(enum msgcode code, char *buf, int len) msg_list_push(NORMAL_FLUSH); } -/** Read a message from the MSG_* fd and dispatch it. This is only - * called by the generator. */ +/* Read a message from the MSG_* fd and handle it. This is called either + * during the early stages of being a local sender (up through the sending + * of the file list) or when we're the generator (to fetch the messages + * from the receiver). */ static void read_msg_fd(void) { char buf[2048]; @@ -226,14 +230,14 @@ static void read_msg_fd(void) switch (tag) { case MSG_DONE: - if (len != 0) { + if (len != 0 || !am_generator) { rprintf(FERROR, "invalid message %d:%d\n", tag, len); exit_cleanup(RERR_STREAMIO); } redo_list_add(-1); break; case MSG_REDO: - if (len != 4) { + if (len != 4 || !am_generator) { rprintf(FERROR, "invalid message %d:%d\n", tag, len); exit_cleanup(RERR_STREAMIO); } @@ -353,8 +357,8 @@ static void whine_about_eof(int fd) exit_cleanup(0); rprintf(FERROR, RSYNC_NAME ": connection unexpectedly closed " - "(%.0f bytes read so far)\n", - (double)stats.total_read); + "(%.0f bytes received so far) [%s]\n", + (double)stats.total_read, who_am_i()); exit_cleanup(RERR_STREAMIO); } @@ -510,7 +514,7 @@ static int read_timeout(int fd, char *buf, size_t len) /* Don't write errors on a dead socket. */ if (fd == sock_f_in) - io_multiplexing_close(); + close_multiplexing_out(); rsyserr(FERROR, errno, "read error"); exit_cleanup(RERR_STREAMIO); } @@ -676,8 +680,9 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) case MSG_INFO: case MSG_ERROR: if (remaining >= sizeof line) { - rprintf(FERROR, "multiplexing overflow %d:%ld\n\n", - tag, (long)remaining); + rprintf(FERROR, + "[%s] multiplexing overflow %d:%ld\n\n", + who_am_i(), tag, (long)remaining); exit_cleanup(RERR_STREAMIO); } read_loop(fd, line, remaining); @@ -685,7 +690,8 @@ static int readfd_unbuffered(int fd, char *buf, size_t len) remaining = 0; break; default: - rprintf(FERROR, "unexpected tag %d\n", tag); + rprintf(FERROR, "[%s] unexpected tag %d\n", + who_am_i(), tag); exit_cleanup(RERR_STREAMIO); } } @@ -723,6 +729,14 @@ static void readfd(int fd, char *buffer, size_t N) } +unsigned short read_short(int f) +{ + uchar b[2]; + readfd(f, (char *)b, 2); + return (b[1] << 8) + b[0]; +} + + int32 read_int(int f) { char b[4]; @@ -744,8 +758,8 @@ int64 read_longint(int f) if ((int32)ret != (int32)0xffffffff) return ret; -#ifdef NO_INT64 - rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n"); +#if SIZEOF_INT64 < 8 + rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); #else readfd(f,b,8); @@ -766,13 +780,55 @@ void read_sbuf(int f,char *buf,size_t len) buf[len] = 0; } -unsigned char read_byte(int f) +uchar read_byte(int f) { - unsigned char c; + uchar c; readfd(f, (char *)&c, 1); return c; } +/* Populate a sum_struct with values from the socket. This is + * called by both the sender and the receiver. */ +void read_sum_head(int f, struct sum_struct *sum) +{ + sum->count = read_int(f); + sum->blength = read_int(f); + if (sum->blength < 0 || sum->blength > MAX_BLOCK_SIZE) { + rprintf(FERROR, "[%s] Invalid block length %ld\n", + who_am_i(), (long)sum->blength); + exit_cleanup(RERR_PROTOCOL); + } + sum->s2length = protocol_version < 27 ? csum_length : (int)read_int(f); + if (sum->s2length < 0 || sum->s2length > MD4_SUM_LENGTH) { + rprintf(FERROR, "[%s] Invalid checksum length %d\n", + who_am_i(), sum->s2length); + exit_cleanup(RERR_PROTOCOL); + } + sum->remainder = read_int(f); + if (sum->remainder < 0 || sum->remainder > sum->blength) { + rprintf(FERROR, "[%s] Invalid remainder length %ld\n", + who_am_i(), (long)sum->remainder); + exit_cleanup(RERR_PROTOCOL); + } +} + +/* Send the values from a sum_struct over the socket. Set sum to + * NULL if there are no checksums to send. This is called by both + * the generator and the sender. */ +void write_sum_head(int f, struct sum_struct *sum) +{ + static struct sum_struct null_sum; + + if (sum == NULL) + sum = &null_sum; + + write_int(f, sum->count); + write_int(f, sum->blength); + if (protocol_version >= 27) + write_int(f, sum->s2length); + write_int(f, sum->remainder); +} + /** * Sleep after writing to limit I/O bandwidth usage. @@ -856,6 +912,11 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) if (msg_fd_in > maxfd) maxfd = msg_fd_in; } + if (fd != sock_f_out && iobuf_out_cnt && no_flush == 1) { + FD_SET(sock_f_out, &w_fds); + if (sock_f_out > maxfd) + maxfd = sock_f_out; + } tv.tv_sec = select_timeout; tv.tv_usec = 0; @@ -874,8 +935,14 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) if (msg_fd_in >= 0 && FD_ISSET(msg_fd_in, &r_fds)) read_msg_fd(); - if (!FD_ISSET(fd, &w_fds)) + if (!FD_ISSET(fd, &w_fds)) { + if (fd != sock_f_out && iobuf_out_cnt) { + no_flush--; + io_flush(NORMAL_FLUSH); + no_flush++; + } continue; + } n = len - total; if (bwlimit && n > bwlimit_writemax) @@ -894,10 +961,17 @@ static void writefd_unbuffered(int fd,char *buf,size_t len) /* Don't try to write errors back across the stream. */ if (fd == sock_f_out) - io_multiplexing_close(); + close_multiplexing_out(); rsyserr(FERROR, errno, - "writefd_unbuffered failed to write %ld bytes: phase \"%s\"", - (long)len, io_write_phase); + "writefd_unbuffered failed to write %ld bytes: phase \"%s\" [%s]", + (long)len, io_write_phase, who_am_i()); + /* If the other side is sending us error messages, try + * to grab any messages they sent before they died. */ + while (fd == sock_f_out && io_multiplexing_in) { + io_timeout = select_timeout = 30; + readfd_unbuffered(sock_f_in, io_filesfrom_buf, + sizeof io_filesfrom_buf); + } exit_cleanup(RERR_STREAMIO); } @@ -989,6 +1063,15 @@ static void writefd(int fd,char *buf,size_t len) } +void write_short(int f, unsigned short x) +{ + uchar b[2]; + b[0] = x; + b[1] = x >> 8; + writefd(f, (char *)b, 2); +} + + void write_int(int f,int32 x) { char b[4]; @@ -1018,8 +1101,8 @@ void write_longint(int f, int64 x) return; } -#ifdef NO_INT64 - rprintf(FERROR,"Integer overflow - attempted 64 bit offset\n"); +#if SIZEOF_INT64 < 8 + rprintf(FERROR, "Integer overflow: attempted 64-bit offset\n"); exit_cleanup(RERR_UNSUPPORTED); #else write_int(f, (int32)0xFFFFFFFF); @@ -1035,19 +1118,20 @@ void write_buf(int f,char *buf,size_t len) writefd(f,buf,len); } + /** Write a string to the connection */ void write_sbuf(int f, char *buf) { writefd(f, buf, strlen(buf)); } -void write_byte(int f,unsigned char c) + +void write_byte(int f, uchar c) { writefd(f, (char *)&c, 1); } - /** * Read a line of up to @p maxlen characters into @p buf (not counting * the trailing null). Strips the (required) trailing newline and all @@ -1119,14 +1203,21 @@ int io_multiplex_write(enum msgcode code, char *buf, size_t len) return 1; } +void close_multiplexing_in(void) +{ + io_multiplexing_in = 0; +} + /** Stop output multiplexing. */ -void io_multiplexing_close(void) +void close_multiplexing_out(void) { io_multiplexing_out = 0; } void start_write_batch(int fd) { + write_stream_flags(batch_fd); + /* Some communication has already taken place, but we don't * enable batch writing until here so that we can write a * canonical record of the communication even though the