pkt-line.c 4.55 KB
Newer Older
1 2 3
#include "cache.h"
#include "pkt-line.h"

4
char packet_buffer[LARGE_PACKET_MAX];
5
static const char *packet_trace_prefix = "git";
6
static struct trace_key trace_packet = TRACE_KEY_INIT(PACKET);
Jeff King's avatar
Jeff King committed
7 8 9 10 11 12 13 14 15 16 17

void packet_trace_identity(const char *prog)
{
	packet_trace_prefix = xstrdup(prog);
}

static void packet_trace(const char *buf, unsigned int len, int write)
{
	int i;
	struct strbuf out;

18
	if (!trace_want(&trace_packet))
Jeff King's avatar
Jeff King committed
19 20 21 22 23 24 25 26
		return;

	/* +32 is just a guess for header + quoting */
	strbuf_init(&out, len+32);

	strbuf_addf(&out, "packet: %12s%c ",
		    packet_trace_prefix, write ? '>' : '<');

27 28
	if ((len >= 4 && starts_with(buf, "PACK")) ||
	    (len >= 5 && starts_with(buf+1, "PACK"))) {
Jeff King's avatar
Jeff King committed
29
		strbuf_addstr(&out, "PACK ...");
30
		trace_disable(&trace_packet);
Jeff King's avatar
Jeff King committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	}
	else {
		/* XXX we should really handle printable utf8 */
		for (i = 0; i < len; i++) {
			/* suppress newlines */
			if (buf[i] == '\n')
				continue;
			if (buf[i] >= 0x20 && buf[i] <= 0x7e)
				strbuf_addch(&out, buf[i]);
			else
				strbuf_addf(&out, "\\%o", buf[i]);
		}
	}

	strbuf_addch(&out, '\n');
46
	trace_strbuf(&trace_packet, &out);
Jeff King's avatar
Jeff King committed
47 48 49
	strbuf_release(&out);
}

50 51 52 53 54 55
/*
 * If we buffered things up above (we don't, but we should),
 * we'd flush it here
 */
void packet_flush(int fd)
{
Jeff King's avatar
Jeff King committed
56
	packet_trace("0000", 4, 1);
57
	write_or_die(fd, "0000", 4);
58 59
}

60 61
void packet_buf_flush(struct strbuf *buf)
{
Jeff King's avatar
Jeff King committed
62
	packet_trace("0000", 4, 1);
63 64 65
	strbuf_add(buf, "0000", 4);
}

66
#define hex(a) (hexchar[(a) & 15])
67 68
static char buffer[1000];
static unsigned format_packet(const char *fmt, va_list args)
69 70 71 72 73 74 75 76 77 78 79 80
{
	static char hexchar[] = "0123456789abcdef";
	unsigned n;

	n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
	if (n >= sizeof(buffer)-4)
		die("protocol error: impossibly long line");
	n += 4;
	buffer[0] = hex(n >> 12);
	buffer[1] = hex(n >> 8);
	buffer[2] = hex(n >> 4);
	buffer[3] = hex(n);
Jeff King's avatar
Jeff King committed
81
	packet_trace(buffer+4, n-4, 1);
82 83 84 85 86 87 88 89 90 91 92
	return n;
}

void packet_write(int fd, const char *fmt, ...)
{
	va_list args;
	unsigned n;

	va_start(args, fmt);
	n = format_packet(fmt, args);
	va_end(args);
93
	write_or_die(fd, buffer, n);
94 95
}

96 97 98 99 100 101 102 103 104 105 106
void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
{
	va_list args;
	unsigned n;

	va_start(args, fmt);
	n = format_packet(fmt, args);
	va_end(args);
	strbuf_add(buf, buffer, n);
}

107 108
static int get_packet_data(int fd, char **src_buf, size_t *src_size,
			   void *dst, unsigned size, int options)
109
{
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	ssize_t ret;

	if (fd >= 0 && src_buf && *src_buf)
		die("BUG: multiple sources given to packet_read");

	/* Read up to "size" bytes from our source, whatever it is. */
	if (src_buf && *src_buf) {
		ret = size < *src_size ? size : *src_size;
		memcpy(dst, *src_buf, ret);
		*src_buf += ret;
		*src_size -= ret;
	} else {
		ret = read_in_full(fd, dst, size);
		if (ret < 0)
			die_errno("read error");
	}

	/* And complain if we didn't get enough bytes to satisfy the read. */
	if (ret < size) {
129
		if (options & PACKET_READ_GENTLE_ON_EOF)
130 131
			return -1;

132
		die("The remote end hung up unexpectedly");
133 134 135
	}

	return ret;
136 137
}

138
static int packet_length(const char *linelen)
139 140
{
	int n;
141
	int len = 0;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

	for (n = 0; n < 4; n++) {
		unsigned char c = linelen[n];
		len <<= 4;
		if (c >= '0' && c <= '9') {
			len += c - '0';
			continue;
		}
		if (c >= 'a' && c <= 'f') {
			len += c - 'a' + 10;
			continue;
		}
		if (c >= 'A' && c <= 'F') {
			len += c - 'A' + 10;
			continue;
		}
158
		return -1;
159
	}
160 161 162
	return len;
}

163 164
int packet_read(int fd, char **src_buf, size_t *src_len,
		char *buffer, unsigned size, int options)
165
{
166
	int len, ret;
167 168
	char linelen[4];

169
	ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options);
170
	if (ret < 0)
171
		return ret;
172 173
	len = packet_length(linelen);
	if (len < 0)
174
		die("protocol error: bad line length character: %.4s", linelen);
Jeff King's avatar
Jeff King committed
175 176
	if (!len) {
		packet_trace("0000", 4, 0);
177
		return 0;
Jeff King's avatar
Jeff King committed
178
	}
179 180 181
	len -= 4;
	if (len >= size)
		die("protocol error: bad line length %d", len);
182
	ret = get_packet_data(fd, src_buf, src_len, buffer, len, options);
183
	if (ret < 0)
184
		return ret;
185 186 187 188 189

	if ((options & PACKET_READ_CHOMP_NEWLINE) &&
	    len && buffer[len-1] == '\n')
		len--;

190
	buffer[len] = 0;
Jeff King's avatar
Jeff King committed
191
	packet_trace(buffer, len, 0);
192 193
	return len;
}
194

195 196 197
static char *packet_read_line_generic(int fd,
				      char **src, size_t *src_len,
				      int *dst_len)
198
{
199 200
	int len = packet_read(fd, src, src_len,
			      packet_buffer, sizeof(packet_buffer),
201
			      PACKET_READ_CHOMP_NEWLINE);
202 203
	if (dst_len)
		*dst_len = len;
204
	return len ? packet_buffer : NULL;
205 206
}

207
char *packet_read_line(int fd, int *len_p)
208
{
209 210
	return packet_read_line_generic(fd, NULL, NULL, len_p);
}
211

212 213 214
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);
215
}