/* $begin open_clientfd */ int open_clientfd(char *hostname, char *port) { int clientfd; struct addrinfo hints, *listp, *p; /* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Open a connection */ hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */ hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */ Getaddrinfo(hostname, port, &hints, &listp); /* Walk the list for one that we can successfully connect to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */ /* Connect to the server */ if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break; /* Success */ Close(clientfd); /* Connect failed, try another */ //line:netp:openclientfd:closefd } /* Clean up */ Freeaddrinfo(listp); if (!p) /* All connects failed */ return -1; else /* The last connect succeeded */ return clientfd; }
int main(int argc, char **argv) { struct addrinfo *p, *listp, hints; char buf[MAXLINE]; int rc, flags; if (argc != 2) { fprintf(stderr, "usage: %s <domain name>\n", argv[0]); exit(0); } /* Get a list of addrinfo records */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 only */ //line:netp:hostinfo:family hints.ai_socktype = SOCK_STREAM; /* Connections only */ //line:netp:hostinfo:socktype if ((rc = getaddrinfo(argv[1], NULL, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(rc)); exit(1); } /* Walk the list and display each IP address */ flags = NI_NUMERICHOST; /* Display address string instead of domain name */ for (p = listp; p; p = p->ai_next) { Getnameinfo(p->ai_addr, p->ai_addrlen, buf, MAXLINE, NULL, 0, flags); printf("%s\n", buf); } /* Clean up */ Freeaddrinfo(listp); exit(0); }
/* * NAME: connectory * USAGE: Connect to a given "host" and "port" with the given "family" * ARGS: family - AF_INET is the only supported argument. * host - A hostname or "dotted quad" (or equivalent). * port - The remote port to connect to in *HOST ORDER*. * * XXX - This so violates everything I really wanted this function to be, * but I changed it to call getaddrinfo() directly instead of calling * inet_vhostsockaddr() because I wanted it to be able to take advantage * of connecting to multiple protocols and multiple ip addresses (for things * like ``us.undernet.org'') without having to do multiple calls to * getaddrinfo() which could be quite costly. */ int connectory (int family, const char *host, const char *port) { AI hints, *results, *ai; int err; int fd; SS localaddr; socklen_t locallen; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if ((err = Getaddrinfo(host, port, &hints, &results))) { yell("Hostname lookup for [%s:%s] failed: %s (%d)", host, port, gai_strerror(err), err); return -5; } fd = -1; for (ai = results; ai; ai = ai->ai_next) { /* First, look up the virtual host we use for this protocol. */ err = inet_vhostsockaddr(ai->ai_family, -1, &localaddr, &locallen); if (err < 0) continue; /* Now try to do the connection. */ fd = client_connect((SA *)&localaddr, locallen, ai->ai_addr, ai->ai_addrlen); if (fd < 0) { err = fd; fd = -1; continue; } else break; } Freeaddrinfo(results); if (fd < 0) return err; return fd; }
/* * NAME: inet_strton * USAGE: Convert "any" kind of address represented by a string into * a socket address suitable for connect()ing or bind()ing with. * ARGS: hostname - The address to convert. It may be any of the following: * IPv4 "Presentation Address" (A.B.C.D) * IPv6 "Presentation Address" (A:B::C:D) * Hostname (foo.bar.com) * 32 bit host order ipv4 address (2134546324) * storage - A pointer to a (struct sockaddr_storage) with the * "family" argument filled in (AF_INET or AF_INET6). * If "hostname" is a p-addr, then the form of the p-addr * must agree with the family in 'storage'. */ int inet_strton (const char *host, const char *port, SA *storage, int flags) { int family = storage->sa_family; /* First check for legacy 32 bit integer DCC addresses */ if ((family == AF_INET || family == AF_UNSPEC) && host && is_number(host)) { ((ISA *)storage)->sin_family = AF_INET; #ifdef HAVE_SA_LEN ((ISA *)storage)->sin_len = sizeof(ISA); #endif ((ISA *)storage)->sin_addr.s_addr = htonl(strtoul(host, NULL, 10)); if (port) ((ISA *)storage)->sin_port = htons((unsigned short)strtoul(port, NULL, 10)); return 0; } else { AI hints; AI *results; int retval; memset(&hints, 0, sizeof(hints)); hints.ai_flags = flags; hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((retval = Getaddrinfo(host, port, &hints, &results))) { yell("getaddrinfo(%s): %s", host, gai_strerror(retval)); return -5; } /* memcpy can bite me. */ memcpy(storage, results->ai_addr, results->ai_addrlen); Freeaddrinfo(results); return 0; } return -2; }
/* $begin open_listenfd */ int open_listenfd(char *port) { struct addrinfo hints, *listp, *p; int listenfd, optval=1; /* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Accept connections */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */ hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */ Getaddrinfo(NULL, port, &hints, &listp); /* Walk the list for one that we can bind to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */ /* Eliminates "Address already in use" error from bind */ Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt (const void *)&optval , sizeof(int)); /* Bind the descriptor to the address */ if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break; /* Success */ Close(listenfd); /* Bind failed, try the next */ } /* Clean up */ Freeaddrinfo(listp); if (!p) /* No address worked */ return -1; /* Make it a listening socket ready to accept connection requests */ if (listen(listenfd, LISTENQ) < 0) { Close(listenfd); return -1; } return listenfd; }