+/* read from a socket with IO timeout. return the number of
+ bytes read. If no bytes can be read then exit, never return
+ a number <= 0 */
+static int read_timeout(int fd, char *buf, int len)
+{
+ int n, ret=0;
+
+ io_flush();
+
+ while (ret == 0) {
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = io_timeout;
+ tv.tv_usec = 0;
+
+ if (select(fd+1, &fds, NULL, NULL,
+ io_timeout?&tv:NULL) != 1) {
+ check_timeout();
+ continue;
+ }
+
+ n = read(fd, buf, len);
+
+ if (n > 0) {
+ buf += n;
+ len -= n;
+ ret += n;
+ if (io_timeout)
+ last_io = time(NULL);
+ continue;
+ }
+
+ if (n == -1 && errno == EINTR) {
+ continue;
+ }
+
+ if (n == 0) {
+ if (eof_error) {
+ rprintf(FERROR,"EOF in read_timeout\n");
+ }
+ exit_cleanup(1);
+ }
+
+ rprintf(FERROR,"read error: %s\n", strerror(errno));
+ exit_cleanup(1);
+ }
+
+ return ret;
+}
+
+/* continue trying to read len bytes - don't return until len
+ has been read */
+static void read_loop(int fd, char *buf, int len)
+{
+ while (len) {
+ int n = read_timeout(fd, buf, len);
+
+ buf += n;
+ len -= n;
+ }
+}
+
+/* read from the file descriptor handing multiplexing -
+ return number of bytes read
+ never return <= 0 */
+static int read_unbuffered(int fd, char *buf, int len)
+{
+ static int remaining;
+ char ibuf[4];
+ int tag, ret=0;
+ char line[1024];
+
+ if (!io_multiplexing_in || fd != multiplex_in_fd)
+ return read_timeout(fd, buf, len);
+
+ while (ret == 0) {
+ if (remaining) {
+ len = MIN(len, remaining);
+ read_loop(fd, buf, len);
+ remaining -= len;
+ ret = len;
+ continue;
+ }
+
+ read_loop(fd, ibuf, 4);
+ tag = IVAL(ibuf, 0);
+
+ remaining = tag & 0xFFFFFF;
+ tag = tag >> 24;
+
+ if (tag == MPLEX_BASE) continue;
+
+ tag -= MPLEX_BASE;
+
+ if (tag != FERROR && tag != FINFO) {
+ rprintf(FERROR,"unexpected tag %d\n", tag);
+ exit_cleanup(1);
+ }
+
+ if (remaining > sizeof(line)-1) {
+ rprintf(FERROR,"multiplexing overflow %d\n\n",
+ remaining);
+ exit_cleanup(1);
+ }
+
+ read_loop(fd, line, remaining);
+ line[remaining] = 0;
+
+ rprintf(tag,"%s", line);
+ remaining = 0;
+ }
+
+ return ret;
+}
+
+