Subject: [PATCH v3 03/26] pkt-line.c: add packet_read_line_timeout()

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Mon, 3 Feb 2014 11:28:51 +0700

This version is also gentler than its friend packet_read_line()
because it's designed for side channel I/O that should not abort the
program even if the channel is broken.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 cache.h    |  1 +
 pkt-line.c | 35 +++++++++++++++++++++++++++++++++++
 pkt-line.h |  1 +
 wrapper.c  | 21 +++++++++++++++++++++
 4 files changed, 58 insertions(+)

diff --git a/cache.h b/cache.h
index 718e32b..939db46 100644
--- a/cache.h
+++ b/cache.h
@@ -1230,6 +1230,7 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
 extern void fsync_or_die(int fd, const char *);
 
 extern ssize_t read_in_full(int fd, void *buf, size_t count);
+extern ssize_t read_in_full_timeout(int fd, void *buf, size_t count, int timeout);
 extern ssize_t write_in_full(int fd, const void *buf, size_t count);
 extern ssize_t write_in_full_timeout(int fd, const void *buf, size_t count, int timeout);
 static inline ssize_t write_str_in_full(int fd, const char *str)
diff --git a/pkt-line.c b/pkt-line.c
index cf681e9..5a07e97 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -229,3 +229,38 @@ char *packet_read_line_buf(char **src, size_t *src_len, int *dst_len)
 {
 	return packet_read_line_generic(-1, src, src_len, dst_len);
 }
+
+char *packet_read_line_timeout(int fd, int timeout, int *len_p)
+{
+	char *buf = packet_buffer;
+	int ret, len, buf_len = sizeof(packet_buffer);
+	char linelen[4];
+
+	if (fd == -1)
+		return NULL;
+	if ((ret = read_in_full_timeout(fd, linelen, 4, timeout)) < 0)
+		return NULL;
+	len = packet_length(linelen);
+	if (len < 0) {
+		error("protocol error: bad line length character: %.4s", linelen);
+		return NULL;
+	}
+	if (!len) {
+		packet_trace("0000", 4, 0);
+		if (len_p)
+			*len_p = 0;
+		return "";
+	}
+	len -= 4;
+	if (len >= buf_len) {
+		error("protocol error: bad line length %d", len);
+		return NULL;
+	}
+	if ((ret = read_in_full_timeout(fd, buf, len, timeout)) < 0)
+		return NULL;
+	buf[len] = '\0';
+	if (len_p)
+		*len_p = len;
+	packet_trace(buf, len, 0);
+	return buf;
+}
diff --git a/pkt-line.h b/pkt-line.h
index 4b93a0c..d47dca5 100644
--- a/pkt-line.h
+++ b/pkt-line.h
@@ -69,6 +69,7 @@ int packet_read(int fd, char **src_buffer, size_t *src_len, char
  * packet is written to it.
  */
 char *packet_read_line(int fd, int *size);
+char *packet_read_line_timeout(int fd, int timeout, int *size);
 
 /*
  * Same as packet_read_line, but read from a buf rather than a descriptor;
diff --git a/wrapper.c b/wrapper.c
index 9a0e289..9cf10b2 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -193,6 +193,27 @@ ssize_t read_in_full(int fd, void *buf, size_t count)
 	return total;
 }
 
+ssize_t read_in_full_timeout(int fd, void *buf, size_t count, int timeout)
+{
+	char *p = buf;
+	ssize_t total = 0;
+	struct pollfd pfd;
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+	while (count > 0 && poll(&pfd, 1, timeout) > 0 &&
+	       (pfd.revents & POLLIN)) {
+		ssize_t loaded = xread(fd, p, count);
+		if (loaded <= 0)
+			return -1;
+		count -= loaded;
+		p += loaded;
+		total += loaded;
+	}
+
+	return count ? -1 : total;
+}
+
 ssize_t write_in_full(int fd, const void *buf, size_t count)
 {
 	const char *p = buf;
-- 
1.8.5.2.240.g8478abd