Create a functions that can read malformed messages without dying. Includes creation of flag PACKET_READ_GENTLE_ALL. For use handling prime-clone (or other server error) responses. Signed-off-by: Kevin Wern <kevin.m.wern@xxxxxxxxx> --- pkt-line.c | 47 ++++++++++++++++++++++++++++++++++++++--------- pkt-line.h | 16 ++++++++++++++++ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/pkt-line.c b/pkt-line.c index 62fdb37..96060e5 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -155,13 +155,17 @@ static int get_packet_data(int fd, char **src_buf, size_t *src_size, *src_size -= ret; } else { ret = read_in_full(fd, dst, size); - if (ret < 0) + if (ret < 0) { + if (options & PACKET_READ_GENTLE_ALL) + return -1; + die_errno("read error"); + } } /* And complain if we didn't get enough bytes to satisfy the read. */ if (ret < size) { - if (options & PACKET_READ_GENTLE_ON_EOF) + if (options & (PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ALL)) return -1; die("The remote end hung up unexpectedly"); @@ -205,15 +209,23 @@ int packet_read(int fd, char **src_buf, size_t *src_len, if (ret < 0) return ret; len = packet_length(linelen); - if (len < 0) + if (len < 0) { + if (options & PACKET_READ_GENTLE_ALL) + return -1; + die("protocol error: bad line length character: %.4s", linelen); + } if (!len) { packet_trace("0000", 4, 0); return 0; } len -= 4; - if (len >= size) + if (len >= size) { + if (options & PACKET_READ_GENTLE_ALL) + return -1; + die("protocol error: bad line length %d", len); + } ret = get_packet_data(fd, src_buf, src_len, buffer, len, options); if (ret < 0) return ret; @@ -229,22 +241,39 @@ int packet_read(int fd, char **src_buf, size_t *src_len, static char *packet_read_line_generic(int fd, char **src, size_t *src_len, - int *dst_len) + int *dst_len, int flags) { int len = packet_read(fd, src, src_len, packet_buffer, sizeof(packet_buffer), - PACKET_READ_CHOMP_NEWLINE); + flags); if (dst_len) *dst_len = len; - return len ? packet_buffer : NULL; + return len > 0 ? packet_buffer : NULL; } char *packet_read_line(int fd, int *len_p) { - return packet_read_line_generic(fd, NULL, NULL, len_p); + return packet_read_line_generic(fd, NULL, NULL, len_p, + PACKET_READ_CHOMP_NEWLINE); } 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); + return packet_read_line_generic(-1, src, src_len, dst_len, + PACKET_READ_CHOMP_NEWLINE); +} + +char *packet_read_line_gentle(int fd, int *len_p) +{ + return packet_read_line_generic(fd, NULL, NULL, len_p, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ALL); +} + + +char *packet_read_line_buf_gentle(char **src, size_t *src_len, int *dst_len) +{ + return packet_read_line_generic(-1, src, src_len, dst_len, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_GENTLE_ALL); } diff --git a/pkt-line.h b/pkt-line.h index 3cb9d91..553e42e 100644 --- a/pkt-line.h +++ b/pkt-line.h @@ -52,11 +52,15 @@ void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((f * condition 4 (truncated input), but instead return -1. However, we will still * die for the other 3 conditions. * + * If options contains PACKET_READ_GENTLE_ALL, we will not die on any of the + * conditions, but return -1 instead. + * * If options contains PACKET_READ_CHOMP_NEWLINE, a trailing newline (if * present) is removed from the buffer before returning. */ #define PACKET_READ_GENTLE_ON_EOF (1u<<0) #define PACKET_READ_CHOMP_NEWLINE (1u<<1) +#define PACKET_READ_GENTLE_ALL (1u<<2) int packet_read(int fd, char **src_buffer, size_t *src_len, char *buffer, unsigned size, int options); @@ -75,6 +79,18 @@ char *packet_read_line(int fd, int *size); */ char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size); +/* + * Same as packet_read_line, but does not die on any errors (uses + * PACKET_READ_GENTLE_ALL). + */ +char *packet_read_line_gentle(int fd, int *len_p); + +/* + * Same as packet_read_line_buf, but does not die on any errors (uses + * PACKET_READ_GENTLE_ALL). + */ +char *packet_read_line_buf_gentle(char **src_buf, size_t *src_len, int *size); + #define DEFAULT_PACKET_MAX 1000 #define LARGE_PACKET_MAX 65520 extern char packet_buffer[LARGE_PACKET_MAX]; -- 2.7.4