From a95aeb489f32fa7e570ecad12fc236f0a0e237a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 30 Sep 2011 16:55:05 +0200 Subject: [PATCH 1/4] Use git_buf in the git request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is clearer and sidesteps the issue of what the return value of snprintf is on the particular OS we're running on. Signed-off-by: Carlos Martín Nieto --- src/transport_git.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/transport_git.c b/src/transport_git.c index bcc612b43..a1c54ca83 100644 --- a/src/transport_git.c +++ b/src/transport_git.c @@ -35,10 +35,11 @@ typedef struct { */ static int gen_proto(char **out, int *outlen, const char *cmd, const char *url) { - char *delim, *repo, *ptr; + char *delim, *repo; char default_command[] = "git-upload-pack"; char host[] = "host="; int len; + git_buf buf = GIT_BUF_INIT; delim = strchr(url, '/'); if (delim == NULL) @@ -53,17 +54,16 @@ static int gen_proto(char **out, int *outlen, const char *cmd, const char *url) if (cmd == NULL) cmd = default_command; - len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 2; + len = 4 + strlen(cmd) + 1 + strlen(repo) + 1 + strlen(host) + (delim - url) + 1 + 1; - *out = git__malloc(len); - if (*out == NULL) - return GIT_ENOMEM; + git_buf_grow(&buf, len); - *outlen = len - 1; - ptr = *out; - memset(ptr, 0x0, len); - /* We expect the return value to be > len - 1 so don't bother checking it */ - snprintf(ptr, len -1, "%04x%s %s%c%s%s", len - 1, cmd, repo, 0, host, url); + git_buf_printf(&buf, "%04x%s %s%c%s", len, cmd, repo, 0, host); + git_buf_put(&buf, url, delim - url); + git_buf_putc(&buf, '\0'); + + *outlen = len; + *out = buf.ptr; return GIT_SUCCESS; } From ccc9872d4df7ca6cd44f777c0600c4b1fab0f9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 30 Sep 2011 17:21:30 +0200 Subject: [PATCH 2/4] Initialise the winsock DLL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows wants us to initialise the networking DLL before we're allowed to send data through a socket. Call WSASetup and WSACleanup if GIT_WIN32 is defined. Signed-off-by: Carlos Martín Nieto --- src/netops.c | 12 +++++++++--- src/netops.h | 4 ++-- src/transport-http.c | 21 ++++++++++++++++++++- src/transport_git.c | 24 +++++++++++++++++++++--- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/netops.c b/src/netops.c index 54aaa4677..c8fe37645 100644 --- a/src/netops.c +++ b/src/netops.c @@ -77,7 +77,7 @@ int gitno_connect(const char *host, const char *port) struct addrinfo *info, *p; struct addrinfo hints; int ret, error = GIT_SUCCESS; - int s; + GIT_SOCKET s; memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; @@ -92,7 +92,11 @@ int gitno_connect(const char *host, const char *port) for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); +#ifdef GIT_WIN32 + if (s == INVALID_SOCKET) { +#else if (s < 0) { +#endif error = GIT_EOSERR; goto cleanup; } @@ -109,19 +113,21 @@ int gitno_connect(const char *host, const char *port) } /* Oops, we couldn't connect to any address */ - error = GIT_EOSERR; + error = git__throw(GIT_EOSERR, "Failed to connect: %s", strerror(errno)); cleanup: freeaddrinfo(info); return error; } -int gitno_send(int s, const char *msg, size_t len, int flags) +int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags) { int ret; size_t off = 0; while (off < len) { + errno = 0; + ret = send(s, msg + off, len - off, flags); if (ret < 0) return git__throw(GIT_EOSERR, "Error sending data: %s", strerror(errno)); diff --git a/src/netops.h b/src/netops.h index 0d962ef61..b0425ae76 100644 --- a/src/netops.h +++ b/src/netops.h @@ -10,7 +10,7 @@ #ifndef GIT_WIN32 typedef int GIT_SOCKET; #else -typedef unsigned int GIT_SOCKET; +typedef SOCKET GIT_SOCKET; #endif typedef struct gitno_buffer { @@ -26,7 +26,7 @@ void gitno_consume(gitno_buffer *buf, const char *ptr); void gitno_consume_n(gitno_buffer *buf, size_t cons); int gitno_connect(const char *host, const char *port); -int gitno_send(int 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_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); diff --git a/src/transport-http.c b/src/transport-http.c index 70086adea..3ee4025f8 100644 --- a/src/transport-http.c +++ b/src/transport-http.c @@ -52,6 +52,9 @@ typedef struct { enum last_cb last_cb; char *content_type; char *service; +#ifdef GIT_WIN32 + WSADATA wsd; +#endif } transport_http; static int gen_request(git_buf *buf, const char *url, const char *host, const char *service) @@ -76,7 +79,8 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch static int do_connect(transport_http *t, const char *service) { git_buf request = GIT_BUF_INIT; - int s = -1, error; + int error; + int s; const char *url, *prefix; char *host = NULL, *port = NULL; @@ -362,6 +366,10 @@ static int http_close(git_transport *transport) if (error < 0) return git__throw(GIT_EOSERR, "Failed to close the socket: %s", strerror(errno)); +#ifdef GIT_WIN32 + WSACleanup(); +#endif + return GIT_SUCCESS; } @@ -388,6 +396,9 @@ static void http_free(git_transport *transport) int git_transport_http(git_transport **out) { transport_http *t; +#ifdef GIT_WIN32 + int ret; +#endif t = git__malloc(sizeof(transport_http)); if (t == NULL) @@ -402,5 +413,13 @@ int git_transport_http(git_transport **out) *out = (git_transport *) t; +#ifdef GIT_WIN32 + ret = WSAStartup(MAKEWORD(2,2), &t->wsd); + if (ret != 0) { + http_free(*out); + return git__throw(GIT_EOSERR, "Winsock init failed"); + } +#endif + return GIT_SUCCESS; } diff --git a/src/transport_git.c b/src/transport_git.c index a1c54ca83..42503e1c9 100644 --- a/src/transport_git.c +++ b/src/transport_git.c @@ -22,10 +22,13 @@ typedef struct { git_transport parent; - int socket; + GIT_SOCKET socket; git_vector refs; git_remote_head **heads; git_transport_caps caps; +#ifdef GIT_WIN32 + WSADATA wsd; +#endif } transport_git; /* @@ -68,7 +71,7 @@ static int gen_proto(char **out, int *outlen, const char *cmd, const char *url) return GIT_SUCCESS; } -static int send_request(int s, const char *cmd, const char *url) +static int send_request(GIT_SOCKET s, const char *cmd, const char *url) { int error, len; char *msg = NULL; @@ -91,7 +94,7 @@ cleanup: */ static int do_connect(transport_git *t, const char *url) { - int s = -1; + GIT_SOCKET s; char *host, *port; const char prefix[] = "git://"; int error, connected = 0; @@ -525,6 +528,10 @@ static void git_free(git_transport *transport) git_pkt_free(p); } +#ifdef GIT_WIN32 + WSACleanup(); +#endif + git_vector_free(refs); free(t->heads); free(t->parent.url); @@ -534,6 +541,9 @@ static void git_free(git_transport *transport) int git_transport_git(git_transport **out) { transport_git *t; +#ifdef GIT_WIN32 + int ret; +#endif t = git__malloc(sizeof(transport_git)); if (t == NULL) @@ -554,5 +564,13 @@ int git_transport_git(git_transport **out) *out = (git_transport *) t; +#ifdef GIT_WIN32 + ret = WSAStartup(MAKEWORD(2,2), &t->wsd); + if (ret != 0) { + git_free(*out); + return git__throw(GIT_EOSERR, "Winsock init failed"); + } +#endif + return GIT_SUCCESS; } From a28889198cf9565944aa0ff983459c6bf6eec311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 30 Sep 2011 18:35:33 +0200 Subject: [PATCH 3/4] local transport: don't segfault on wrong URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit memset the structure on initialisation and don't try to dereference the vector with the heads if we didn't find a repository. Signed-off-by: Carlos Martín Nieto --- src/transport_local.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/transport_local.c b/src/transport_local.c index 4975af9ad..7e932f846 100644 --- a/src/transport_local.c +++ b/src/transport_local.c @@ -201,16 +201,19 @@ static void local_free(git_transport *transport) unsigned int i; transport_local *t = (transport_local *) transport; git_vector *vec = t->refs; + git_remote_head *h; assert(transport); - for (i = 0; i < vec->length; ++i) { - git_remote_head *h = git_vector_get(vec, i); - free(h->name); - free(h); + if (t->refs != NULL) { + git_vector_foreach (vec, i, h) { + free(h->name); + free(h); + } + git_vector_free(vec); + free(vec); } - git_vector_free(vec); - free(vec); + git_repository_free(t->repo); free(t->parent.url); free(t); @@ -228,6 +231,8 @@ int git_transport_local(git_transport **out) if (t == NULL) return GIT_ENOMEM; + memset(t, 0x0, sizeof(transport_local)); + t->parent.connect = local_connect; t->parent.ls = local_ls; t->parent.send_wants = local_send_wants; From bad53552e539e58b76c4fcf4902686534f8a2678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 30 Sep 2011 23:48:27 +0200 Subject: [PATCH 4/4] netops: abstract away socket closing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Winsock wants us to use closesocket() instead of close(), so introduce the gitno_close function, which does the right thing. Signed-off-by: Carlos Martín Nieto --- src/netops.c | 12 ++++++++++++ src/netops.h | 1 + src/transport-http.c | 2 +- src/transport_git.c | 13 ++++++------- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/netops.c b/src/netops.c index c8fe37645..7d8a7b28c 100644 --- a/src/netops.c +++ b/src/netops.c @@ -138,6 +138,18 @@ int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags) return off; } +#ifdef GIT_WIN32 +int gitno_close(GIT_SOCKET s) +{ + return closesocket(s) == SOCKET_ERROR ? -1 : 0; +} +#else +int gitno_close(GIT_SOCKET s) +{ + return close(s); +} +#endif + int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) { fd_set fds; diff --git a/src/netops.h b/src/netops.h index b0425ae76..203df85af 100644 --- a/src/netops.h +++ b/src/netops.h @@ -27,6 +27,7 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons); 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_close(GIT_SOCKET s); 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); diff --git a/src/transport-http.c b/src/transport-http.c index 3ee4025f8..1da56e11f 100644 --- a/src/transport-http.c +++ b/src/transport-http.c @@ -362,7 +362,7 @@ static int http_close(git_transport *transport) transport_http *t = (transport_http *) transport; int error; - error = close(t->socket); + error = gitno_close(t->socket); if (error < 0) return git__throw(GIT_EOSERR, "Failed to close the socket: %s", strerror(errno)); diff --git a/src/transport_git.c b/src/transport_git.c index 42503e1c9..8529fd47a 100644 --- a/src/transport_git.c +++ b/src/transport_git.c @@ -505,15 +505,18 @@ static int git_download_pack(char **out, git_transport *transport, git_repositor static int git_close(git_transport *transport) { transport_git *t = (transport_git*) transport; - int s = t->socket; int error; /* Can't do anything if there's an error, so don't bother checking */ - git_pkt_send_flush(s); - error = close(s); + git_pkt_send_flush(t->socket); + error = gitno_close(t->socket); if (error < 0) error = git__throw(GIT_EOSERR, "Failed to close socket"); +#ifdef GIT_WIN32 + WSACleanup(); +#endif + return error; } @@ -528,10 +531,6 @@ static void git_free(git_transport *transport) git_pkt_free(p); } -#ifdef GIT_WIN32 - WSACleanup(); -#endif - git_vector_free(refs); free(t->heads); free(t->parent.url);