diff options
| author | Philip Kelley <phkelley@hotmail.com> | 2012-10-29 13:41:14 -0400 |
|---|---|---|
| committer | Philip Kelley <phkelley@hotmail.com> | 2012-11-01 09:02:33 -0400 |
| commit | 41fb1ca0ec51ad1d2a14b911aab3215e42965d1b (patch) | |
| tree | 8e2e8b7bfa136602a424a8e9f23189a5618a0c2e /src/netops.c | |
| parent | a0ce87c51c1a3b1b3b674902148ad28d8e5fa32d (diff) | |
| download | libgit2-41fb1ca0ec51ad1d2a14b911aab3215e42965d1b.tar.gz | |
Reorganize transport architecture (squashed 3)
Diffstat (limited to 'src/netops.c')
| -rw-r--r-- | src/netops.c | 191 |
1 files changed, 111 insertions, 80 deletions
diff --git a/src/netops.c b/src/netops.c index d9663e63c..3e2743486 100644 --- a/src/netops.c +++ b/src/netops.c @@ -14,12 +14,13 @@ #else # include <ws2tcpip.h> # ifdef _MSC_VER -# pragma comment(lib, "ws2_32.lib") +# pragma comment(lib, "ws2_32") # endif #endif #ifdef GIT_SSL # include <openssl/ssl.h> +# include <openssl/err.h> # include <openssl/x509v3.h> #endif @@ -30,7 +31,6 @@ #include "netops.h" #include "posix.h" #include "buffer.h" -#include "transport.h" #ifdef GIT_WIN32 static void net_set_error(const char *str) @@ -41,6 +41,8 @@ static void net_set_error(const char *str) size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, (LPSTR)&err_str, 0, 0); + GIT_UNUSED(size); + giterr_set(GITERR_NET, "%s: %s", str, err_str); LocalFree(err_str); } @@ -108,8 +110,8 @@ static int gitno__recv_ssl(gitno_buffer *buf) int ret; do { - ret = SSL_read(buf->ssl->ssl, buf->data + buf->offset, buf->len - buf->offset); - } while (SSL_get_error(buf->ssl->ssl, ret) == SSL_ERROR_WANT_READ); + ret = SSL_read(buf->socket->ssl.ssl, buf->data + buf->offset, buf->len - buf->offset); + } while (SSL_get_error(buf->socket->ssl.ssl, ret) == SSL_ERROR_WANT_READ); if (ret < 0) { net_set_error("Error receiving socket data"); @@ -117,28 +119,26 @@ static int gitno__recv_ssl(gitno_buffer *buf) } buf->offset += ret; - if (buf->packetsize_cb) buf->packetsize_cb(ret, buf->packetsize_payload); return ret; } #endif -int gitno__recv(gitno_buffer *buf) +static int gitno__recv(gitno_buffer *buf) { int ret; - ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0); + ret = p_recv(buf->socket->socket, buf->data + buf->offset, buf->len - buf->offset, 0); if (ret < 0) { net_set_error("Error receiving socket data"); return -1; } buf->offset += ret; - if (buf->packetsize_cb) buf->packetsize_cb(ret, buf->packetsize_payload); return ret; } void gitno_buffer_setup_callback( - git_transport *t, + gitno_socket *socket, gitno_buffer *buf, char *data, size_t len, @@ -148,20 +148,21 @@ void gitno_buffer_setup_callback( buf->data = data; buf->len = len; buf->offset = 0; - buf->fd = t->socket; + buf->socket = socket; buf->recv = recv; buf->cb_data = cb_data; } -void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, size_t len) +void gitno_buffer_setup(gitno_socket *socket, gitno_buffer *buf, char *data, size_t len) { #ifdef GIT_SSL - if (t->use_ssl) { - gitno_buffer_setup_callback(t, buf, data, len, gitno__recv_ssl, NULL); - buf->ssl = &t->ssl; - } else + if (socket->ssl.ctx) { + gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv_ssl, NULL); + return; + } #endif - gitno_buffer_setup_callback(t, buf, data, len, gitno__recv, NULL); + + gitno_buffer_setup_callback(socket, buf, data, len, gitno__recv, NULL); } /* Consume up to ptr and move the rest of the buffer to the beginning */ @@ -187,31 +188,23 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons) buf->offset -= cons; } -int gitno_ssl_teardown(git_transport *t) -{ -#ifdef GIT_SSL - int ret; -#endif - - if (!t->use_ssl) - return 0; - #ifdef GIT_SSL +static int gitno_ssl_teardown(gitno_ssl *ssl) +{ + int ret; + do { - ret = SSL_shutdown(t->ssl.ssl); + ret = SSL_shutdown(ssl->ssl); } while (ret == 0); if (ret < 0) - return ssl_set_error(&t->ssl, ret); + return ssl_set_error(ssl, ret); - SSL_free(t->ssl.ssl); - SSL_CTX_free(t->ssl.ctx); -#endif + SSL_free(ssl->ssl); + SSL_CTX_free(ssl->ctx); return 0; } - -#ifdef GIT_SSL /* Match host names according to RFC 2818 rules */ static int match_host(const char *pattern, const char *host) { @@ -262,7 +255,7 @@ static int check_host_name(const char *name, const char *host) return 0; } -static int verify_server_cert(git_transport *t, const char *host) +static int verify_server_cert(gitno_ssl *ssl, const char *host) { X509 *cert; X509_NAME *peer_name; @@ -275,7 +268,7 @@ static int verify_server_cert(git_transport *t, const char *host) void *addr; int i = -1,j; - if (SSL_get_verify_result(t->ssl.ssl) != X509_V_OK) { + if (SSL_get_verify_result(ssl->ssl) != X509_V_OK) { giterr_set(GITERR_SSL, "The SSL certificate is invalid"); return -1; } @@ -292,7 +285,7 @@ static int verify_server_cert(git_transport *t, const char *host) } - cert = SSL_get_peer_certificate(t->ssl.ssl); + cert = SSL_get_peer_certificate(ssl->ssl); /* Check the alternative names */ alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); @@ -376,7 +369,7 @@ static int verify_server_cert(git_transport *t, const char *host) on_error: OPENSSL_free(peer_cn); - return ssl_set_error(&t->ssl, 0); + return ssl_set_error(ssl, 0); cert_fail: OPENSSL_free(peer_cn); @@ -384,51 +377,81 @@ cert_fail: return -1; } -static int ssl_setup(git_transport *t, const char *host) +static int ssl_setup(gitno_socket *socket, const char *host, int flags) { int ret; SSL_library_init(); SSL_load_error_strings(); - t->ssl.ctx = SSL_CTX_new(SSLv23_method()); - if (t->ssl.ctx == NULL) - return ssl_set_error(&t->ssl, 0); + socket->ssl.ctx = SSL_CTX_new(SSLv23_method()); + if (socket->ssl.ctx == NULL) + return ssl_set_error(&socket->ssl, 0); - SSL_CTX_set_mode(t->ssl.ctx, SSL_MODE_AUTO_RETRY); - SSL_CTX_set_verify(t->ssl.ctx, SSL_VERIFY_NONE, NULL); - if (!SSL_CTX_set_default_verify_paths(t->ssl.ctx)) - return ssl_set_error(&t->ssl, 0); + SSL_CTX_set_mode(socket->ssl.ctx, SSL_MODE_AUTO_RETRY); + SSL_CTX_set_verify(socket->ssl.ctx, SSL_VERIFY_NONE, NULL); + if (!SSL_CTX_set_default_verify_paths(socket->ssl.ctx)) + return ssl_set_error(&socket->ssl, 0); - t->ssl.ssl = SSL_new(t->ssl.ctx); - if (t->ssl.ssl == NULL) - return ssl_set_error(&t->ssl, 0); + socket->ssl.ssl = SSL_new(socket->ssl.ctx); + if (socket->ssl.ssl == NULL) + return ssl_set_error(&socket->ssl, 0); - if((ret = SSL_set_fd(t->ssl.ssl, t->socket)) == 0) - return ssl_set_error(&t->ssl, ret); + if((ret = SSL_set_fd(socket->ssl.ssl, socket->socket)) == 0) + return ssl_set_error(&socket->ssl, ret); - if ((ret = SSL_connect(t->ssl.ssl)) <= 0) - return ssl_set_error(&t->ssl, ret); + if ((ret = SSL_connect(socket->ssl.ssl)) <= 0) + return ssl_set_error(&socket->ssl, ret); - if (t->check_cert && verify_server_cert(t, host) < 0) + if ((GITNO_CONNECT_SSL_NO_CHECK_CERT & flags) || verify_server_cert(&socket->ssl, host) < 0) return -1; return 0; } -#else -static int ssl_setup(git_transport *t, const char *host) +#endif + +static int gitno__close(GIT_SOCKET s) { - GIT_UNUSED(t); - GIT_UNUSED(host); +#ifdef GIT_WIN32 + if (SOCKET_ERROR == closesocket(s)) + return -1; + + if (0 != WSACleanup()) { + giterr_set(GITERR_OS, "Winsock cleanup failed"); + return -1; + } + return 0; -} +#else + return close(s); #endif +} -int gitno_connect(git_transport *t, const char *host, const char *port) +int gitno_connect(gitno_socket *s_out, const char *host, const char *port, int flags) { struct addrinfo *info = NULL, *p; struct addrinfo hints; - int ret; GIT_SOCKET s = INVALID_SOCKET; + int ret; + +#ifdef GIT_WIN32 + /* on win32, the WSA context needs to be initialized + * before any socket calls can be performed */ + WSADATA wsd; + + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { + giterr_set(GITERR_OS, "Winsock init failed"); + return -1; + } + + if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) { + WSACleanup(); + giterr_set(GITERR_OS, "Winsock init failed"); + return -1; + } +#endif + + /* Zero the socket structure provided */ + memset(s_out, 0x0, sizeof(gitno_socket)); memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; @@ -452,7 +475,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) break; /* If we can't connect, try the next one */ - gitno_close(s); + gitno__close(s); s = INVALID_SOCKET; } @@ -462,46 +485,56 @@ int gitno_connect(git_transport *t, const char *host, const char *port) return -1; } - t->socket = s; + s_out->socket = s; p_freeaddrinfo(info); - if (t->use_ssl && ssl_setup(t, host) < 0) +#ifdef GIT_SSL + if ((flags & GITNO_CONNECT_SSL) && ssl_setup(s_out, host, flags) < 0) return -1; +#else + /* SSL is not supported */ + if (flags & GITNO_CONNECT_SSL) { + giterr_set(GITERR_OS, "SSL is not supported by this copy of libgit2."); + return -1; + } +#endif return 0; } #ifdef GIT_SSL -static int send_ssl(gitno_ssl *ssl, const char *msg, size_t len) +static int gitno_send_ssl(gitno_ssl *ssl, const char *msg, size_t len, int flags) { int ret; size_t off = 0; + GIT_UNUSED(flags); + while (off < len) { ret = SSL_write(ssl->ssl, msg + off, len - off); if (ret <= 0 && ret != SSL_ERROR_WANT_WRITE) return ssl_set_error(ssl, ret); off += ret; - } + } return off; } #endif -int gitno_send(git_transport *t, const char *msg, size_t len, int flags) +int gitno_send(gitno_socket *socket, const char *msg, size_t len, int flags) { int ret; size_t off = 0; #ifdef GIT_SSL - if (t->use_ssl) - return send_ssl(&t->ssl, msg, len); + if (socket->ssl.ctx) + return gitno_send_ssl(&socket->ssl, msg, len, flags); #endif while (off < len) { errno = 0; - ret = p_send(t->socket, msg + off, len - off, flags); + ret = p_send(socket->socket, msg + off, len - off, flags); if (ret < 0) { net_set_error("Error sending data"); return -1; @@ -513,19 +546,17 @@ int gitno_send(git_transport *t, const char *msg, size_t len, int flags) return (int)off; } - -#ifdef GIT_WIN32 -int gitno_close(GIT_SOCKET s) -{ - return closesocket(s) == SOCKET_ERROR ? -1 : 0; -} -#else -int gitno_close(GIT_SOCKET s) +int gitno_close(gitno_socket *s) { - return close(s); -} +#ifdef GIT_SSL + if (s->ssl.ctx && + gitno_ssl_teardown(&s->ssl) < 0) + return -1; #endif + return gitno__close(s->socket); +} + int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) { fd_set fds; @@ -535,10 +566,10 @@ int gitno_select_in(gitno_buffer *buf, long int sec, long int usec) tv.tv_usec = usec; FD_ZERO(&fds); - FD_SET(buf->fd, &fds); + FD_SET(buf->socket->socket, &fds); /* The select(2) interface is silly */ - return select((int)buf->fd + 1, &fds, NULL, NULL, &tv); + return select((int)buf->socket->socket + 1, &fds, NULL, NULL, &tv); } int gitno_extract_host_and_port(char **host, char **port, const char *url, const char *default_port) |
