Commit 34bfb4b0 by Carlos Martín Nieto Committed by Vicent Marti

net,pkt: add chunked support

As we don't know the length of the message we want to send to the
other end, we send a chunk size before each message. In later
versions, sending the wants might benefit from batching the lines
together.

Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
parent eb07a4d1
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "common.h" #include "common.h"
#include "netops.h" #include "netops.h"
#include "posix.h"
void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, int fd) void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, int fd)
{ {
...@@ -138,6 +139,7 @@ int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags) ...@@ -138,6 +139,7 @@ int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags)
return off; return off;
} }
#ifdef GIT_WIN32 #ifdef GIT_WIN32
int gitno_close(GIT_SOCKET s) int gitno_close(GIT_SOCKET s)
{ {
...@@ -150,6 +152,20 @@ int gitno_close(GIT_SOCKET s) ...@@ -150,6 +152,20 @@ int gitno_close(GIT_SOCKET s)
} }
#endif #endif
int gitno_send_chunk_size(int s, size_t len)
{
char str[8] = {0};
int ret;
ret = p_snprintf(str, sizeof(str), "%zx", len);
if (ret >= (int) sizeof(str)) {
return git__throw(GIT_ESHORTBUFFER, "Your number is too fucking big");
}
return gitno_send(s, str, ret, 0 /* TODO: MSG_MORE */);
}
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) int gitno_select_in(gitno_buffer *buf, long int sec, long int usec)
{ {
fd_set fds; fd_set fds;
......
...@@ -28,6 +28,7 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons); ...@@ -28,6 +28,7 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons);
int gitno_connect(const char *host, const char *port); int gitno_connect(const char *host, const char *port);
int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags); int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags);
int gitno_close(GIT_SOCKET s); int gitno_close(GIT_SOCKET s);
int gitno_send_chunk_size(int s, size_t len);
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec); int gitno_select_in(gitno_buffer *buf, long int sec, long int usec);
int gitno_extract_host_and_port(char **host, char **port, const char *url, const char *default_port); int gitno_extract_host_and_port(char **host, char **port, const char *url, const char *default_port);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "util.h" #include "util.h"
#include "netops.h" #include "netops.h"
#include "posix.h" #include "posix.h"
#include "buffer.h"
#include <ctype.h> #include <ctype.h>
...@@ -261,18 +262,25 @@ void git_pkt_free(git_pkt *pkt) ...@@ -261,18 +262,25 @@ void git_pkt_free(git_pkt *pkt)
free(pkt); free(pkt);
} }
int git_pkt_send_flush(int s) int git_pkt_send_flush(int s, int chunked)
{ {
char flush[] = "0000"; char flush[] = "0000";
int error;
if (chunked) {
error = gitno_send_chunk_size(s, strlen(flush));
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send chunk size");
}
return gitno_send(s, flush, strlen(flush), 0); return gitno_send(s, flush, strlen(flush), 0);
} }
static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, int fd) static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, int fd, int chunked)
{ {
char capstr[20]; /* Longer than we need */ char capstr[20]; /* Longer than we need */
char oid[GIT_OID_HEXSZ +1] = {0}, *cmd; char oid[GIT_OID_HEXSZ +1] = {0}, *cmd;
int error, len; int error, len;
git_buf buf = GIT_BUF_INIT;
if (caps->ofs_delta) if (caps->ofs_delta)
strcpy(capstr, GIT_CAP_OFS_DELTA); strcpy(capstr, GIT_CAP_OFS_DELTA);
...@@ -283,9 +291,13 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, ...@@ -283,9 +291,13 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps,
return GIT_ENOMEM; return GIT_ENOMEM;
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
memset(cmd, 0x0, len + 1); git_buf_printf(&buf, "%04xwant %s%c%s\n", len, oid, 0, capstr);
p_snprintf(cmd, len + 1, "%04xwant %s%c%s\n", len, oid, 0, capstr); if (chunked) {
error = gitno_send(fd, cmd, len, 0); error = gitno_send_chunk_size(fd, len);
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send first want chunk size");
}
error = gitno_send(fd, git_buf_cstr(&buf), len, 0);
free(cmd); free(cmd);
return error; return error;
} }
...@@ -296,7 +308,7 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, ...@@ -296,7 +308,7 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps,
*/ */
#define WANT_PREFIX "0032want " #define WANT_PREFIX "0032want "
int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, int chunked)
{ {
unsigned int i = 0; unsigned int i = 0;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
...@@ -317,7 +329,7 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) ...@@ -317,7 +329,7 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
break; break;
} }
error = send_want_with_caps(refs->heads[i], caps, fd); error = send_want_with_caps(refs->heads[i], caps, fd, chunked);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want pkt with caps"); return git__rethrow(error, "Failed to send want pkt with caps");
/* Increase it here so it's correct whether we run this or not */ /* Increase it here so it's correct whether we run this or not */
...@@ -331,13 +343,17 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) ...@@ -331,13 +343,17 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
continue; continue;
git_oid_fmt(buf + strlen(WANT_PREFIX), &head->oid); git_oid_fmt(buf + strlen(WANT_PREFIX), &head->oid);
if (chunked) {
error = gitno_send_chunk_size(fd, strlen(buf));
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want chunk size");
}
error = gitno_send(fd, buf, strlen(buf), 0); error = gitno_send(fd, buf, strlen(buf), 0);
if (error < 0) { if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send want pkt"); return git__rethrow(error, "Failed to send want pkt");
} }
}
return git_pkt_send_flush(fd); return git_pkt_send_flush(fd, chunked);
} }
/* /*
...@@ -346,17 +362,29 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) ...@@ -346,17 +362,29 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd)
*/ */
#define HAVE_PREFIX "0032have " #define HAVE_PREFIX "0032have "
int git_pkt_send_have(git_oid *oid, int fd) int git_pkt_send_have(git_oid *oid, int fd, int chunked)
{ {
char buf[] = "0032have 0000000000000000000000000000000000000000\n"; char buf[] = "0032have 0000000000000000000000000000000000000000\n";
int error;
if (chunked) {
error = gitno_send_chunk_size(fd, strlen(buf));
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send chunk size");
}
git_oid_fmt(buf + strlen(HAVE_PREFIX), oid); git_oid_fmt(buf + strlen(HAVE_PREFIX), oid);
return gitno_send(fd, buf, strlen(buf), 0); return gitno_send(fd, buf, strlen(buf), 0);
} }
int git_pkt_send_done(int fd) int git_pkt_send_done(int fd, int chunked)
{ {
char buf[] = "0009done\n"; char buf[] = "0009done\n";
int error;
if (chunked) {
error = gitno_send_chunk_size(fd, strlen(buf));
if (error < GIT_SUCCESS)
return git__rethrow(error, "Failed to send chunk size");
}
return gitno_send(fd, buf, strlen(buf), 0); return gitno_send(fd, buf, strlen(buf), 0);
} }
...@@ -63,10 +63,10 @@ typedef struct { ...@@ -63,10 +63,10 @@ typedef struct {
} git_pkt_comment; } git_pkt_comment;
int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len);
int git_pkt_send_flush(int s); int git_pkt_send_flush(int s, int chunked);
int git_pkt_send_done(int s); int git_pkt_send_done(int s, int chunked);
int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd); int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd, int chunked);
int git_pkt_send_have(git_oid *oid, int fd); int git_pkt_send_have(git_oid *oid, int fd, int chunked);
void git_pkt_free(git_pkt *pkt); void git_pkt_free(git_pkt *pkt);
#endif #endif
...@@ -269,14 +269,14 @@ static int git_send_wants(git_transport *transport, git_headarray *array) ...@@ -269,14 +269,14 @@ static int git_send_wants(git_transport *transport, git_headarray *array)
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
return git_pkt_send_wants(array, &t->caps, t->socket); return git_pkt_send_wants(array, &t->caps, t->socket, 0);
} }
static int git_send_have(git_transport *transport, git_oid *oid) static int git_send_have(git_transport *transport, git_oid *oid)
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
return git_pkt_send_have(oid, t->socket); return git_pkt_send_have(oid, t->socket, 0);
} }
static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *GIT_UNUSED(list)) static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *GIT_UNUSED(list))
...@@ -333,12 +333,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -333,12 +333,12 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
*/ */
i = 0; i = 0;
while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) { while ((error = git_revwalk_next(&oid, walk)) == GIT_SUCCESS) {
error = git_pkt_send_have(&oid, t->socket); error = git_pkt_send_have(&oid, t->socket, 1);
i++; i++;
if (i % 20 == 0) { if (i % 20 == 0) {
const char *ptr = buf.data, *line_end; const char *ptr = buf.data, *line_end;
git_pkt *pkt; git_pkt *pkt;
git_pkt_send_flush(t->socket); git_pkt_send_flush(t->socket, 0);
while (1) { while (1) {
/* Wait for max. 1 second */ /* Wait for max. 1 second */
error = gitno_select_in(&buf, 1, 0); error = gitno_select_in(&buf, 1, 0);
...@@ -384,8 +384,8 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g ...@@ -384,8 +384,8 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g
error = GIT_SUCCESS; error = GIT_SUCCESS;
done: done:
git_pkt_send_flush(t->socket); git_pkt_send_flush(t->socket, 0);
git_pkt_send_done(t->socket); git_pkt_send_done(t->socket, 0);
cleanup: cleanup:
git_revwalk_free(walk); git_revwalk_free(walk);
...@@ -396,14 +396,14 @@ static int git_send_flush(git_transport *transport) ...@@ -396,14 +396,14 @@ static int git_send_flush(git_transport *transport)
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
return git_pkt_send_flush(t->socket); return git_pkt_send_flush(t->socket, 1);
} }
static int git_send_done(git_transport *transport) static int git_send_done(git_transport *transport)
{ {
transport_git *t = (transport_git *) transport; transport_git *t = (transport_git *) transport;
return git_pkt_send_done(t->socket); return git_pkt_send_done(t->socket, 1);
} }
static int store_pack(char **out, gitno_buffer *buf, git_repository *repo) static int store_pack(char **out, gitno_buffer *buf, git_repository *repo)
...@@ -503,8 +503,9 @@ static int git_close(git_transport *transport) ...@@ -503,8 +503,9 @@ static int git_close(git_transport *transport)
int error; int error;
/* Can't do anything if there's an error, so don't bother checking */ /* Can't do anything if there's an error, so don't bother checking */
git_pkt_send_flush(t->socket); git_pkt_send_flush(t->socket, 0);
error = gitno_close(t->socket); error = gitno_close(t->socket);
if (error < 0) if (error < 0)
error = git__throw(GIT_EOSERR, "Failed to close socket"); error = git__throw(GIT_EOSERR, "Failed to close socket");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment