summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/netops.c123
1 files changed, 88 insertions, 35 deletions
diff --git a/src/netops.c b/src/netops.c
index 98b5035ff..2161dfab9 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -37,10 +37,93 @@
struct addrinfo {
struct hostent *ai_hostent;
struct servent *ai_servent;
- struct sockaddr_in ai_addr;
+ struct sockaddr_in ai_addr_in;
+ struct sockaddr *ai_addr;
+ size_t ai_addrlen;
+ int ai_family;
int ai_socktype;
+ int ai_protocol;
long ai_port;
+ struct addrinfo *ai_next;
};
+
+static int getaddrinfo(const char *host, const char *port, struct addrinfo *hints, struct addrinfo **info) {
+ GIT_UNUSED(hints);
+
+ struct addrinfo *ainfo, *ai;
+ int p = 0;
+
+ if((ainfo = malloc(sizeof(struct addrinfo))) == NULL)
+ return -1;
+
+ if((ainfo->ai_hostent = gethostbyname(host)) == NULL)
+ return -2;
+
+ ainfo->ai_servent = getservbyname(port, 0);
+
+ if(ainfo->ai_servent)
+ ainfo->ai_port = ainfo->ai_servent->s_port;
+ else
+ ainfo->ai_port = atol(port);
+
+
+ memcpy(&ainfo->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_length);
+ ainfo->ai_protocol = 0;
+ ainfo->ai_socktype = hints->ai_socktype;
+ ainfo->ai_family = ainfo->ai_hostent->h_addrtype;
+ ainfo->ai_addr_in.sin_family = ainfo->ai_family;
+ ainfo->ai_addr_in.sin_port = ainfo->ai_port;
+ ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in;
+ ainfo->ai_addrlen = sizeof(struct sockaddr_in);
+
+ *info = ainfo;
+
+ if(ainfo->ai_hostent->h_addr_list[1] == NULL) {
+ ainfo->ai_next = NULL;
+ return 0;
+ }
+
+ ai = ainfo;
+
+ for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) {
+ ai->ai_next = malloc(sizeof(struct addrinfo));
+ memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo));
+ memcpy(&ai->ai_next->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[p], ainfo->ai_hostent->h_length);
+ ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in;
+ ai = ai->ai_next;
+ }
+
+ ai->ai_next = NULL;
+ return 0;
+}
+
+static void freeaddrinfo(struct addrinfo *info) {
+ struct addrinfo *p, *next;
+
+ p = info;
+
+ while(p != NULL) {
+ next = p->ai_next;
+ free(p);
+ p = next;
+ }
+}
+
+static const char *gai_strerror(int ret) {
+ switch(ret) {
+ case -1:
+ return "Out of memory";
+ break;
+
+ case -2:
+ return "Address lookup failed";
+ break;
+
+ default:
+ return "Unknown error";
+ break;
+ }
+}
#endif
#ifdef GIT_WIN32
@@ -386,53 +469,29 @@ static int ssl_setup(git_transport *t, const char *host)
int gitno_connect(git_transport *t, const char *host, const char *port)
{
-#ifndef NO_ADDRINFO
struct addrinfo *info = NULL, *p;
-#else
- int p;
-#endif
struct addrinfo hints;
int ret;
GIT_SOCKET s = INVALID_SOCKET;
memset(&hints, 0x0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
-#ifndef NO_ADDRINFO
hints.ai_family = AF_UNSPEC;
if ((ret = getaddrinfo(host, port, &hints, &info)) < 0) {
giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret));
return -1;
}
-#else
- hints.ai_hostent = gethostbyname(host);
- hints.ai_servent = getservbyname(port, 0);
-
- if(hints.ai_servent)
- hints.ai_port = hints.ai_servent->s_port;
- else
- hints.ai_port = atol(port);
-#endif
-#ifndef NO_ADDRINFO
for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
-#else
- for (p = 0; hints.ai_hostent->h_addr_list[p] != NULL; p++) {
- s = socket(hints.ai_hostent->h_addrtype, hints.ai_socktype, 0);
-#endif
+
if (s == INVALID_SOCKET) {
net_set_error("error creating socket");
break;
}
-#ifndef NO_ADDRINFO
+
if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
-#else
- memcpy(&hints.ai_addr.sin_addr, hints.ai_hostent->h_addr_list[p], hints.ai_hostent->h_length);
- hints.ai_addr.sin_family = hints.ai_hostent->h_addrtype;
- hints.ai_addr.sin_port = hints.ai_port;
- if (connect(s, (struct sockaddr *)&hints.ai_addr, sizeof(struct sockaddr_in)) == 0)
-#endif
break;
/* If we can't connect, try the next one */
@@ -441,20 +500,14 @@ int gitno_connect(git_transport *t, const char *host, const char *port)
}
/* Oops, we couldn't connect to any address */
- if (s == INVALID_SOCKET &&
-#ifndef NO_ADDRINFO
- p == NULL) {
-#else
- hints.ai_hostent->h_addr_list[p] == NULL) {
-#endif
+ if (s == INVALID_SOCKET && p == NULL) {
giterr_set(GITERR_OS, "Failed to connect to %s", host);
return -1;
}
t->socket = s;
-#ifndef NO_ADDRINFO
freeaddrinfo(info);
-#endif
+
if (t->encrypt && ssl_setup(t, host) < 0)
return -1;