summaryrefslogtreecommitdiffstats
path: root/sockutil.c
diff options
context:
space:
mode:
authorDean Jansa <djansa@redhat.com>2010-09-28 15:53:28 -0500
committerDean Jansa <djansa@redhat.com>2010-09-28 15:53:28 -0500
commitedf6032e3395baa5e2a160e4f70d3b108ae31622 (patch)
tree583c4dccccd249674adb9711b083a5597d3405ac /sockutil.c
parente96e56146dc7c11d388d25db42383993b87e8791 (diff)
downloadqarsh-edf6032e3395baa5e2a160e4f70d3b108ae31622.tar.gz
qarsh-edf6032e3395baa5e2a160e4f70d3b108ae31622.tar.xz
qarsh-edf6032e3395baa5e2a160e4f70d3b108ae31622.zip
First crack at ipv6/ipv4 agnostic qarsh/qacp.
Diffstat (limited to 'sockutil.c')
-rw-r--r--sockutil.c129
1 files changed, 99 insertions, 30 deletions
diff --git a/sockutil.c b/sockutil.c
index 05097b2..6e74993 100644
--- a/sockutil.c
+++ b/sockutil.c
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
@@ -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;