Subject: How do I write a client that can use either IPv4 or IPv6
Date: 02/25/98
Starting BSD/OS 4.0 the getaddrinfo(3) function is available. It is described in RFC 2133. This function may be used to gather address information about a host and service without needing to know the internet protocol associated with the host. Below is a function, netconnect(), which returns a connected socket for the requests hostname and service. A TELNET client might use it as:

	s = netconnect(server, "telnet", SOCK_STREAM, &error, &errmsg);
	if (s < 0)
		err(1, "%s", errmsg);

An application using TCP typically does not need to know what IP protocol is being used. It typically only needs the connected socket which simply provides a reliable full duplex byte stream. Programs that do need to know, such as FTP, could use the getsockname(3) function to determine who they are connected to and what protocol was used. The getsockname(3) function can be used to determine which local address was used.

/*
 * int
 * netconnect(char *hostname, char *service, int sockettype, int *errorp,
 *	      char **serrorp)
 *
 * Make a network connection to the specified hostname and service.
 *
 * The service is either the ASCII representation of the port number
 * or the service name (e.g., "23" or "telnet").
 *
 * sockettype is the type of socket to create, typically SOCK_STREAM.
 * It may be 0 to imply any socket type is okay.
 *
 * If errorp is not NULL and the function returns failure, it will
 * be filled in with the appropriate error value.
 *
 * If serrorp is not NULL and the function returns failure, it will
 * be filled in with a pointer to a textual error message.
 *
 * returns the file descriptor of the connected socket on success.
 *
 * returns -2 if the getaddrinfo(3) call failed.  Use gai_strerror(*errorp)
 * to get the textual error message.
 * 
 * returns -1 if socket(2) or connect(2) fails.  Use strerror(*errorp)
 * to get the textual error message.
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int
netconnect(char *hostname, char *service, int type, int *errorp, char **serrorp)
{
	struct addrinfo hints;
	struct addrinfo *ai, *an;
	int s, error;

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = type;

	if ((error = getaddrinfo(hostname, service, &hints, &ai)) != 0) {
		if (errorp)
			*errorp = error;
		if (serrorp)
			*serrorp = gai_strerror(error);
		return (-2);
	}

	for (an = ai; an; an = an->ai_next) {
		s = socket(an->ai_family, an->ai_socktype, an->ai_protocol);
		if (s < 0)
			continue;
		if (connect(s, an->ai_addr, an->ai_addrlen) == 0) {
			freeaddrinfo(ai);
			return (s);
		}
		close(s);
	}
	if (errorp)
		*errorp = errno;
	if (serrorp)
		*serrorp = strerror(errno);
	freeaddrinfo(ai);
	return (-1);
}