Merge branch 'dh/repack' (early part)
[gitweb.git] / connect.c
index 8a8a13bb72b33f335a5a10642f0461ef673ef168..375739205f72062c7b51e16ca4cdecc053e1c2da 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -3,6 +3,7 @@
 #include "pkt-line.h"
 #include "quote.h"
 #include "refs.h"
+#include "run-command.h"
 
 static char *server_capabilities;
 
@@ -390,16 +391,34 @@ static enum protocol get_protocol(const char *name)
 
 #ifndef NO_IPV6
 
+static const char *ai_name(const struct addrinfo *ai)
+{
+       static char addr[INET_ADDRSTRLEN];
+       if ( AF_INET == ai->ai_family ) {
+               struct sockaddr_in *in;
+               in = (struct sockaddr_in *)ai->ai_addr;
+               inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr));
+       } else if ( AF_INET6 == ai->ai_family ) {
+               struct sockaddr_in6 *in;
+               in = (struct sockaddr_in6 *)ai->ai_addr;
+               inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr));
+       } else {
+               strcpy(addr, "(unknown)");
+       }
+       return addr;
+}
+
 /*
  * Returns a connected socket() fd, or else die()s.
  */
-static int git_tcp_connect_sock(char *host)
+static int git_tcp_connect_sock(char *host, int flags)
 {
        int sockfd = -1, saved_errno = 0;
        char *colon, *end;
        const char *port = STR(DEFAULT_GIT_PORT);
        struct addrinfo hints, *ai0, *ai;
        int gai;
+       int cnt = 0;
 
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
@@ -416,15 +435,23 @@ static int git_tcp_connect_sock(char *host)
        if (colon) {
                *colon = 0;
                port = colon + 1;
+               if (!*port)
+                       port = "<none>";
        }
 
        memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "Looking up %s ... ", host);
+
        gai = getaddrinfo(host, port, &hints, &ai);
        if (gai)
-               die("Unable to look up %s (%s)", host, gai_strerror(gai));
+               die("Unable to look up %s (port %s) (%s)", host, port, gai_strerror(gai));
+
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
 
        for (ai0 = ai; ai; ai = ai->ai_next) {
                sockfd = socket(ai->ai_family,
@@ -435,10 +462,18 @@ static int git_tcp_connect_sock(char *host)
                }
                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
                        saved_errno = errno;
+                       fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+                               host,
+                               cnt,
+                               ai_name(ai),
+                               hstrerror(h_errno),
+                               strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
+               if (flags & CONNECT_VERBOSE)
+                       fprintf(stderr, "%s ", ai_name(ai));
                break;
        }
 
@@ -447,6 +482,9 @@ static int git_tcp_connect_sock(char *host)
        if (sockfd < 0)
                die("unable to connect a socket (%s)", strerror(saved_errno));
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\n");
+
        return sockfd;
 }
 
@@ -455,7 +493,7 @@ static int git_tcp_connect_sock(char *host)
 /*
  * Returns a connected socket() fd, or else die()s.
  */
-static int git_tcp_connect_sock(char *host)
+static int git_tcp_connect_sock(char *host, int flags)
 {
        int sockfd = -1, saved_errno = 0;
        char *colon, *end;
@@ -464,6 +502,7 @@ static int git_tcp_connect_sock(char *host)
        struct sockaddr_in sa;
        char **ap;
        unsigned int nport;
+       int cnt;
 
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
@@ -482,6 +521,9 @@ static int git_tcp_connect_sock(char *host)
                port = colon + 1;
        }
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "Looking up %s ... ", host);
+
        he = gethostbyname(host);
        if (!he)
                die("Unable to look up %s (%s)", host, hstrerror(h_errno));
@@ -494,7 +536,10 @@ static int git_tcp_connect_sock(char *host)
                nport = se->s_port;
        }
 
-       for (ap = he->h_addr_list; *ap; ap++) {
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
+
+       for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {
                sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
                if (sockfd < 0) {
                        saved_errno = errno;
@@ -508,25 +553,37 @@ static int git_tcp_connect_sock(char *host)
 
                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
                        saved_errno = errno;
+                       fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+                               host,
+                               cnt,
+                               inet_ntoa(*(struct in_addr *)&sa.sin_addr),
+                               hstrerror(h_errno),
+                               strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
+               if (flags & CONNECT_VERBOSE)
+                       fprintf(stderr, "%s ",
+                               inet_ntoa(*(struct in_addr *)&sa.sin_addr));
                break;
        }
 
        if (sockfd < 0)
                die("unable to connect a socket (%s)", strerror(saved_errno));
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\n");
+
        return sockfd;
 }
 
 #endif /* NO_IPV6 */
 
 
-static void git_tcp_connect(int fd[2], char *host)
+static void git_tcp_connect(int fd[2], char *host, int flags)
 {
-       int sockfd = git_tcp_connect_sock(host);
+       int sockfd = git_tcp_connect_sock(host, flags);
 
        fd[0] = sockfd;
        fd[1] = dup(sockfd);
@@ -598,8 +655,8 @@ static void git_proxy_connect(int fd[2], char *host)
 {
        const char *port = STR(DEFAULT_GIT_PORT);
        char *colon, *end;
-       int pipefd[2][2];
-       pid_t pid;
+       const char *argv[4];
+       struct child_process proxy;
 
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
@@ -618,25 +675,18 @@ static void git_proxy_connect(int fd[2], char *host)
                port = colon + 1;
        }
 
-       if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
-               die("unable to create pipe pair for communication");
-       pid = fork();
-       if (!pid) {
-               dup2(pipefd[1][0], 0);
-               dup2(pipefd[0][1], 1);
-               close(pipefd[0][0]);
-               close(pipefd[0][1]);
-               close(pipefd[1][0]);
-               close(pipefd[1][1]);
-               execlp(git_proxy_command, git_proxy_command, host, port, NULL);
-               die("exec failed");
-       }
-       if (pid < 0)
-               die("fork failed");
-       fd[0] = pipefd[0][0];
-       fd[1] = pipefd[1][1];
-       close(pipefd[0][1]);
-       close(pipefd[1][0]);
+       argv[0] = git_proxy_command;
+       argv[1] = host;
+       argv[2] = port;
+       argv[3] = NULL;
+       memset(&proxy, 0, sizeof(proxy));
+       proxy.argv = argv;
+       proxy.in = -1;
+       proxy.out = -1;
+       if (start_command(&proxy))
+               die("cannot start proxy %s", argv[0]);
+       fd[0] = proxy.out; /* read from proxy stdout */
+       fd[1] = proxy.in;  /* write to proxy stdin */
 }
 
 #define MAX_CMD_LEN 1024
@@ -650,7 +700,7 @@ static void git_proxy_connect(int fd[2], char *host)
  *
  * Does not return a negative value on error; it just dies.
  */
-pid_t git_connect(int fd[2], char *url, const char *prog)
+pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
 {
        char *host, *path = url;
        char *end;
@@ -723,7 +773,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog)
                if (git_use_proxy(host))
                        git_proxy_connect(fd, host);
                else
-                       git_tcp_connect(fd, host);
+                       git_tcp_connect(fd, host, flags);
                /*
                 * Separate original protocol components prog and path
                 * from extended components with a NUL byte.