From edf6032e3395baa5e2a160e4f70d3b108ae31622 Mon Sep 17 00:00:00 2001 From: Dean Jansa Date: Tue, 28 Sep 2010 15:53:28 -0500 Subject: First crack at ipv6/ipv4 agnostic qarsh/qacp. --- sockutil.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 30 deletions(-) (limited to 'sockutil.c') diff --git a/sockutil.c b/sockutil.c index 05097b2..6e74993 100644 --- a/sockutil.c +++ b/sockutil.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -35,30 +36,48 @@ int getsockport(int sd) { - struct sockaddr_in addr; + struct sockaddr_storage addr; socklen_t addrlen; addrlen = sizeof addr; if (getsockname(sd, (struct sockaddr *)&addr, &addrlen) == 0) { - return ntohs(addr.sin_port); + if (addr.ss_family == AF_INET) { + struct sockaddr_in *ipv4p = (struct sockaddr_in *)&addr; + return ntohs(ipv4p->sin_port); + } else { + struct sockaddr_in6 *ipv6p = (struct sockaddr_in6 *)&addr; + return ntohs(ipv6p->sin6_port); + } } else { return -1; } } int -bind_any(int minport) +bind_any(int minport, unsigned short ss_family) { int sd; - struct sockaddr_in addr; + struct sockaddr_storage addr; - sd = socket(AF_INET, SOCK_STREAM, 0); + sd = socket(ss_family, SOCK_STREAM, 0); if (sd == -1) return -1; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - do { - addr.sin_port = htons(minport++); - } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + + if (ss_family == AF_INET) { + struct sockaddr_in *ipv4p = (struct sockaddr_in *)&addr; + ipv4p->sin_family = AF_INET; + ipv4p->sin_addr.s_addr = htonl(INADDR_ANY); + do { + ipv4p->sin_port = htons(minport++); + } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + } else { + struct sockaddr_in6 *ipv6p = (struct sockaddr_in6 *)&addr; + ipv6p->sin6_family = AF_INET6; + ipv6p->sin6_addr = in6addr_any; + do { + ipv6p->sin6_port = htons(minport++); + } while (bind(sd, (struct sockaddr *)&addr, sizeof addr) != 0); + } + if (listen(sd, 0) == -1) { syslog(LOG_WARNING, "listen error %d, %s", errno, strerror(errno)); @@ -67,39 +86,89 @@ bind_any(int minport) } int -connect_to_host(char *hostname, int port) +connect_to_host(char *hostname, int port, unsigned short *ss_family) { - struct hostent *h; - struct sockaddr_in haddr; + struct addrinfo *ail; + struct addrinfo *aip; + struct addrinfo hints; + char portstr[NI_MAXSERV]; int sd; + int err; - if ((h = gethostbyname(hostname)) == NULL) { + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + memset(portstr, 0, sizeof portstr); + snprintf(portstr, NI_MAXSERV, "%d", port); + + if ((err = getaddrinfo(hostname, portstr, NULL, &ail)) != 0) { + fprintf(stderr, "Could not resolve hostname %s: %s\n", + hostname, gai_strerror(err)); return -1; } - haddr.sin_family = h->h_addrtype; - haddr.sin_port = htons(port); - memcpy(&haddr.sin_addr, h->h_addr, h->h_length); - sd = socket(PF_INET, SOCK_STREAM, 0); - if (sd == -1) return -1; - if (connect(sd, (struct sockaddr *)&haddr, sizeof haddr) == -1) { - return -1; + /* TBD -- do we loop over all of the addrinfos returned trying to + * connect, or just pick the first one? */ + + for (aip = ail; aip != NULL; aip = aip->ai_next) { +#if 0 + char hname[NI_MAXHOST] = ""; + char nname[NI_MAXHOST] = ""; + + err = getnameinfo(aip->ai_addr, aip->ai_addrlen, hname, NI_MAXHOST, NULL, 0, 0); + err = getnameinfo(aip->ai_addr, aip->ai_addrlen, nname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + + if (err != 0) { + printf("error in getnameinfo: %s\n", gai_strerror(err)); + continue; + } + + if (*hname && *nname) { + printf("Trying: %s (%s) -- ", hname, nname); + if (aip->ai_family == AF_INET6) puts("IPv6"); + if (aip->ai_family == AF_INET) puts("IPv4"); + } +#endif + + sd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); + if (sd == -1) return -1; + if (connect(sd, aip->ai_addr, aip->ai_addrlen) == -1) { + close(sd); + continue; + } else { + *ss_family=aip->ai_family; + freeaddrinfo(ail); + return sd; + } } - return sd; + + freeaddrinfo(ail); + return -1; } int -connect_to_peer(struct sockaddr_in *peer, int port) +connect_to_peer(struct sockaddr_storage *peer, int port) { - struct sockaddr_in in_peer; int sd; int fdflags; + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + struct sockaddr_storage *peeraddr; + + if (peer->ss_family == AF_INET) { + ipv4.sin_family = AF_INET; + ipv4.sin_port=htons(port); + ipv4.sin_addr = ((struct sockaddr_in *)peer)->sin_addr; + peeraddr = (struct sockaddr_storage *)&ipv4; + } else { + ipv6.sin6_family = AF_INET6; + ipv6.sin6_port=htons(port); + ipv6.sin6_addr = ((struct sockaddr_in6 *)peer)->sin6_addr; + peeraddr = (struct sockaddr_storage *)&ipv6; + } - in_peer.sin_family = AF_INET; - in_peer.sin_port = htons(port); - in_peer.sin_addr = peer->sin_addr; - - sd = socket(PF_INET, SOCK_STREAM, 0); + sd = socket(peer->ss_family, SOCK_STREAM, 0); if (sd == -1) return -1; /* Set close-on-exec for these sds */ @@ -112,7 +181,7 @@ connect_to_peer(struct sockaddr_in *peer, int port) return -1; } - if (connect(sd, (struct sockaddr *)&in_peer, sizeof in_peer) == -1) { + if (connect(sd, (struct sockaddr *)peeraddr, sizeof *peeraddr) == -1) { return -1; } return sd; -- cgit