Commit bec92f78 by Vicent Martí

Merge pull request #492 from carlosmn/networking

Networking improvements
parents 2744806f 6ac3b707
...@@ -28,16 +28,18 @@ GIT_BEGIN_DECL ...@@ -28,16 +28,18 @@ GIT_BEGIN_DECL
*/ */
/** /**
* Create a new unnamed remote * Create a remote in memory
* *
* Useful when you don't want to store the remote * Create a remote with the default refspecs in memory. You can use
* this when you have a URL instead of a remote's name.
* *
* @param out pointer to the new remote object * @param out pointer to the new remote object
* @param repo the associtated repository * @param repo the associtated repository
* @param url the remote repository's URL * @param url the remote repository's URL
* @param name the remote's name
* @return GIT_SUCCESS or an error code * @return GIT_SUCCESS or an error code
*/ */
int git_remote_new(git_remote **out, git_repository *repo, const char *url); int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name);
/** /**
* Get the information for a particular remote * Get the information for a particular remote
...@@ -107,20 +109,13 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction); ...@@ -107,20 +109,13 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction);
GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs); GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs);
/** /**
* Negotiate what data needs to be exchanged to synchroize the remtoe
* and local references
*
* @param remote the remote you want to negotiate with
*/
GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
/**
* Download the packfile * Download the packfile
* *
* The packfile is downloaded with a temporary filename, as it's final * Negotiate what objects should be downloaded and download the
* name is not known yet. If there was no packfile needed (all the * packfile with those objects. The packfile is downloaded with a
* objects were available locally), filename will be NULL and the * temporary filename, as it's final name is not known yet. If there
* function will return success. * was no packfile needed (all the objects were available locally),
* filename will be NULL and the function will return success.
* *
* @param remote the remote to download from * @param remote the remote to download from
* @param filename where to store the temproray filename * @param filename where to store the temproray filename
...@@ -129,6 +124,26 @@ GIT_EXTERN(int) git_remote_negotiate(git_remote *remote); ...@@ -129,6 +124,26 @@ GIT_EXTERN(int) git_remote_negotiate(git_remote *remote);
GIT_EXTERN(int) git_remote_download(char **filename, git_remote *remote); GIT_EXTERN(int) git_remote_download(char **filename, git_remote *remote);
/** /**
* Check whether the remote is connected
*
* Check whether the remote's underlying transport is connected to the
* remote host.
*
* @return 1 if it's connected, 0 otherwise.
*/
GIT_EXTERN(int) git_remote_connected(git_remote *remote);
/**
* Disconnect from the remote
*
* Close the connection to the remote and free the underlying
* transport.
*
* @param remote the remote to disconnect from
*/
GIT_EXTERN(void) git_remote_disconnect(git_remote *remote);
/**
* Free the memory associated with a remote * Free the memory associated with a remote
* *
* @param remote the remote to free * @param remote the remote to free
......
/*
* Copyright (C) 2009-2011 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "common.h"
#include "protocol.h"
#include "pkt.h"
#include "buffer.h"
int git_protocol_store_refs(git_protocol *p, const char *data, size_t len)
{
git_buf *buf = &p->buf;
git_vector *refs = p->refs;
int error;
const char *line_end, *ptr;
if (len == 0) { /* EOF */
if (buf->size != 0)
return p->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
else
return 0;
}
git_buf_put(buf, data, len);
ptr = buf->ptr;
while (1) {
git_pkt *pkt;
if (buf->size == 0)
return 0;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
if (error == GIT_ESHORTBUFFER)
return 0; /* Ask for more */
if (error < GIT_SUCCESS)
return p->error = git__rethrow(error, "Failed to parse pkt-line");
git_buf_consume(buf, line_end);
error = git_vector_insert(refs, pkt);
if (error < GIT_SUCCESS)
return p->error = git__rethrow(error, "Failed to add pkt to list");
if (pkt->type == GIT_PKT_FLUSH)
p->flush = 1;
}
return error;
}
/*
* Copyright (C) 2009-2011 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_protocol_h__
#define INCLUDE_protocol_h__
#include "transport.h"
#include "buffer.h"
typedef struct {
git_transport *transport;
git_vector *refs;
git_buf buf;
int error;
unsigned int flush :1;
} git_protocol;
int git_protocol_store_refs(git_protocol *p, const char *data, size_t len);
#endif
...@@ -23,8 +23,13 @@ int git_refspec_parse(git_refspec *refspec, const char *str) ...@@ -23,8 +23,13 @@ int git_refspec_parse(git_refspec *refspec, const char *str)
} }
delim = strchr(str, ':'); delim = strchr(str, ':');
if (delim == NULL) if (delim == NULL) {
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'"); refspec->src = git__strdup(str);
if (refspec->src == NULL)
return GIT_ENOMEM;
return GIT_SUCCESS;
}
refspec->src = git__strndup(str, delim - str); refspec->src = git__strndup(str, delim - str);
if (refspec->src == NULL) if (refspec->src == NULL)
......
...@@ -10,9 +10,12 @@ ...@@ -10,9 +10,12 @@
#include "git2/refspec.h" #include "git2/refspec.h"
struct git_refspec { struct git_refspec {
int force; struct git_refspec *next;
char *src; char *src;
char *dst; char *dst;
unsigned int force :1,
pattern :1,
matching :1;
}; };
int git_refspec_parse(struct git_refspec *refspec, const char *str); int git_refspec_parse(struct git_refspec *refspec, const char *str);
......
...@@ -56,22 +56,34 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha ...@@ -56,22 +56,34 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha
return refspec_parse(refspec, val); return refspec_parse(refspec, val);
} }
int git_remote_new(git_remote **out, git_repository *repo, const char *url) int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
{ {
git_remote *remote; git_remote *remote;
if (url == NULL)
return git__throw(GIT_EINVALIDARGS, "No URL was given");
remote = git__malloc(sizeof(git_remote)); remote = git__malloc(sizeof(git_remote));
if (remote == NULL) if (remote == NULL)
return GIT_ENOMEM; return GIT_ENOMEM;
memset(remote, 0x0, sizeof(git_remote)); memset(remote, 0x0, sizeof(git_remote));
remote->repo = repo; remote->repo = repo;
remote->url = git__strdup(url); remote->url = git__strdup(url);
if (remote->url == NULL) { if (remote->url == NULL) {
git__free(remote); git__free(remote);
return GIT_ENOMEM; return GIT_ENOMEM;
} }
if (name != NULL) {
remote->name = git__strdup(name);
if (remote->name == NULL) {
git__free(remote);
return GIT_ENOMEM;
}
}
*out = remote; *out = remote;
return GIT_SUCCESS; return GIT_SUCCESS;
} }
...@@ -206,13 +218,13 @@ int git_remote_ls(git_remote *remote, git_headarray *refs) ...@@ -206,13 +218,13 @@ int git_remote_ls(git_remote *remote, git_headarray *refs)
return remote->transport->ls(remote->transport, refs); return remote->transport->ls(remote->transport, refs);
} }
int git_remote_negotiate(git_remote *remote)
{
return git_fetch_negotiate(remote);
}
int git_remote_download(char **filename, git_remote *remote) int git_remote_download(char **filename, git_remote *remote)
{ {
int error;
if ((error = git_fetch_negotiate(remote)) < 0)
return git__rethrow(error, "Error negotiating");
return git_fetch_download_pack(filename, remote); return git_fetch_download_pack(filename, remote);
} }
...@@ -255,6 +267,21 @@ int git_remote_update_tips(struct git_remote *remote) ...@@ -255,6 +267,21 @@ int git_remote_update_tips(struct git_remote *remote)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
int git_remote_connected(git_remote *remote)
{
return remote->transport == NULL ? 0 : remote->transport->connected;
}
void git_remote_disconnect(git_remote *remote)
{
if (remote->transport != NULL) {
if (remote->transport->connected)
remote->transport->close(remote->transport);
remote->transport->free(remote->transport);
}
}
void git_remote_free(git_remote *remote) void git_remote_free(git_remote *remote)
{ {
if (remote == NULL) if (remote == NULL)
...@@ -266,11 +293,6 @@ void git_remote_free(git_remote *remote) ...@@ -266,11 +293,6 @@ void git_remote_free(git_remote *remote)
git__free(remote->push.dst); git__free(remote->push.dst);
git__free(remote->url); git__free(remote->url);
git__free(remote->name); git__free(remote->name);
if (remote->transport != NULL) { git_remote_disconnect(remote);
if (remote->transport->connected)
remote->transport->close(remote->transport);
remote->transport->free(remote->transport);
}
git__free(remote); git__free(remote);
} }
...@@ -20,9 +20,11 @@ ...@@ -20,9 +20,11 @@
#include "filebuf.h" #include "filebuf.h"
#include "repository.h" #include "repository.h"
#include "fetch.h" #include "fetch.h"
#include "protocol.h"
typedef struct { typedef struct {
git_transport parent; git_transport parent;
git_protocol proto;
GIT_SOCKET socket; GIT_SOCKET socket;
git_vector refs; git_vector refs;
git_remote_head **heads; git_remote_head **heads;
...@@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url) ...@@ -126,11 +128,7 @@ static int do_connect(transport_git *t, const char *url)
static int store_refs(transport_git *t) static int store_refs(transport_git *t)
{ {
gitno_buffer *buf = &t->buf; gitno_buffer *buf = &t->buf;
git_vector *refs = &t->refs;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
const char *line_end, *ptr;
git_pkt *pkt;
while (1) { while (1) {
error = gitno_recv(buf); error = gitno_recv(buf);
...@@ -139,34 +137,20 @@ static int store_refs(transport_git *t) ...@@ -139,34 +137,20 @@ static int store_refs(transport_git *t)
if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */ if (error == GIT_SUCCESS) /* Orderly shutdown, so exit */
return GIT_SUCCESS; return GIT_SUCCESS;
ptr = buf->data; error = git_protocol_store_refs(&t->proto, buf->data, buf->offset);
while (1) { if (error == GIT_ESHORTBUFFER) {
if (buf->offset == 0) gitno_consume_n(buf, buf->len);
break; continue;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); }
/*
* If the error is GIT_ESHORTBUFFER, it means the buffer
* isn't long enough to satisfy the request. Break out and
* wait for more input.
* On any other error, fail.
*/
if (error == GIT_ESHORTBUFFER) {
break;
}
if (error < GIT_SUCCESS) {
return error;
}
/* Get rid of the part we've used already */
gitno_consume(buf, line_end);
error = git_vector_insert(refs, pkt); if (error < GIT_SUCCESS)
if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to store refs");
return error;
if (pkt->type == GIT_PKT_FLUSH) gitno_consume_n(buf, buf->offset);
return GIT_SUCCESS;
if (t->proto.flush) { /* No more refs */
t->proto.flush = 0;
return GIT_SUCCESS;
} }
} }
...@@ -476,6 +460,7 @@ static void git_free(git_transport *transport) ...@@ -476,6 +460,7 @@ static void git_free(git_transport *transport)
git_vector_free(refs); git_vector_free(refs);
git__free(t->heads); git__free(t->heads);
git_buf_free(&t->proto.buf);
git__free(t->parent.url); git__free(t->parent.url);
git__free(t); git__free(t);
} }
...@@ -501,6 +486,8 @@ int git_transport_git(git_transport **out) ...@@ -501,6 +486,8 @@ int git_transport_git(git_transport **out)
t->parent.download_pack = git_download_pack; t->parent.download_pack = git_download_pack;
t->parent.close = git_close; t->parent.close = git_close;
t->parent.free = git_free; t->parent.free = git_free;
t->proto.refs = &t->refs;
t->proto.transport = (git_transport *) t;
*out = (git_transport *) t; *out = (git_transport *) t;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "fetch.h" #include "fetch.h"
#include "filebuf.h" #include "filebuf.h"
#include "repository.h" #include "repository.h"
#include "protocol.h"
enum last_cb { enum last_cb {
NONE, NONE,
...@@ -28,6 +29,7 @@ enum last_cb { ...@@ -28,6 +29,7 @@ enum last_cb {
typedef struct { typedef struct {
git_transport parent; git_transport parent;
git_protocol proto;
git_vector refs; git_vector refs;
git_vector common; git_vector common;
int socket; int socket;
...@@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser) ...@@ -186,47 +188,8 @@ static int on_headers_complete(http_parser *parser)
static int on_body_store_refs(http_parser *parser, const char *str, size_t len) static int on_body_store_refs(http_parser *parser, const char *str, size_t len)
{ {
transport_http *t = (transport_http *) parser->data; transport_http *t = (transport_http *) parser->data;
git_buf *buf = &t->buf;
git_vector *refs = &t->refs;
int error;
const char *line_end, *ptr;
static int first_pkt = 1;
if (len == 0) { /* EOF */
if (buf->size != 0)
return t->error = git__throw(GIT_ERROR, "EOF and unprocessed data");
else
return 0;
}
git_buf_put(buf, str, len);
ptr = buf->ptr;
while (1) {
git_pkt *pkt;
if (buf->size == 0)
return 0;
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->size);
if (error == GIT_ESHORTBUFFER)
return 0; /* Ask for more */
if (error < GIT_SUCCESS)
return t->error = git__rethrow(error, "Failed to parse pkt-line");
git_buf_consume(buf, line_end);
if (first_pkt) { return git_protocol_store_refs(&t->proto, str, len);
first_pkt = 0;
if (pkt->type != GIT_PKT_COMMENT)
return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
}
error = git_vector_insert(refs, pkt);
if (error < GIT_SUCCESS)
return t->error = git__rethrow(error, "Failed to add pkt to list");
}
return error;
} }
static int on_message_complete(http_parser *parser) static int on_message_complete(http_parser *parser)
...@@ -243,6 +206,7 @@ static int store_refs(transport_http *t) ...@@ -243,6 +206,7 @@ static int store_refs(transport_http *t)
http_parser_settings settings; http_parser_settings settings;
char buffer[1024]; char buffer[1024];
gitno_buffer buf; gitno_buffer buf;
git_pkt *pkt;
http_parser_init(&t->parser, HTTP_RESPONSE); http_parser_init(&t->parser, HTTP_RESPONSE);
t->parser.data = t; t->parser.data = t;
...@@ -273,6 +237,12 @@ static int store_refs(transport_http *t) ...@@ -273,6 +237,12 @@ static int store_refs(transport_http *t)
return GIT_SUCCESS; return GIT_SUCCESS;
} }
pkt = git_vector_get(&t->refs, 0);
if (pkt == NULL || pkt->type != GIT_PKT_COMMENT)
return t->error = git__throw(GIT_EOBJCORRUPTED, "Not a valid smart HTTP response");
else
git_vector_remove(&t->refs, 0);
return error; return error;
} }
...@@ -750,6 +720,7 @@ static void http_free(git_transport *transport) ...@@ -750,6 +720,7 @@ static void http_free(git_transport *transport)
} }
git_vector_free(common); git_vector_free(common);
git_buf_free(&t->buf); git_buf_free(&t->buf);
git_buf_free(&t->proto.buf);
git__free(t->heads); git__free(t->heads);
git__free(t->content_type); git__free(t->content_type);
git__free(t->host); git__free(t->host);
...@@ -775,6 +746,8 @@ int git_transport_http(git_transport **out) ...@@ -775,6 +746,8 @@ int git_transport_http(git_transport **out)
t->parent.download_pack = http_download_pack; t->parent.download_pack = http_download_pack;
t->parent.close = http_close; t->parent.close = http_close;
t->parent.free = http_free; t->parent.free = http_free;
t->proto.refs = &t->refs;
t->proto.transport = (git_transport *) t;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
/* on win32, the WSA context needs to be initialized /* on win32, the WSA context needs to be initialized
......
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