Patch #401196: IPv6 extensions to the socket module.
New functions getnameinfo, getaddrinfo. New exceptions socket.gaierror,
socket.herror. Various new constants, in particular AF_INET6 and error
codes and parameters for getaddrinfo.
AF_INET6 support in setipaddr, makesockaddr, getsockaddr, getsockaddrlen,
gethost_common, PySocket_gethostbyaddr.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index e4bdf41..b44e9b8 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -7,7 +7,7 @@
 
 Limitations:
 
-- only AF_INET and AF_UNIX address families are supported in a
+- only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
   portable manner, though AF_PACKET is supported under Linux.
 - no read/write operations (use send/recv or makefile instead)
 - additional restrictions apply on Windows
@@ -15,6 +15,10 @@
 Module interface:
 
 - socket.error: exception raised for socket specific errors
+- socket.gaierror: exception raised for getaddrinfo/getnameinfo errors,
+	a subclass of socket.error
+- socket.herror: exception raised for gethostby* errors,
+	a subclass of socket.error
 - socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd')
 - socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
 - socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com')
@@ -25,6 +29,9 @@
 - socket.ntohl(32 bit value) --> new int object
 - socket.htons(16 bit value) --> new int object
 - socket.htonl(32 bit value) --> new int object
+- socket.getaddrinfo(host, port [, family, socktype, proto, flags])
+	--> List of (family, socktype, proto, canonname, sockaddr)
+- socket.getnameinfo(sockaddr, flags) --> (host, port)
 - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
 - socket.inet_aton(IP address) -> 32-bit packed IP representation
 - socket.inet_ntoa(packed IP) -> IP address string
@@ -239,6 +246,10 @@
 #	define SIZEOF_SOCKET_T SIZEOF_INT
 #endif
 
+#ifdef MS_WIN32
+#	define EAFNOSUPPORT            WSAEAFNOSUPPORT
+#	define snprintf _snprintf
+#endif
 
 #if defined(PYOS_OS2)
 #define SOCKETCLOSE soclose
@@ -253,6 +264,8 @@
    by this module (but not argument type or memory errors, etc.). */
 
 static PyObject *PySocket_Error;
+static PyObject *PyH_Error;
+static PyObject *PyGAI_Error;
 
 #ifdef USE_SSL
 static PyObject *SSLErrorObject;
@@ -393,6 +406,43 @@
 }
 
 
+static PyObject *
+PyH_Err(int h_error)
+{
+	PyObject *v;
+
+#ifdef HAVE_HSTRERROR
+	v = Py_BuildValue("(is)", h_error, (char *)hstrerror(h_error));
+#else
+	v = Py_BuildValue("(is)", h_error, "host not found");
+#endif
+	if (v != NULL) {
+		PyErr_SetObject(PyGAI_Error, v);
+		Py_DECREF(v);
+	}
+
+	return NULL;
+}
+
+
+static PyObject *
+PyGAI_Err(int error)
+{
+	PyObject *v;
+
+	if (error == EAI_SYSTEM)
+		return PySocket_Err();
+
+	v = Py_BuildValue("(is)", error, gai_strerror(error));
+	if (v != NULL) {
+		PyErr_SetObject(PyGAI_Error, v);
+		Py_DECREF(v);
+	}
+
+	return NULL;
+}
+
+
 /* The object holding a socket.  It holds some extra information,
    like the address family, which is used to decode socket address
    arguments properly. */
@@ -408,6 +458,10 @@
 #ifdef AF_UNIX
 		struct sockaddr_un un;
 #endif
+#ifdef INET6
+		struct sockaddr_in6 in6;
+		struct sockaddr_storage storage;
+#endif
 #if defined(linux) && defined(AF_PACKET)
 		struct sockaddr_ll ll;
 #endif
@@ -484,85 +538,87 @@
 /* Convert a string specifying a host name or one of a few symbolic
    names to a numeric IP address.  This usually calls gethostbyname()
    to do the work; the names "" and "<broadcast>" are special.
-   Return the length (should always be 4 bytes), or negative if
+   Return the length (IPv4 should be 4 bytes), or negative if
    an error occurred; then an exception is raised. */
 
 static int
-setipaddr(char* name, struct sockaddr_in * addr_ret)
+setipaddr(char* name, struct sockaddr * addr_ret, int af)
 {
-	struct hostent *hp;
-	int d1, d2, d3, d4;
-	int h_length;
-	char ch;
-#ifdef HAVE_GETHOSTBYNAME_R
-	struct hostent hp_allocated;
-#ifdef HAVE_GETHOSTBYNAME_R_3_ARG
-	struct hostent_data data;
-#else
-	char buf[1001];
-	int buf_len = (sizeof buf) - 1;
-	int errnop;
-#endif
-#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG)
-	int result;
-#endif
-#endif /* HAVE_GETHOSTBYNAME_R */
+	struct addrinfo hints, *res;
+	int error;
 
 	memset((void *) addr_ret, '\0', sizeof(*addr_ret));
 	if (name[0] == '\0') {
-		addr_ret->sin_addr.s_addr = INADDR_ANY;
-		return 4;
+		int siz;
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_family = af;
+		hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
+		hints.ai_flags = AI_PASSIVE;
+		error = getaddrinfo(NULL, "0", &hints, &res);
+		if (error) {
+			PyGAI_Err(error);
+			return -1;
+		}
+		switch (res->ai_family) {
+		case AF_INET:
+			siz = 4;
+			break;
+#ifdef INET6
+		case AF_INET6:
+			siz = 16;
+			break;
+#endif
+		default:
+			freeaddrinfo(res);
+			PyErr_SetString(PySocket_Error,
+				"unsupported address family");
+			return -1;
+		}
+		if (res->ai_next) {
+			PyErr_SetString(PySocket_Error,
+				"wildcard resolved to multiple address");
+			return -1;
+		}
+		memcpy(addr_ret, res->ai_addr, res->ai_addrlen);
+		freeaddrinfo(res);
+		return siz;
 	}
 	if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
-		addr_ret->sin_addr.s_addr = INADDR_BROADCAST;
-		return 4;
+		struct sockaddr_in *sin;
+		if (af != PF_INET && af != PF_UNSPEC) {
+			PyErr_SetString(PySocket_Error,
+				"address family mismatched");
+			return -1;
+		}
+		sin = (struct sockaddr_in *)addr_ret;
+		memset((void *) sin, '\0', sizeof(*sin));
+		sin->sin_family = AF_INET;
+#ifdef HAVE_SOCKADDR_SA_LEN
+		sin->sin_len = sizeof(*sin);
+#endif
+		sin->sin_addr.s_addr = INADDR_BROADCAST;
+		return sizeof(sin->sin_addr);
 	}
-	if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
-	    0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
-	    0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
-		addr_ret->sin_addr.s_addr = htonl(
-			((long) d1 << 24) | ((long) d2 << 16) |
-			((long) d3 << 8) | ((long) d4 << 0));
-		return 4;
-	}
-	Py_BEGIN_ALLOW_THREADS
-#ifdef HAVE_GETHOSTBYNAME_R
-#if    defined(HAVE_GETHOSTBYNAME_R_6_ARG)
-	result = gethostbyname_r(name, &hp_allocated, buf, buf_len, &hp, &errnop);
-#elif  defined(HAVE_GETHOSTBYNAME_R_5_ARG)
-	hp = gethostbyname_r(name, &hp_allocated, buf, buf_len, &errnop);
-#else  /* HAVE_GETHOSTBYNAME_R_3_ARG */
-	memset((void *) &data, '\0', sizeof(data));
-	result = gethostbyname_r(name, &hp_allocated, &data);
-	hp = (result != 0) ? NULL : &hp_allocated;
-#endif
-#else /* not HAVE_GETHOSTBYNAME_R */
-#ifdef USE_GETHOSTBYNAME_LOCK
-	PyThread_acquire_lock(gethostbyname_lock, 1);
-#endif
-	hp = gethostbyname(name);
-#endif /* HAVE_GETHOSTBYNAME_R */
-	Py_END_ALLOW_THREADS
-
-	if (hp == NULL) {
-#ifdef HAVE_HSTRERROR
-		/* Let's get real error message to return */
-		extern int h_errno;
-		PyErr_SetString(PySocket_Error, (char *)hstrerror(h_errno));
-#else
-		PyErr_SetString(PySocket_Error, "host not found");
-#endif
-#ifdef USE_GETHOSTBYNAME_LOCK
-		PyThread_release_lock(gethostbyname_lock);
-#endif
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = af;
+	error = getaddrinfo(name, NULL, &hints, &res);
+	if (error) {
+		PyGAI_Err(error);
 		return -1;
 	}
-	memcpy((char *) &addr_ret->sin_addr, hp->h_addr, hp->h_length);
-	h_length = hp->h_length;
-#ifdef USE_GETHOSTBYNAME_LOCK
-	PyThread_release_lock(gethostbyname_lock);
+	memcpy((char *) addr_ret, res->ai_addr, res->ai_addrlen);
+	freeaddrinfo(res);
+	switch (addr_ret->sa_family) {
+	case AF_INET:
+		return 4;
+#ifdef INET6
+	case AF_INET6:
+		return 16;
 #endif
-	return h_length;
+	default:
+		PyErr_SetString(PySocket_Error, "unknown address family");
+		return -1;
+	}
 }
 
 
@@ -571,13 +627,17 @@
    size numbers). */
 
 static PyObject *
-makeipaddr(struct sockaddr_in *addr)
+makeipaddr(struct sockaddr *addr, int addrlen)
 {
-	unsigned long x = ntohl(addr->sin_addr.s_addr);
-	char buf[100];
-	sprintf(buf, "%d.%d.%d.%d",
-		(int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
-		(int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
+	char buf[NI_MAXHOST];
+	int error;
+
+	error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+		NI_NUMERICHOST);
+	if (error) {
+		PyGAI_Err(error);
+		return NULL;
+	}
 	return PyString_FromString(buf);
 }
 
@@ -606,10 +666,11 @@
 
 	case AF_INET:
 	{
-		struct sockaddr_in *a = (struct sockaddr_in *) addr;
-		PyObject *addrobj = makeipaddr(a);
+		struct sockaddr_in *a;
+		PyObject *addrobj = makeipaddr(addr, sizeof(*a));
 		PyObject *ret = NULL;
 		if (addrobj) {
+			a = (struct sockaddr_in *)addr;
 			ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
 			Py_DECREF(addrobj);
 		}
@@ -622,6 +683,22 @@
 		struct sockaddr_un *a = (struct sockaddr_un *) addr;
 		return PyString_FromString(a->sun_path);
 	}
+#endif /* AF_UNIX */
+
+#ifdef INET6
+	case AF_INET6:
+	{
+		struct sockaddr_in6 *a;
+		PyObject *addrobj = makeipaddr(addr, sizeof(*a));
+		PyObject *ret = NULL;
+		if (addrobj) {
+			a = (struct sockaddr_in6 *)addr;
+			ret = Py_BuildValue("Oiii", addrobj, ntohs(a->sin6_port),
+				a->sin6_flowinfo, a->sin6_scope_id);
+			Py_DECREF(addrobj);
+		}
+		return ret;
+	}
 #endif
 
 #if defined(linux) && defined(AF_PACKET)
@@ -681,7 +758,7 @@
 					"AF_UNIX path too long");
 			return 0;
 		}
-		addr->sun_family = AF_UNIX;
+		addr->sun_family = s->sock_family;
 		memcpy(addr->sun_path, path, len);
 		addr->sun_path[len] = 0;
 		*addr_ret = (struct sockaddr *) addr;
@@ -704,7 +781,7 @@
 		}
 		if (!PyArg_ParseTuple(args, "si:getsockaddrarg", &host, &port))
 			return 0;
-		if (setipaddr(host, addr) < 0)
+		if (setipaddr(host, (struct sockaddr *)addr, AF_INET) < 0)
 			return 0;
 		addr->sin_family = AF_INET;
 		addr->sin_port = htons((short)port);
@@ -713,6 +790,30 @@
 		return 1;
 	}
 
+#ifdef INET6
+	case AF_INET6:
+	{
+		struct sockaddr_in6* addr;
+		char *host;
+		int port, flowinfo, scope_id;
+ 		addr = (struct sockaddr_in6*)&(s->sock_addr).in6;
+		flowinfo = scope_id = 0;
+		if (!PyArg_ParseTuple(args, "si|ii", &host, &port, &flowinfo,
+				&scope_id)) {
+			return 0;
+		}
+		if (setipaddr(host, (struct sockaddr *)addr, AF_INET6) < 0)
+			return 0;
+		addr->sin6_family = s->sock_family;
+		addr->sin6_port = htons((short)port);
+		addr->sin6_flowinfo = flowinfo;
+		addr->sin6_scope_id = scope_id;
+		*addr_ret = (struct sockaddr *) addr;
+		*len_ret = sizeof *addr;
+		return 1;
+	}
+#endif
+
 #if defined(linux) && defined(AF_PACKET)
 	case AF_PACKET:
 	{
@@ -745,7 +846,6 @@
 	}
 #endif
 
-
 	/* More cases here... */
 
 	default:
@@ -779,6 +879,14 @@
 		return 1;
 	}
 
+#ifdef INET6
+	case AF_INET6:
+	{
+		*len_ret = sizeof (struct sockaddr_in6);
+		return 1;
+	}
+#endif
+
 #if defined(linux) && defined(AF_PACKET)
 	case AF_PACKET:
 	{
@@ -1652,12 +1760,14 @@
 PySocket_gethostbyname(PyObject *self, PyObject *args)
 {
 	char *name;
-	struct sockaddr_in addrbuf;
+	struct sockaddr_storage addrbuf;
+
 	if (!PyArg_ParseTuple(args, "s:gethostbyname", &name))
 		return NULL;
-	if (setipaddr(name, &addrbuf) < 0)
+	if (setipaddr(name, (struct sockaddr *)&addrbuf, AF_INET) < 0)
 		return NULL;
-	return makeipaddr(&addrbuf);
+	return makeipaddr((struct sockaddr *)&addrbuf,
+		sizeof(struct sockaddr_in));
 }
 
 static char gethostbyname_doc[] =
@@ -1669,23 +1779,44 @@
 /* Convenience function common to gethostbyname_ex and gethostbyaddr */
 
 static PyObject *
-gethost_common(struct hostent *h, struct sockaddr_in *addr)
+gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
 {
 	char **pch;
 	PyObject *rtn_tuple = (PyObject *)NULL;
 	PyObject *name_list = (PyObject *)NULL;
 	PyObject *addr_list = (PyObject *)NULL;
 	PyObject *tmp;
+
 	if (h == NULL) {
-#ifdef HAVE_HSTRERROR
 		/* Let's get real error message to return */
+#ifndef MS_WIN32
 		extern int h_errno;
-		PyErr_SetString(PySocket_Error, (char *)hstrerror(h_errno));
+#endif
+		PyH_Err(h_errno);
+		return NULL;
+	}
+	if (h->h_addrtype != af) {
+#ifdef HAVE_STRERROR
+	        /* Let's get real error message to return */
+		PyErr_SetString(PySocket_Error, (char *)strerror(EAFNOSUPPORT));
 #else
-		PyErr_SetString(PySocket_Error, "host not found");
+		PyErr_SetString(PySocket_Error,
+		    "Address family not supported by protocol family");
 #endif
 		return NULL;
 	}
+	switch (af) {
+	case AF_INET:
+		if (alen < sizeof(struct sockaddr_in))
+			return NULL;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		if (alen < sizeof(struct sockaddr_in6))
+			return NULL;
+		break;
+#endif
+	}
 	if ((name_list = PyList_New(0)) == NULL)
 		goto err;
 	if ((addr_list = PyList_New(0)) == NULL)
@@ -1702,8 +1833,43 @@
 	}
 	for (pch = h->h_addr_list; *pch != NULL; pch++) {
 		int status;
-		memcpy((char *) &addr->sin_addr, *pch, h->h_length);
-		tmp = makeipaddr(addr);
+		switch (af) {
+		case AF_INET:
+		    {
+			struct sockaddr_in sin;
+			memset(&sin, 0, sizeof(sin));
+			sin.sin_family = af;
+#ifdef HAVE_SOCKADDR_SA_LEN
+			sin.sin_len = sizeof(sin);
+#endif
+			memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr));
+			tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin));
+			if (pch == h->h_addr_list && alen >= sizeof(sin))
+				memcpy((char *) addr, &sin, sizeof(sin));
+			break;
+		    }
+#ifdef INET6
+		case AF_INET6:
+		    {
+			struct sockaddr_in6 sin6;
+			memset(&sin6, 0, sizeof(sin6));
+			sin6.sin6_family = af;
+#ifdef HAVE_SOCKADDR_SA_LEN
+			sin6.sin6_len = sizeof(sin6);
+#endif
+			memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr));
+			tmp = makeipaddr((struct sockaddr *)&sin6,
+				sizeof(sin6));
+			if (pch == h->h_addr_list && alen >= sizeof(sin6))
+				memcpy((char *) addr, &sin6, sizeof(sin6));
+			break;
+		    }
+#endif
+		default:	/* can't happen */
+			PyErr_SetString(PySocket_Error,
+				"unsupported address family");
+			return NULL;
+		}
 		if (tmp == NULL)
 			goto err;
 		status = PyList_Append(addr_list, tmp);
@@ -1727,7 +1893,7 @@
 {
 	char *name;
 	struct hostent *h;
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
 	PyObject *ret;
 #ifdef HAVE_GETHOSTBYNAME_R
 	struct hostent hp_allocated;
@@ -1742,9 +1908,10 @@
 	int result;
 #endif
 #endif /* HAVE_GETHOSTBYNAME_R */
+
 	if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name))
 		return NULL;
-	if (setipaddr(name, &addr) < 0)
+	if (setipaddr(name, (struct sockaddr *)&addr, PF_INET) < 0)
 		return NULL;
 	Py_BEGIN_ALLOW_THREADS
 #ifdef HAVE_GETHOSTBYNAME_R
@@ -1764,7 +1931,7 @@
 	h = gethostbyname(name);
 #endif /* HAVE_GETHOSTBYNAME_R */
 	Py_END_ALLOW_THREADS
-	ret = gethost_common(h, &addr);
+	ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), addr.ss_family);
 #ifdef USE_GETHOSTBYNAME_LOCK
 	PyThread_release_lock(gethostbyname_lock);
 #endif
@@ -1784,7 +1951,12 @@
 static PyObject *
 PySocket_gethostbyaddr(PyObject *self, PyObject *args)
 {
+#ifdef INET6
+        struct sockaddr_storage addr;
+#else
 	struct sockaddr_in addr;
+#endif
+	struct sockaddr *sa = (struct sockaddr *)&addr;
 	char *ip_num;
 	struct hostent *h;
 	PyObject *ret;
@@ -1801,40 +1973,55 @@
 	int result;
 #endif
 #endif /* HAVE_GETHOSTBYNAME_R */
+	char *ap;
+	int al;
+	int af;
 
 	if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num))
 		return NULL;
-	if (setipaddr(ip_num, &addr) < 0)
+	af = PF_UNSPEC;
+	if (setipaddr(ip_num, sa, af) < 0)
 		return NULL;
+	af = sa->sa_family;
+	ap = NULL;
+	al = 0;
+	switch (af) {
+	case AF_INET:
+		ap = (char *)&((struct sockaddr_in *)sa)->sin_addr;
+		al = sizeof(((struct sockaddr_in *)sa)->sin_addr);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+		al = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
+		break;
+#endif
+	default:
+		PyErr_SetString(PySocket_Error, "unsupported address family");
+		return NULL;
+	}
 	Py_BEGIN_ALLOW_THREADS
 #ifdef HAVE_GETHOSTBYNAME_R
 #if   defined(HAVE_GETHOSTBYNAME_R_6_ARG)
-	result = gethostbyaddr_r((char *)&addr.sin_addr,
-		sizeof(addr.sin_addr),
-		AF_INET, &hp_allocated, buf, buf_len,
+	result = gethostbyaddr_r(ap, al, af,
+		&hp_allocated, buf, buf_len,
 		&h, &errnop);
 #elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
-	h = gethostbyaddr_r((char *)&addr.sin_addr,
-			    sizeof(addr.sin_addr),
-			    AF_INET,
+	h = gethostbyaddr_r(ap, al, af,
 			    &hp_allocated, buf, buf_len, &errnop);
 #else /* HAVE_GETHOSTBYNAME_R_3_ARG */
 	memset((void *) &data, '\0', sizeof(data));
-	result = gethostbyaddr_r((char *)&addr.sin_addr,
-		sizeof(addr.sin_addr),
-		AF_INET, &hp_allocated, &data);
+	result = gethostbyaddr_r(ap, al, af, &hp_allocated, &data);
 	h = (result != 0) ? NULL : &hp_allocated;
 #endif
 #else /* not HAVE_GETHOSTBYNAME_R */
 #ifdef USE_GETHOSTBYNAME_LOCK
 	PyThread_acquire_lock(gethostbyname_lock, 1);
 #endif
-	h = gethostbyaddr((char *)&addr.sin_addr,
-			  sizeof(addr.sin_addr),
-			  AF_INET);
+	h = gethostbyaddr(ap, al, af);
 #endif /* HAVE_GETHOSTBYNAME_R */
 	Py_END_ALLOW_THREADS
-	ret = gethost_common(h, &addr);
+	ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af);
 #ifdef USE_GETHOSTBYNAME_LOCK
 	PyThread_release_lock(gethostbyname_lock);
 #endif
@@ -2134,6 +2321,156 @@
 	return PyString_FromString(inet_ntoa(packed_addr));
 }
 
+/* Python interface to getaddrinfo(host, port). */
+
+/*ARGSUSED*/
+static PyObject *
+PySocket_getaddrinfo(PyObject *self, PyObject *args)
+{
+	struct addrinfo hints, *res0, *res;
+	PyObject *pobj = (PyObject *)NULL;
+	char pbuf[10];
+	char *hptr, *pptr;
+	int family, socktype, protocol, flags;
+	int error;
+	PyObject *all = (PyObject *)NULL;
+	PyObject *single = (PyObject *)NULL;
+
+	family = socktype = protocol = flags = 0;
+	family = PF_UNSPEC;
+	if (!PyArg_ParseTuple(args, "zO|iiii:getaddrinfo",
+	    &hptr, &pobj, &family, &socktype,
+			&protocol, &flags)) {
+		return NULL;
+	}
+	if (PyInt_Check(pobj)) {
+		snprintf(pbuf, sizeof(pbuf), "%ld", PyInt_AsLong(pobj));
+		pptr = pbuf;
+	} else if (PyString_Check(pobj)) {
+		pptr = PyString_AsString(pobj);
+	} else if (pobj == Py_None) {
+		pptr = (char *)NULL;
+	} else {
+		PyErr_SetString(PySocket_Error, "Int or String expected");
+		return NULL;
+	}
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = family;
+	hints.ai_socktype = socktype;
+	hints.ai_protocol = protocol;
+	hints.ai_flags = flags;
+	error = getaddrinfo(hptr, pptr, &hints, &res0);
+	if (error) {
+		PyGAI_Err(error);
+		return NULL;
+	}
+
+	if ((all = PyList_New(0)) == NULL)
+		goto err;
+	for (res = res0; res; res = res->ai_next) {
+		single = Py_BuildValue("iiisO", res->ai_family,
+			res->ai_socktype, res->ai_protocol,
+			res->ai_canonname ? res->ai_canonname : "",
+			makesockaddr(-1, res->ai_addr, res->ai_addrlen));
+		if (single == NULL)
+			goto err;
+
+		if (PyList_Append(all, single))
+			goto err;
+		Py_XDECREF(single);
+	}
+	Py_XDECREF(pobj);
+	return all;
+ err:
+	Py_XDECREF(single);
+	Py_XDECREF(all);
+	Py_XDECREF(pobj);
+	return (PyObject *)NULL;
+}
+
+static char getaddrinfo_doc[] =
+"socket.getaddrinfo(host, port [, family, socktype, proto, flags])\n\
+	--> List of (family, socktype, proto, canonname, sockaddr)\n\
+\n\
+Resolve host and port into addrinfo struct.";
+
+/* Python interface to getnameinfo(sa, flags). */
+
+/*ARGSUSED*/
+static PyObject *
+PySocket_getnameinfo(PyObject *self, PyObject *args)
+{
+	PyObject *sa = (PyObject *)NULL;
+	int flags;
+	char *hostp;
+	int n, port, flowinfo, scope_id;
+	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+	struct addrinfo hints, *res = NULL;
+	int error;
+	PyObject *ret = (PyObject *)NULL;
+
+	flags = flowinfo = scope_id = 0;
+	if (PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags) == 0)
+		return NULL;
+	n = PyArg_ParseTuple(sa, "si|ii", &hostp, &port, &flowinfo, scope_id);
+	if (n == 0)
+		goto fail;
+	snprintf(pbuf, sizeof(pbuf), "%d", port);
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	error = getaddrinfo(hostp, pbuf, &hints, &res);
+	if (error) {
+		PyGAI_Err(error);
+		goto fail;
+	}
+	if (res->ai_next) {
+		PyErr_SetString(PySocket_Error,
+			"sockaddr resolved to multiple addresses");
+		goto fail;
+	}
+	switch (res->ai_family) {
+	case AF_INET:
+	    {
+		char *t1;
+		int t2;
+		if (PyArg_ParseTuple(sa, "si", &t1, &t2) == 0) {
+			PyErr_SetString(PySocket_Error,
+				"IPv4 sockaddr must be 2 tuple");
+			goto fail;
+		}
+		break;
+	    }
+#ifdef INET6
+	case AF_INET6:
+	    {
+		struct sockaddr_in6 *sin6;
+		sin6 = (struct sockaddr_in6 *)res->ai_addr;
+		sin6->sin6_flowinfo = flowinfo;
+		sin6->sin6_scope_id = scope_id;
+		break;
+	    }
+#endif
+	}
+	error = getnameinfo(res->ai_addr, res->ai_addrlen,
+			hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
+	if (error) {
+		PyGAI_Err(error);
+		goto fail;
+	}
+	ret = Py_BuildValue("ss", hbuf, pbuf);
+
+fail:
+	if (res)
+		freeaddrinfo(res);
+	Py_XDECREF(sa);
+	return ret;
+}
+
+static char getnameinfo_doc[] =
+"socket.getnameinfo(sockaddr, flags) --> (host, port)\n\
+\n\
+Get host and port for a sockaddr.";
+
 
 #ifdef USE_SSL
 
@@ -2389,6 +2726,10 @@
 	 METH_VARARGS, inet_aton_doc},
 	{"inet_ntoa",		PySocket_inet_ntoa,
 	 METH_VARARGS, inet_ntoa_doc},
+	{"getaddrinfo",		PySocket_getaddrinfo,
+	 METH_VARARGS, getaddrinfo_doc},
+	{"getnameinfo",		PySocket_getnameinfo,
+	 METH_VARARGS, getnameinfo_doc},
 #ifdef USE_SSL
 	{"ssl",			PySocket_ssl,
 	 METH_VARARGS, ssl_doc},
@@ -2559,6 +2900,13 @@
 	PySocket_Error = PyErr_NewException("socket.error", NULL, NULL);
 	if (PySocket_Error == NULL)
 		return;
+	PyH_Error = PyErr_NewException("socket.herror", PySocket_Error, NULL);
+	if (PyH_Error == NULL)
+		return;
+	PyGAI_Error = PyErr_NewException("socket.gaierror", PySocket_Error,
+	    NULL);
+	if (PyGAI_Error == NULL)
+		return;
 #ifdef USE_SSL
 	SSL_load_error_strings();
 	SSLeay_add_ssl_algorithms();
@@ -2584,6 +2932,9 @@
 	insint(d, "AF_UNSPEC", AF_UNSPEC);
 #endif
 	insint(d, "AF_INET", AF_INET);
+#ifdef AF_INET6
+	insint(d, "AF_INET6", AF_INET6);
+#endif /* AF_INET6 */
 #ifdef AF_UNIX
 	insint(d, "AF_UNIX", AF_UNIX);
 #endif /* AF_UNIX */
@@ -2939,6 +3290,98 @@
 	insint(d, "IPX_TYPE", IPX_TYPE);
 #endif
 
+	/* get{addr,name}info parameters */
+#ifdef EAI_ADDRFAMILY
+	insint(d, "EAI_ADDRFAMILY", EAI_ADDRFAMILY);
+#endif
+#ifdef EAI_AGAIN
+	insint(d, "EAI_AGAIN", EAI_AGAIN);
+#endif
+#ifdef EAI_BADFLAGS
+	insint(d, "EAI_BADFLAGS", EAI_BADFLAGS);
+#endif
+#ifdef EAI_FAIL
+	insint(d, "EAI_FAIL", EAI_FAIL);
+#endif
+#ifdef EAI_FAMILY
+	insint(d, "EAI_FAMILY", EAI_FAMILY);
+#endif
+#ifdef EAI_MEMORY
+	insint(d, "EAI_MEMORY", EAI_MEMORY);
+#endif
+#ifdef EAI_NODATA
+	insint(d, "EAI_NODATA", EAI_NODATA);
+#endif
+#ifdef EAI_NONAME
+	insint(d, "EAI_NONAME", EAI_NONAME);
+#endif
+#ifdef EAI_SERVICE
+	insint(d, "EAI_SERVICE", EAI_SERVICE);
+#endif
+#ifdef EAI_SOCKTYPE
+	insint(d, "EAI_SOCKTYPE", EAI_SOCKTYPE);
+#endif
+#ifdef EAI_SYSTEM
+	insint(d, "EAI_SYSTEM", EAI_SYSTEM);
+#endif
+#ifdef EAI_BADHINTS
+	insint(d, "EAI_BADHINTS", EAI_BADHINTS);
+#endif
+#ifdef EAI_PROTOCOL
+	insint(d, "EAI_PROTOCOL", EAI_PROTOCOL);
+#endif
+#ifdef EAI_MAX
+	insint(d, "EAI_MAX", EAI_MAX);
+#endif
+#ifdef AI_PASSIVE
+	insint(d, "AI_PASSIVE", AI_PASSIVE);
+#endif
+#ifdef AI_CANONNAME
+	insint(d, "AI_CANONNAME", AI_CANONNAME);
+#endif
+#ifdef AI_NUMERICHOST
+	insint(d, "AI_NUMERICHOST", AI_NUMERICHOST);
+#endif
+#ifdef AI_MASK
+	insint(d, "AI_MASK", AI_MASK);
+#endif
+#ifdef AI_ALL
+	insint(d, "AI_ALL", AI_ALL);
+#endif
+#ifdef AI_V4MAPPED_CFG
+	insint(d, "AI_V4MAPPED_CFG", AI_V4MAPPED_CFG);
+#endif
+#ifdef AI_ADDRCONFIG
+	insint(d, "AI_ADDRCONFIG", AI_ADDRCONFIG);
+#endif
+#ifdef AI_V4MAPPED
+	insint(d, "AI_V4MAPPED", AI_V4MAPPED);
+#endif
+#ifdef AI_DEFAULT
+	insint(d, "AI_DEFAULT", AI_DEFAULT);
+#endif
+#ifdef NI_MAXHOST
+	insint(d, "NI_MAXHOST", NI_MAXHOST);
+#endif
+#ifdef NI_MAXSERV
+	insint(d, "NI_MAXSERV", NI_MAXSERV);
+#endif
+#ifdef NI_NOFQDN
+	insint(d, "NI_NOFQDN", NI_NOFQDN);
+#endif
+#ifdef NI_NUMERICHOST
+	insint(d, "NI_NUMERICHOST", NI_NUMERICHOST);
+#endif
+#ifdef NI_NAMEREQD
+	insint(d, "NI_NAMEREQD", NI_NAMEREQD);
+#endif
+#ifdef NI_NUMERICSERV
+	insint(d, "NI_NUMERICSERV", NI_NUMERICSERV);
+#endif
+#ifdef NI_DGRAM
+	insint(d, "NI_DGRAM", NI_DGRAM);
+#endif
+
 	/* Initialize gethostbyname lock */
 #ifdef USE_GETHOSTBYNAME_LOCK
 	gethostbyname_lock = PyThread_allocate_lock();