Commit f77d4f7fc6ca80725ef25dc16e143d75f762b8cb

Vicent Martí 2011-10-01T03:56:19

Merge pull request #437 from carlosmn/networking-windows Fix networking on Windows

diff --git a/src/netops.c b/src/netops.c
index 54aaa46..7d8a7b2 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));
@@ -132,6 +138,18 @@ int gitno_send(int 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 0d962ef..203df85 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,8 @@ 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_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 70086ad..1da56e1 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;
 
@@ -358,10 +362,14 @@ 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));
 
+#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 bcc612b..8529fd4 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;
 
 /*
@@ -35,10 +38,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,22 +57,21 @@ 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);
+
+	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 - 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);
+	*outlen = len;
+	*out = buf.ptr;
 
 	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;
@@ -502,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;
 }
 
@@ -534,6 +540,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 +563,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;
 }
diff --git a/src/transport_local.c b/src/transport_local.c
index 4975af9..7e932f8 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;