From 4625003149d02227f981b53101c7e6be12226382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 27 May 2014 17:51:25 +0200 Subject: server: handle negotiation lines A bit of scaffolding for handling the lines from the client telling us about its commits. --- src/server.c | 46 ++++++++++++++++++++++++++++++++++++ src/server.h | 6 +++++ tests/network/protocol/negotiation.c | 40 +++++++++++++++++++++++++++++++ tests/network/server.c | 33 ++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 tests/network/protocol/negotiation.c diff --git a/src/server.c b/src/server.c index 047f8d22e..766726798 100644 --- a/src/server.c +++ b/src/server.c @@ -29,6 +29,8 @@ void git_server_free(git_server *server) if (server == NULL) return; + git_array_clear(server->wants); + git_array_clear(server->common); git__free(server->path); git__free(server); } @@ -98,6 +100,50 @@ cleanup: return error; } +int git_server__negotiation(git_server *server, git_pkt *_pkt) +{ + git_oid *id, *have_id; + git_pkt_have_want *pkt; + git_odb *odb = NULL; + int error; + + if (_pkt->type != GIT_PKT_HAVE && _pkt->type != GIT_PKT_WANT) { + giterr_set(GITERR_NET, "invalid pkt for negotiation"); + return -1; + } + + pkt = (git_pkt_have_want *) _pkt; + + if (pkt->type == GIT_PKT_WANT) { + id = git_array_alloc(server->wants); + GITERR_CHECK_ALLOC(id); + + git_oid_cpy(id, &pkt->id); + return 0; + } + + /* we know it's a 'have', so we check to see if it's common */ + have_id = &pkt->id; + if ((error = git_repository_odb(&odb, server->repo)) < 0) + return error; + + if ((error = git_odb_exists(odb, have_id)) < 0) + goto cleanup; + + if (error == 1) { + error = 0; + id = git_array_alloc(server->common); + GITERR_CHECK_ALLOC(id); + + git_oid_cpy(id, &pkt->id); + } + +cleanup: + git_odb_free(odb); + + return error; +} + int git_server_run(git_server *server) { /* 65535 is the max size of a pkt frame */ diff --git a/src/server.h b/src/server.h index eff5dd4ec..943eaa2cd 100644 --- a/src/server.h +++ b/src/server.h @@ -9,6 +9,9 @@ #include "common.h" #include "transports/smart.h" +#include "array.h" + +typedef git_array_t(git_oid) git_oid_array; struct git_server { enum git_request_type type; @@ -16,12 +19,15 @@ struct git_server { gitno_socket s; int rpc; char *path; + git_oid_array common; + git_oid_array wants; }; extern int git_server_new(git_server **out, git_repository *repo, int fd); extern void git_server_free(git_server *server); extern int git_server__handle_request(git_server *server, git_pkt *pkt); extern int git_server__ls(git_buf *out, git_server *server); +extern int git_server__negotiation(git_server *server, git_pkt *_pkt); #endif diff --git a/tests/network/protocol/negotiation.c b/tests/network/protocol/negotiation.c new file mode 100644 index 000000000..0fa76a257 --- /dev/null +++ b/tests/network/protocol/negotiation.c @@ -0,0 +1,40 @@ +#include "clar_libgit2.h" +#include "transports/smart.h" + +static git_pkt *pkt; + +void test_network_protocol_negotiation__cleanup(void) +{ + git_pkt_free(pkt); + pkt = NULL; +} + +void test_network_protocol_negotiation__have(void) +{ + const char buf[] = "0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n"; + const char *rest; + git_oid id; + git_pkt_have_want *ppkt; + + git_oid_fromstr(&id, "7e47fe2bd8d01d481f44d7af0531bd93d3b21c01"); + + cl_git_pass(git_pkt_parse_line(&pkt, buf, &rest, sizeof(buf))); + cl_assert_equal_i(GIT_PKT_HAVE, pkt->type); + ppkt = (git_pkt_have_want *) pkt; + cl_assert(!git_oid_cmp(&id, &ppkt->id)); +} + +void test_network_protocol_negotiation__want(void) +{ + const char buf[] = "0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n"; + const char *rest; + git_oid id; + git_pkt_have_want *ppkt; + + git_oid_fromstr(&id, "7e47fe2bd8d01d481f44d7af0531bd93d3b21c01"); + + cl_git_pass(git_pkt_parse_line(&pkt, buf, &rest, sizeof(buf))); + cl_assert_equal_i(GIT_PKT_WANT, pkt->type); + ppkt = (git_pkt_have_want *) pkt; + cl_assert(!git_oid_cmp(&id, &ppkt->id)); +} diff --git a/tests/network/server.c b/tests/network/server.c index 41319552d..4fc81cb23 100644 --- a/tests/network/server.c +++ b/tests/network/server.c @@ -81,3 +81,36 @@ void test_network_server__upload_pack_ls(void) git_buf_free(&listing); } + +void test_network_server__want(void) +{ + const char buf[] = "0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n"; + const char *rest; + + cl_git_pass(git_pkt_parse_line(&g_pkt, buf, &rest, sizeof(buf))); + cl_git_pass(git_server_new(&g_server, g_repo, 0)); + cl_git_pass(git_server__negotiation(g_server, g_pkt)); + cl_assert_equal_i(1, git_array_size(g_server->wants)); +} + +void test_network_server__have_no_common(void) +{ + const char buf[] = "0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n"; + const char *rest; + + cl_git_pass(git_pkt_parse_line(&g_pkt, buf, &rest, sizeof(buf))); + cl_git_pass(git_server_new(&g_server, g_repo, 0)); + cl_git_pass(git_server__negotiation(g_server, g_pkt)); + cl_assert_equal_i(0, git_array_size(g_server->common)); +} + +void test_network_server__have_common(void) +{ + const char buf[] = "0032have a65fedf39aefe402d3bb6e24df4d4f5fe4547750\n"; + const char *rest; + + cl_git_pass(git_pkt_parse_line(&g_pkt, buf, &rest, sizeof(buf))); + cl_git_pass(git_server_new(&g_server, g_repo, 0)); + cl_git_pass(git_server__negotiation(g_server, g_pkt)); + cl_assert_equal_i(1, git_array_size(g_server->common)); +} -- cgit v1.2.1