summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-05-27 17:51:25 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-05-27 17:51:25 +0200
commit4625003149d02227f981b53101c7e6be12226382 (patch)
treeac1a86f48c69d4da0ec14adc4860f0be7ab422ec
parent16b20526e1580f50b29f0dae87a30ebefe0a3c89 (diff)
downloadlibgit2-cmn/server.tar.gz
server: handle negotiation linescmn/server
A bit of scaffolding for handling the lines from the client telling us about its commits.
-rw-r--r--src/server.c46
-rw-r--r--src/server.h6
-rw-r--r--tests/network/protocol/negotiation.c40
-rw-r--r--tests/network/server.c33
4 files changed, 125 insertions, 0 deletions
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));
+}