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)