diff options
| -rw-r--r-- | src/fetch.c | 78 | ||||
| -rw-r--r-- | src/pkt.c | 18 | ||||
| -rw-r--r-- | src/transport.h | 5 | ||||
| -rw-r--r-- | src/transports/git.c | 10 | 
4 files changed, 85 insertions, 26 deletions
diff --git a/src/fetch.c b/src/fetch.c index 6a726417c..4880772d5 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -75,13 +75,24 @@ static int filter_wants(git_remote *remote)  }  /* Wait until we get an ack from the */ -static int recv_pkt(gitno_buffer *buf) +static int recv_pkt(git_pkt **out, gitno_buffer *buf)  { -	const char *ptr = buf->data, *line_end; +	const char *ptr = buf->data, *line_end = ptr;  	git_pkt *pkt; -	int pkt_type, error; +	int pkt_type, error = 0;  	do { +		if (buf->offset > 0) +			error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); +		else +			error = GIT_EBUFS; + +		if (error == 0) +			break; /* return the pkt */ + +		if (error < 0 && error != GIT_EBUFS) +			return -1; +  		/* Wait for max. 1 second */  		if ((error = gitno_select_in(buf, 1, 0)) < 0) {  			return -1; @@ -97,21 +108,41 @@ static int recv_pkt(gitno_buffer *buf)  		if ((error = gitno_recv(buf)) < 0)  			return -1; - -		error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); -		if (error == GIT_EBUFS) -			continue; -		if (error < 0) -			return -1;  	} while (error);  	gitno_consume(buf, line_end);  	pkt_type = pkt->type; -	git__free(pkt); +	if (out != NULL) +		*out = pkt; +	else +		git__free(pkt);  	return pkt_type;  } +static int store_common(git_transport *t) +{ +	int done = 0; +	git_pkt *pkt = NULL; +	gitno_buffer *buf = &t->buffer; + +	do { +		if (recv_pkt(&pkt, buf) < 0) +			return -1; + +		if (pkt->type == GIT_PKT_ACK) { +			if (git_vector_insert(&t->common, pkt) < 0) +				return -1; +		} else { +			git__free(pkt); +			return 0; +		} + +	} while (1); + +	return 0; +} +  /*   * In this first version, we push all our refs in and start sending   * them out. When we get an ACK we hide that commit and continue @@ -169,18 +200,25 @@ int git_fetch_negotiate(git_remote *remote)  				goto on_error;  			git_buf_clear(&data); -			pkt_type = recv_pkt(buf); - -			if (pkt_type == GIT_PKT_ACK) { -				break; -			} else if (pkt_type == GIT_PKT_NAK) { -				continue; +			if (t->caps.multi_ack) { +				if (store_common(t) < 0) +					goto on_error;  			} else { -				giterr_set(GITERR_NET, "Unexpected pkt type"); -				goto on_error; +				pkt_type = recv_pkt(NULL, buf); + +				if (pkt_type == GIT_PKT_ACK) { +					break; +				} else if (pkt_type == GIT_PKT_NAK) { +					continue; +				} else { +					giterr_set(GITERR_NET, "Unexpected pkt type"); +					goto on_error; +				}  			} -  		} + +		if (t->common.length > 0) +			break;  	}  	if (error < 0 && error != GIT_REVWALKOVER) @@ -195,7 +233,7 @@ int git_fetch_negotiate(git_remote *remote)  	git_revwalk_free(walk);  	/* Now let's eat up whatever the server gives us */ -	pkt_type = recv_pkt(buf); +	pkt_type = recv_pkt(NULL, buf);  	if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {  		giterr_set(GITERR_NET, "Unexpected pkt type");  		return -1; @@ -283,20 +283,28 @@ int git_pkt_buffer_flush(git_buf *buf)  static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)  { -	char capstr[20]; +	git_buf str = GIT_BUF_INIT;  	char oid[GIT_OID_HEXSZ +1] = {0};  	unsigned int len;  	if (caps->ofs_delta) -		strncpy(capstr, GIT_CAP_OFS_DELTA, sizeof(capstr)); +		git_buf_puts(&str, GIT_CAP_OFS_DELTA " "); + +	if (caps->multi_ack) +		git_buf_puts(&str, GIT_CAP_MULTI_ACK " "); + +	if (git_buf_oom(&str)) +		return -1;  	len = (unsigned int)  		(strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + -		 strlen(capstr) + 1 /* LF */); +		 git_buf_len(&str) + 1 /* LF */);  	git_buf_grow(buf, git_buf_len(buf) + len); -  	git_oid_fmt(oid, &head->oid); -	return git_buf_printf(buf, "%04xwant %s %s\n", len, oid, capstr); +	git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str)); +	git_buf_free(&str); + +	return git_buf_oom(buf);  }  /* diff --git a/src/transport.h b/src/transport.h index 09afb0c72..3ef36f49f 100644 --- a/src/transport.h +++ b/src/transport.h @@ -20,10 +20,12 @@  #define GIT_CAP_OFS_DELTA "ofs-delta" +#define GIT_CAP_MULTI_ACK "multi_ack"  typedef struct git_transport_caps {  	int common:1, -		ofs_delta:1; +		ofs_delta:1, +		multi_ack: 1;  } git_transport_caps;  #ifdef GIT_SSL @@ -76,6 +78,7 @@ struct git_transport {  #ifdef GIT_SSL  	struct gitno_ssl ssl;  #endif +	git_vector common;  	gitno_buffer buffer;  	GIT_SOCKET socket;  	git_transport_caps caps; diff --git a/src/transports/git.c b/src/transports/git.c index 4fcde2d37..f5cdfe7a4 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -179,6 +179,12 @@ static int detect_caps(transport_git *t)  			continue;  		} +		if(!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) { +			caps->common = caps->multi_ack = 1; +			ptr += strlen(GIT_CAP_MULTI_ACK); +			continue; +		} +  		/* We don't know this capability, so skip it */  		ptr = strchr(ptr, ' ');  	} @@ -303,6 +309,10 @@ int git_transport_git(git_transport **out)  	GITERR_CHECK_ALLOC(t);  	memset(t, 0x0, sizeof(transport_git)); +	if (git_vector_init(&t->parent.common, 8, NULL)) { +		git__free(t); +		return -1; +	}  	t->parent.connect = git_connect;  	t->parent.negotiation_step = git_negotiation_step;  | 
