git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[WIP 07/15] connect: convert get_remote_heads to use struct packet_reader

From
BWBrandon Williams <bmwill@google.com>
Date
Dec 4, 2017, 23:58 UTC
Message-ID
<20171204235823.63299-8-bmwill@google.com>
In-Reply-To
<20171204235823.63299-1-bmwill@google.com>

In order to allow for better control flow when protocol_v2 is introduced convert 'get_remote_heads()' to use 'struct packet_reader' to read packet lines. This enables a client to be able to peek the first line of a server's response (without consuming it) in order to determine the protocol version its speaking and then passing control to the appropriate handler.

This is needed because the initial response from a server speaking protocol_v0 includes the first ref, while subsequent protocol versions respond with a version line. We want to be able to read this first line without consuming the first ref sent in the protocol_v0 case so that the protocol version the server is speaking can be determined outside of 'get_remote_heads()' in a future patch.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 connect.c | 125 +++++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 70 insertions(+), 55 deletions(-)
diff --git a/connect.c b/connect.c
index 7fbd396b3..f79ea9179 100644
--- a/connect.c
+++ b/connect.c
@@ -48,6 +48,12 @@ int check_ref_type(const struct ref *ref, int flags)
 
 static void die_initial_contact(int unexpected)
 {
+	/*
+	 * A hang-up after seeing some response from the other end
+	 * means that it is unexpected, as we know the other end is
+	 * willing to talk to us.  A hang-up before seeing any
+	 * response does not necessarily mean an ACL problem, though.
+	 */
 	if (unexpected)
 		die(_("The remote end hung up upon initial contact"));
 	else
@@ -56,6 +62,41 @@ static void die_initial_contact(int unexpected)
 		      "and the repository exists."));
 }
 
+static enum protocol_version discover_version(struct packet_reader *reader)
+{
+	enum protocol_version version = protocol_unknown_version;
+
+	/*
+	 * Peek the first line of the server's response to
+	 * determine the protocol version the server is speaking.
+	 */
+	switch (packet_reader_peek(reader)) {
+	case PACKET_READ_ERROR:
+		die_initial_contact(0);
+	case PACKET_READ_FLUSH:
+	case PACKET_READ_DELIM:
+		version = protocol_v0;
+		break;
+	case PACKET_READ_NORMAL:
+		version = determine_protocol_version_client(reader->line);
+		break;
+	}
+
+	/* Maybe process capabilities here, at least for v2 */
+	switch (version) {
+	case protocol_v1:
+		/* Read the peeked version line */
+		packet_reader_read(reader);
+		break;
+	case protocol_v0:
+		break;
+	case protocol_unknown_version:
+		BUG("ERROR");
+	}
+
+	return version;
+}
+
 static void parse_one_symref_info(struct string_list *symref, const char *val, int len)
 {
 	char *sym, *target;
@@ -109,44 +150,10 @@ static void annotate_refs_with_symref_info(struct ref *ref)
 	string_list_clear(&symref, 0);
 }
 
-/*
- * Read one line of a server's ref advertisement into packet_buffer.
- */
-static int read_remote_ref(int in, char **src_buf, size_t *src_len,
-			   int *responded)
-{
-	int len = packet_read(in, src_buf, src_len,
-			      packet_buffer, sizeof(packet_buffer),
-			      PACKET_READ_GENTLE_ON_EOF |
-			      PACKET_READ_CHOMP_NEWLINE);
-	const char *arg;
-	if (len < 0)
-		die_initial_contact(*responded);
-	if (len > 4 && skip_prefix(packet_buffer, "ERR ", &arg))
-		die("remote error: %s", arg);
-
-	*responded = 1;
-
-	return len;
-}
-
-#define EXPECTING_PROTOCOL_VERSION 0
-#define EXPECTING_FIRST_REF 1
-#define EXPECTING_REF 2
-#define EXPECTING_SHALLOW 3
-
-/* Returns 1 if packet_buffer is a protocol version pkt-line, 0 otherwise. */
-static int process_protocol_version(void)
-{
-	switch (determine_protocol_version_client(packet_buffer)) {
-	case protocol_v1:
-		return 1;
-	case protocol_v0:
-		return 0;
-	default:
-		die("server is speaking an unknown protocol");
-	}
-}
+#define EXPECTING_FIRST_REF 0
+#define EXPECTING_REF 1
+#define EXPECTING_SHALLOW 2
+#define EXPECTING_DONE 3
 
 static void process_capabilities(int *len)
 {
@@ -230,28 +237,34 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
 			      struct oid_array *shallow_points)
 {
 	struct ref **orig_list = list;
+	int len = 0;
+	int state = EXPECTING_FIRST_REF;
+	struct packet_reader reader;
+	const char *arg;
 
-	/*
-	 * A hang-up after seeing some response from the other end
-	 * means that it is unexpected, as we know the other end is
-	 * willing to talk to us.  A hang-up before seeing any
-	 * response does not necessarily mean an ACL problem, though.
-	 */
-	int responded = 0;
-	int len;
-	int state = EXPECTING_PROTOCOL_VERSION;
+	packet_reader_init(&reader, in, src_buf, src_len);
+
+	discover_version(&reader);
 
 	*list = NULL;
 
-	while ((len = read_remote_ref(in, &src_buf, &src_len, &responded))) {
+	while (state != EXPECTING_DONE) {
+		switch (packet_reader_read(&reader)) {
+		case PACKET_READ_ERROR:
+			die_initial_contact(1);
+		case PACKET_READ_NORMAL:
+			len = reader.pktlen;
+			if (len > 4 && skip_prefix(packet_buffer, "ERR ", &arg))
+				die("remote error: %s", arg);
+			break;
+		case PACKET_READ_FLUSH:
+			state = EXPECTING_DONE;
+			break;
+		case PACKET_READ_DELIM:
+			die("invalid packet\n");
+		}
+
 		switch (state) {
-		case EXPECTING_PROTOCOL_VERSION:
-			if (process_protocol_version()) {
-				state = EXPECTING_FIRST_REF;
-				break;
-			}
-			state = EXPECTING_FIRST_REF;
-			/* fallthrough */
 		case EXPECTING_FIRST_REF:
 			process_capabilities(&len);
 			if (process_dummy_ref()) {
@@ -269,6 +282,8 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
 			if (process_shallow(len, shallow_points))
 				break;
 			die("protocol error: unexpected '%s'", packet_buffer);
+		case EXPECTING_DONE:
+			break;
 		default:
 			die("unexpected state %d", state);
 		}
-- 
2.15.1.424.g9478a66081-goog
Previous: Brandon WilliamsNext: Junio C Hamano
Message 26 of 47 in “[RFC] protocol version 2”
  1. Brandon WilliamsOct 20, 2017
  2. Junio C HamanoOct 24, 2017
  3. Brandon WilliamsOct 24, 2017
  4. Junio C HamanoOct 25, 2017
  5. Junio C HamanoOct 26, 2017
  6. Derrick StoleeOct 25, 2017
  7. Brandon WilliamsOct 25, 2017
  8. Philip OakleyOct 28, 2017
  9. Brandon WilliamsOct 31, 2017
  10. Jonathan TanNov 10, 2017
  11. 00/15 protocol version 2Brandon Williams, Dec 4, 2017
  12. 01/15 pkt-line: introduce packet_read_with_statusBrandon Williams, Dec 4, 2017
  13. Stefan BellerDec 7, 2017
  14. Brandon WilliamsDec 8, 2017
  15. 02/15 pkt-line: introduce struct packet_readerBrandon Williams, Dec 4, 2017
  16. Stefan BellerDec 7, 2017
  17. Brandon WilliamsDec 8, 2017
  18. 03/15 pkt-line: add delim packet supportBrandon Williams, Dec 4, 2017
  19. Stefan BellerDec 7, 2017
  20. Brandon WilliamsDec 8, 2017
  21. 04/15 upload-pack: convert to a builtinBrandon Williams, Dec 4, 2017
  22. Junio C HamanoDec 6, 2017
  23. Johannes SchindelinDec 7, 2017
  24. Junio C HamanoDec 8, 2017
  25. Brandon WilliamsDec 8, 2017
  26. 07/15 connect: convert get_remote_heads to use struct packet_readerBrandon Williams, Dec 4, 2017
  27. Junio C HamanoDec 6, 2017
  28. Brandon WilliamsDec 8, 2017
  29. 06/15 transport: use get_refs_via_connect to get refsBrandon Williams, Dec 4, 2017
  30. Junio C HamanoDec 6, 2017
  31. Brandon WilliamsDec 7, 2017
  32. 08/15 connect: discover protocol version outside of get_remote_headsBrandon Williams, Dec 4, 2017
  33. Junio C HamanoDec 7, 2017
  34. Brandon WilliamsDec 7, 2017
  35. Junio C HamanoDec 7, 2017
  36. Brandon WilliamsDec 8, 2017
  37. 13/15 connect: request remote refs using v2Brandon Williams, Dec 4, 2017
  38. 09/15 transport: store protocol versionBrandon Williams, Dec 4, 2017
  39. 11/15 serve: introduce git-serveBrandon Williams, Dec 4, 2017
  40. Junio C HamanoDec 7, 2017
  41. Brandon WilliamsDec 8, 2017
  42. 12/15 ls-refs: introduce ls-refs server commandBrandon Williams, Dec 4, 2017
  43. Philip OakleyDec 13, 2017
  44. 15/15 fetch-pack: perform a fetch using v2Brandon Williams, Dec 4, 2017
  45. 14/15 upload_pack: introduce fetch server commandBrandon Williams, Dec 4, 2017
  46. 10/15 protocol: introduce enum protocol_version value protocol_v2Brandon Williams, Dec 4, 2017
  47. 05/15 upload-pack: factor out processing linesBrandon Williams, Dec 4, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.