void packet_flush(int fd)
{
packet_trace("0000", 4, 1);
- write_or_die(fd, "0000", 4);
+ if (write_in_full(fd, "0000", 4) < 0)
+ die_errno(_("unable to write flush packet"));
}
void packet_delim(int fd)
{
packet_trace("0001", 4, 1);
- write_or_die(fd, "0001", 4);
+ if (write_in_full(fd, "0001", 4) < 0)
+ die_errno(_("unable to write delim packet"));
+}
+
+void packet_response_end(int fd)
+{
+ packet_trace("0002", 4, 1);
+ if (write_in_full(fd, "0002", 4) < 0)
+ die_errno(_("unable to write stateless separator packet"));
}
int packet_flush_gently(int fd)
strbuf_add(buf, "0001", 4);
}
-static void set_packet_header(char *buf, const int size)
+void set_packet_header(char *buf, int size)
{
static char hexchar[] = "0123456789abcdef";
#undef hex
}
-static void format_packet(struct strbuf *out, const char *fmt, va_list args)
+static void format_packet(struct strbuf *out, const char *prefix,
+ const char *fmt, va_list args)
{
size_t orig_len, n;
orig_len = out->len;
strbuf_addstr(out, "0000");
+ strbuf_addstr(out, prefix);
strbuf_vaddf(out, fmt, args);
n = out->len - orig_len;
packet_trace(out->buf + orig_len + 4, n - 4, 1);
}
-static int packet_write_fmt_1(int fd, int gently,
+static int packet_write_fmt_1(int fd, int gently, const char *prefix,
const char *fmt, va_list args)
{
static struct strbuf buf = STRBUF_INIT;
strbuf_reset(&buf);
- format_packet(&buf, fmt, args);
+ format_packet(&buf, prefix, fmt, args);
if (write_in_full(fd, buf.buf, buf.len) < 0) {
if (!gently) {
check_pipe(errno);
va_list args;
va_start(args, fmt);
- packet_write_fmt_1(fd, 0, fmt, args);
+ packet_write_fmt_1(fd, 0, "", fmt, args);
va_end(args);
}
va_list args;
va_start(args, fmt);
- status = packet_write_fmt_1(fd, 1, fmt, args);
+ status = packet_write_fmt_1(fd, 1, "", fmt, args);
va_end(args);
return status;
}
static int packet_write_gently(const int fd_out, const char *buf, size_t size)
{
- static char packet_write_buffer[LARGE_PACKET_MAX];
+ char header[4];
size_t packet_size;
- if (size > sizeof(packet_write_buffer) - 4)
+ if (size > LARGE_PACKET_DATA_MAX)
return error(_("packet write failed - data exceeds max packet size"));
packet_trace(buf, size, 1);
packet_size = size + 4;
- set_packet_header(packet_write_buffer, packet_size);
- memcpy(packet_write_buffer + 4, buf, size);
- if (write_in_full(fd_out, packet_write_buffer, packet_size) < 0)
+
+ set_packet_header(header, packet_size);
+
+ /*
+ * Write the header and the buffer in 2 parts so that we do
+ * not need to allocate a buffer or rely on a static buffer.
+ * This also avoids putting a large buffer on the stack which
+ * might have multi-threading issues.
+ */
+
+ if (write_in_full(fd_out, header, 4) < 0 ||
+ write_in_full(fd_out, buf, size) < 0)
return error(_("packet write failed"));
return 0;
}
va_list args;
va_start(args, fmt);
- format_packet(buf, fmt, args);
+ format_packet(buf, "", fmt, args);
va_end(args);
}
packet_trace(data, len, 1);
}
-int write_packetized_from_fd(int fd_in, int fd_out)
+int write_packetized_from_fd_no_flush(int fd_in, int fd_out)
{
- static char buf[LARGE_PACKET_DATA_MAX];
+ char *buf = xmalloc(LARGE_PACKET_DATA_MAX);
int err = 0;
ssize_t bytes_to_write;
while (!err) {
- bytes_to_write = xread(fd_in, buf, sizeof(buf));
- if (bytes_to_write < 0)
+ bytes_to_write = xread(fd_in, buf, LARGE_PACKET_DATA_MAX);
+ if (bytes_to_write < 0) {
+ free(buf);
return COPY_READ_ERROR;
+ }
if (bytes_to_write == 0)
break;
err = packet_write_gently(fd_out, buf, bytes_to_write);
}
- if (!err)
- err = packet_flush_gently(fd_out);
+ free(buf);
return err;
}
-int write_packetized_from_buf(const char *src_in, size_t len, int fd_out)
+int write_packetized_from_buf_no_flush(const char *src_in, size_t len, int fd_out)
{
int err = 0;
size_t bytes_written = 0;
err = packet_write_gently(fd_out, src_in + bytes_written, bytes_to_write);
bytes_written += bytes_to_write;
}
- if (!err)
- err = packet_flush_gently(fd_out);
return err;
}
*src_size -= ret;
} else {
ret = read_in_full(fd, dst, size);
- if (ret < 0)
+ if (ret < 0) {
+ if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
+ return error_errno(_("read error"));
die_errno(_("read error"));
+ }
}
/* And complain if we didn't get enough bytes to satisfy the read. */
if (options & PACKET_READ_GENTLE_ON_EOF)
return -1;
+ if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
+ return error(_("the remote end hung up unexpectedly"));
die(_("the remote end hung up unexpectedly"));
}
return ret;
}
-static int packet_length(const char *linelen)
+int packet_length(const char lenbuf_hex[4])
{
- int val = hex2chr(linelen);
- return (val < 0) ? val : (val << 8) | hex2chr(linelen + 2);
+ int val = hex2chr(lenbuf_hex);
+ return (val < 0) ? val : (val << 8) | hex2chr(lenbuf_hex + 2);
}
enum packet_read_status packet_read_with_status(int fd, char **src_buffer,
len = packet_length(linelen);
if (len < 0) {
+ if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
+ return error(_("protocol error: bad line length "
+ "character: %.4s"), linelen);
die(_("protocol error: bad line length character: %.4s"), linelen);
} else if (!len) {
packet_trace("0000", 4, 0);
packet_trace("0001", 4, 0);
*pktlen = 0;
return PACKET_READ_DELIM;
+ } else if (len == 2) {
+ packet_trace("0002", 4, 0);
+ *pktlen = 0;
+ return PACKET_READ_RESPONSE_END;
} else if (len < 4) {
+ if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
+ return error(_("protocol error: bad line length %d"),
+ len);
die(_("protocol error: bad line length %d"), len);
}
len -= 4;
- if ((unsigned)len >= size)
+ if ((unsigned)len >= size) {
+ if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
+ return error(_("protocol error: bad line length %d"),
+ len);
die(_("protocol error: bad line length %d"), len);
+ }
if (get_packet_data(fd, src_buffer, src_len, buffer, len, options) < 0) {
*pktlen = -1;
buffer[len] = 0;
packet_trace(buffer, len, 0);
+
+ if ((options & PACKET_READ_DIE_ON_ERR_PACKET) &&
+ starts_with(buffer, "ERR "))
+ die(_("remote error: %s"), buffer + 4);
+
*pktlen = len;
return PACKET_READ_NORMAL;
}
return packet_read_line_generic(-1, src, src_len, dst_len);
}
-ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out)
+ssize_t read_packetized_to_strbuf(int fd_in, struct strbuf *sb_out, int options)
{
int packet_len;
* that there is already room for the extra byte.
*/
sb_out->buf + sb_out->len, LARGE_PACKET_DATA_MAX+1,
- PACKET_READ_GENTLE_ON_EOF);
+ options);
if (packet_len <= 0)
break;
sb_out->len += packet_len;
return sb_out->len - orig_len;
}
+int recv_sideband(const char *me, int in_stream, int out)
+{
+ char buf[LARGE_PACKET_MAX + 1];
+ int len;
+ struct strbuf scratch = STRBUF_INIT;
+ enum sideband_type sideband_type;
+
+ while (1) {
+ int status = packet_read_with_status(in_stream, NULL, NULL,
+ buf, LARGE_PACKET_MAX,
+ &len,
+ PACKET_READ_GENTLE_ON_EOF);
+ if (!demultiplex_sideband(me, status, buf, len, 0, &scratch,
+ &sideband_type))
+ continue;
+ switch (sideband_type) {
+ case SIDEBAND_PRIMARY:
+ write_or_die(out, buf + 1, len - 1);
+ break;
+ default: /* errors: message already written */
+ if (scratch.len > 0)
+ BUG("unhandled incomplete sideband: '%s'",
+ scratch.buf);
+ return sideband_type;
+ }
+ }
+}
+
/* Packet Reader Functions */
void packet_reader_init(struct packet_reader *reader, int fd,
char *src_buffer, size_t src_len,
reader->buffer = packet_buffer;
reader->buffer_size = sizeof(packet_buffer);
reader->options = options;
+ reader->me = "git";
+ reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
}
enum packet_read_status packet_reader_read(struct packet_reader *reader)
{
+ struct strbuf scratch = STRBUF_INIT;
+
if (reader->line_peeked) {
reader->line_peeked = 0;
return reader->status;
}
- reader->status = packet_read_with_status(reader->fd,
- &reader->src_buffer,
- &reader->src_len,
- reader->buffer,
- reader->buffer_size,
- &reader->pktlen,
- reader->options);
+ /*
+ * Consume all progress packets until a primary payload packet is
+ * received
+ */
+ while (1) {
+ enum sideband_type sideband_type;
+ reader->status = packet_read_with_status(reader->fd,
+ &reader->src_buffer,
+ &reader->src_len,
+ reader->buffer,
+ reader->buffer_size,
+ &reader->pktlen,
+ reader->options);
+ if (!reader->use_sideband)
+ break;
+ if (demultiplex_sideband(reader->me, reader->status,
+ reader->buffer, reader->pktlen, 1,
+ &scratch, &sideband_type))
+ break;
+ }
if (reader->status == PACKET_READ_NORMAL)
- reader->line = reader->buffer;
+ /* Skip the sideband designator if sideband is used */
+ reader->line = reader->use_sideband ?
+ reader->buffer + 1 : reader->buffer;
else
reader->line = NULL;
reader->line_peeked = 1;
return reader->status;
}
+
+void packet_writer_init(struct packet_writer *writer, int dest_fd)
+{
+ writer->dest_fd = dest_fd;
+ writer->use_sideband = 0;
+}
+
+void packet_writer_write(struct packet_writer *writer, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ packet_write_fmt_1(writer->dest_fd, 0,
+ writer->use_sideband ? "\001" : "", fmt, args);
+ va_end(args);
+}
+
+void packet_writer_error(struct packet_writer *writer, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ packet_write_fmt_1(writer->dest_fd, 0,
+ writer->use_sideband ? "\003" : "ERR ", fmt, args);
+ va_end(args);
+}
+
+void packet_writer_delim(struct packet_writer *writer)
+{
+ packet_delim(writer->dest_fd);
+}
+
+void packet_writer_flush(struct packet_writer *writer)
+{
+ packet_flush(writer->dest_fd);
+}