pkt-line: allow peeking a packet line without consuming it

Sometimes it is advantageous to be able to peek the next packet line without consuming it (e.g. to be able to determine the protocol version a server is speaking). In order to do that introduce 'struct packet_reader' which is an abstraction around the normal packet reading logic. This enables a caller to be able to peek a single line at a time using 'packet_reader_peek()' and having a caller consume a line by calling 'packet_reader_read()'. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Mar 14, 2018 at 11:31 UTC 77dabc14c497d2498b814967bf21a3ed1618207f
2 files changed +108
pkt-line.c
+50
@@ -400,3 +400,53 @@ ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out)
400 }
401 return sb_out->len - orig_len;
402 }
403 +
404 +/* Packet Reader Functions */
405 +void packet_reader_init(struct packet_reader *reader, int fd,
406 + char *src_buffer, size_t src_len,
407 + int options)
408 +{
409 + memset(reader, 0, sizeof(*reader));
410 +
411 + reader->fd = fd;
412 + reader->src_buffer = src_buffer;
413 + reader->src_len = src_len;
414 + reader->buffer = packet_buffer;
415 + reader->buffer_size = sizeof(packet_buffer);
416 + reader->options = options;
417 +}
418 +
419 +enum packet_read_status packet_reader_read(struct packet_reader *reader)
420 +{
421 + if (reader->line_peeked) {
422 + reader->line_peeked = 0;
423 + return reader->status;
424 + }
425 +
426 + reader->status = packet_read_with_status(reader->fd,
427 + &reader->src_buffer,
428 + &reader->src_len,
429 + reader->buffer,
430 + reader->buffer_size,
431 + &reader->pktlen,
432 + reader->options);
433 +
434 + if (reader->status == PACKET_READ_NORMAL)
435 + reader->line = reader->buffer;
436 + else
437 + reader->line = NULL;
438 +
439 + return reader->status;
440 +}
441 +
442 +enum packet_read_status packet_reader_peek(struct packet_reader *reader)
443 +{
444 + /* Only allow peeking a single line */
445 + if (reader->line_peeked)
446 + return reader->status;
447 +
448 + /* Peek a line by reading it and setting peeked flag */
449 + packet_reader_read(reader);
450 + reader->line_peeked = 1;
451 + return reader->status;
452 +}
pkt-line.h
+58
@@ -112,6 +112,64 @@ char *packet_read_line_buf(char **src_buf, size_t *src_len, int *size);
112 */
113 ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out);
114
115 +struct packet_reader {
116 + /* source file descriptor */
117 + int fd;
118 +
119 + /* source buffer and its size */
120 + char *src_buffer;
121 + size_t src_len;
122 +
123 + /* buffer that pkt-lines are read into and its size */
124 + char *buffer;
125 + unsigned buffer_size;
126 +
127 + /* options to be used during reads */
128 + int options;
129 +
130 + /* status of the last read */
131 + enum packet_read_status status;
132 +
133 + /* length of data read during the last read */
134 + int pktlen;
135 +
136 + /* the last line read */
137 + const char *line;
138 +
139 + /* indicates if a line has been peeked */
140 + int line_peeked;
141 +};
142 +
143 +/*
144 + * Initialize a 'struct packet_reader' object which is an
145 + * abstraction around the 'packet_read_with_status()' function.
146 + */
147 +extern void packet_reader_init(struct packet_reader *reader, int fd,
148 + char *src_buffer, size_t src_len,
149 + int options);
150 +
151 +/*
152 + * Perform a packet read and return the status of the read.
153 + * The values of 'pktlen' and 'line' are updated based on the status of the
154 + * read as follows:
155 + *
156 + * PACKET_READ_ERROR: 'pktlen' is set to '-1' and 'line' is set to NULL
157 + * PACKET_READ_NORMAL: 'pktlen' is set to the number of bytes read
158 + * 'line' is set to point at the read line
159 + * PACKET_READ_FLUSH: 'pktlen' is set to '0' and 'line' is set to NULL
160 + */
161 +extern enum packet_read_status packet_reader_read(struct packet_reader *reader);
162 +
163 +/*
164 + * Peek the next packet line without consuming it and return the status.
165 + * The next call to 'packet_reader_read()' will perform a read of the same line
166 + * that was peeked, consuming the line.
167 + *
168 + * Peeking multiple times without calling 'packet_reader_read()' will return
169 + * the same result.
170 + */
171 +extern enum packet_read_status packet_reader_peek(struct packet_reader *reader);
172 +
173 #define DEFAULT_PACKET_MAX 1000
174 #define LARGE_PACKET_MAX 65520
175 #define LARGE_PACKET_DATA_MAX (LARGE_PACKET_MAX - 4)