? Include/addrinfo.h
? Python/getaddrinfo.c
? Python/getnameinfo.c
Index: acconfig.h
===================================================================
RCS file: /cvsroot/python/python/dist/src/acconfig.h,v
retrieving revision 1.47
diff -u -r1.47 acconfig.h
--- acconfig.h	2001/06/23 16:30:13	1.47
+++ acconfig.h	2001/06/24 04:41:42
@@ -184,11 +184,23 @@
 /* Define if you want to use BSD db. */
 #undef WITH_LIBDB
 
+/* Define if --enable-ipv6 is specified */
+#undef ENABLE_IPV6
+
 /* Define if you want to use ndbm. */
 #undef WITH_LIBNDBM
 
 /* Define if you want to compile in Python-specific mallocs */
 #undef WITH_PYMALLOC
+
+/* struct addrinfo (netdb.h) */
+#undef HAVE_ADDRINFO
+
+/* Define if sockaddr has sa_len member */
+#undef HAVE_SOCKADDR_SA_LEN
+
+/* struct sockaddr_storage (sys/socket.h) */
+#undef HAVE_SOCKADDR_STORAGE
 
 /* Define if you want to produce an OpenStep/Rhapsody framework
    (shared library plus accessory files). */
Index: configure
===================================================================
RCS file: /cvsroot/python/python/dist/src/configure,v
retrieving revision 1.212
diff -u -r1.212 configure
--- configure	2001/06/23 16:30:12	1.212
+++ configure	2001/06/24 04:41:46
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-# From configure.in Revision: 1.219 
+# From configure.in Revision: 1.220 
 
 # Guess values for system-dependent variables and create Makefiles.
 # Generated automatically using autoconf version 2.13 
Index: Lib/BaseHTTPServer.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/BaseHTTPServer.py,v
retrieving revision 1.15
diff -u -r1.15 BaseHTTPServer.py
--- Lib/BaseHTTPServer.py	2001/02/09 05:38:46	1.15
+++ Lib/BaseHTTPServer.py	2001/06/24 04:41:47
@@ -68,8 +68,10 @@
 import sys
 import time
 import socket # For gethostbyaddr()
+import string
 import mimetools
 import SocketServer
+import re
 
 # Default error message
 DEFAULT_ERROR_MESSAGE = """\
@@ -474,7 +476,8 @@
 
     httpd = ServerClass(server_address, HandlerClass)
 
-    print "Serving HTTP on port", port, "..."
+    sa = httpd.socket.getsockname()
+    print "Serving HTTP on", sa[0], "port", sa[1], "..."
     httpd.serve_forever()
 
 
Index: Lib/SocketServer.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/SocketServer.py,v
retrieving revision 1.24
diff -u -r1.24 SocketServer.py
--- Lib/SocketServer.py	2001/04/11 04:02:05	1.24
+++ Lib/SocketServer.py	2001/06/24 04:41:47
@@ -5,7 +5,7 @@
 For socket-based servers:
 
 - address family:
-        - AF_INET: IP (Internet Protocol) sockets (default)
+        - AF_INET{,6}: IP (Internet Protocol) sockets (default)
         - AF_UNIX: Unix domain sockets
         - others, e.g. AF_DECNET are conceivable (see <socket.h>
 - socket type:
Index: Lib/ftplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/ftplib.py,v
retrieving revision 1.53
diff -u -r1.53 ftplib.py
--- Lib/ftplib.py	2001/04/09 04:31:50	1.53
+++ Lib/ftplib.py	2001/06/24 04:41:47
@@ -108,17 +108,29 @@
             self.connect(host)
             if user: self.login(user, passwd, acct)
 
-    def connect(self, host='', port=0):
-        '''Connect to host.  Arguments are:
-        - host: hostname to connect to (string, default previous host)
-        - port: port to connect to (integer, default previous port)'''
-        if host: self.host = host
-        if port: self.port = port
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.connect((self.host, self.port))
-        self.file = self.sock.makefile('rb')
-        self.welcome = self.getresp()
-        return self.welcome
+    def connect(self, host = '', port = 0):
+	'''Connect to host.  Arguments are:
+	- host: hostname to connect to (string, default previous host)
+	- port: port to connect to (integer, default previous port)'''
+	if host: self.host = host
+	if port: self.port = port
+	self.passiveserver = 0
+	for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
+	    af, socktype, proto, canonname, sa = res
+	    try:
+		self.sock = socket.socket(af, socktype, proto)
+		self.sock.connect(sa)
+	    except socket.error, msg:
+		self.sock.close()
+		self.sock = None
+		continue
+	    break
+	if not self.sock:
+	    raise socket.error, msg
+	self.af = af
+	self.file = self.sock.makefile('rb')
+	self.welcome = self.getresp()
+	return self.welcome
 
     def getwelcome(self):
         '''Get the welcome message from the server.
@@ -243,15 +255,48 @@
         cmd = 'PORT ' + ','.join(bytes)
         return self.voidcmd(cmd)
 
+    def sendeprt(self, host, port):
+	'''Send a EPRT command with the current host and the given port number.'''
+	af = 0
+	if self.af == socket.AF_INET:
+	    af = 1
+	if self.af == socket.AF_INET6:
+	    af = 2
+	if af == 0:
+	    raise error_proto, 'unsupported address family'
+	fields = ['', `af`, host, `port`, '']
+	cmd = 'EPRT ' + string.joinfields(fields, '|')
+	return self.voidcmd(cmd)
+
     def makeport(self):
-        '''Create a new socket and send a PORT command for it.'''
-        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        sock.bind(('', 0))
-        sock.listen(1)
-        dummyhost, port = sock.getsockname() # Get proper port
-        host, dummyport = self.sock.getsockname() # Get proper host
-        resp = self.sendport(host, port)
-        return sock
+	'''Create a new socket and send a PORT command for it.'''
+	for res in socket.getaddrinfo(None, 0, self.af, socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
+	    af, socktype, proto, canonname, sa = res
+	    try:
+		sock = socket.socket(af, socktype, proto)
+		sock.bind(sa)
+	    except socket.error, msg:
+		sock.close()
+		sock = None
+		continue
+	    break
+	if not sock:
+	    raise socket.error, msg
+	sock.listen(1)
+	port = sock.getsockname()[1] # Get proper port
+	host = self.sock.getsockname()[0] # Get proper host
+	if self.af == socket.AF_INET:
+	    resp = self.sendport(host, port)
+	else:
+	    resp = self.sendeprt(host, port)
+	return sock
+
+    def makepasv(self):
+	if self.af == socket.AF_INET:
+	    host, port = parse227(self.sendcmd('PASV'))
+	else:
+	    host, port = parse229(self.sendcmd('EPSV'), self.sock.getpeername())
+	return host, port
 
     def ntransfercmd(self, cmd, rest=None):
         """Initiate a transfer over the data connection.
@@ -270,9 +315,10 @@
         """
         size = None
         if self.passiveserver:
-            host, port = parse227(self.sendcmd('PASV'))
-            conn=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            conn.connect((host, port))
+            host, port = self.makepasv()
+	    af, socktype, proto, canon, sa = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0]
+	    conn = socket.socket(af, socktype, proto)
+	    conn.connect(sa)
             if rest is not None:
                 self.sendcmd("REST %s" % rest)
             resp = self.sendcmd(cmd)
@@ -520,6 +566,28 @@
         raise error_proto, resp
     host = '.'.join(numbers[:4])
     port = (int(numbers[4]) << 8) + int(numbers[5])
+    return host, port
+
+
+def parse229(resp, peer):
+    '''Parse the '229' response for a EPSV request.
+    Raises error_proto if it does not contain '(|||port|)'
+    Return ('host.addr.as.numbers', port#) tuple.'''
+
+    if resp[:3] <> '229':
+	raise error_reply, resp
+    left = string.find(resp, '(')
+    if left < 0: raise error_proto, resp
+    right = string.find(resp, ')', left + 1)
+    if right < 0:
+	raise error_proto, resp	# should contain '(|||port|)'
+    if resp[left + 1] <> resp[right - 1]:
+	raise error_proto, resp
+    parts = string.split(resp[left + 1:right], resp[left+1])
+    if len(parts) <> 5:
+	raise error_proto, resp
+    host = peer[0]
+    port = string.atoi(parts[3])
     return host, port
 
 
Index: Lib/httplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/httplib.py,v
retrieving revision 1.35
diff -u -r1.35 httplib.py
--- Lib/httplib.py	2001/06/01 16:25:38	1.35
+++ Lib/httplib.py	2001/06/24 04:41:48
@@ -357,10 +357,22 @@
 
     def connect(self):
         """Connect to the host and port specified in __init__."""
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        if self.debuglevel > 0:
-            print "connect: (%s, %s)" % (self.host, self.port)
-        self.sock.connect((self.host, self.port))
+ 	for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
+ 	    af, socktype, proto, canonname, sa = res
+ 	    try:
+ 		self.sock = socket.socket(af, socktype, proto)
+		if self.debuglevel > 0:
+		    print "connect: (%s, %s)" % (self.host, self.port)
+		self.sock.connect(sa)
+	    except socket.error, msg:
+		if self.debuglevel > 0:
+		    print 'connect fail:', (self.host, self.port)
+		self.sock.close()
+		self.sock = None
+		continue
+	    break
+	if not self.sock:
+	    raise socket.error, msg
 
     def close(self):
         """Close the connection to the HTTP server."""
Index: Lib/poplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/poplib.py,v
retrieving revision 1.14
diff -u -r1.14 poplib.py
--- Lib/poplib.py	2001/02/12 02:00:42	1.14
+++ Lib/poplib.py	2001/06/24 04:41:48
@@ -73,13 +73,23 @@
 
 
     def __init__(self, host, port = POP3_PORT):
-        self.host = host
-        self.port = port
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.connect((self.host, self.port))
-        self.file = self.sock.makefile('rb')
-        self._debugging = 0
-        self.welcome = self._getresp()
+	self.host = host
+	self.port = port
+	for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
+	    af, socktype, proto, canonname, sa = res
+	    try:
+		self.sock = socket.socket(af, socktype, proto)
+		self.sock.connect(sa)
+	    except socket.error, msg:
+		self.sock.close()
+		self.sock = None
+		continue
+	    break
+	if not self.sock:
+	    raise socket.error, msg
+	self.file = self.sock.makefile('rb')
+	self._debugging = 0
+	self.welcome = self._getresp()
 
 
     def _putline(self, line):
Index: Lib/smtplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/smtplib.py,v
retrieving revision 1.36
diff -u -r1.36 smtplib.py
--- Lib/smtplib.py	2001/02/15 22:15:13	1.36
+++ Lib/smtplib.py	2001/06/24 04:41:48
@@ -208,24 +208,32 @@
         specified during instantiation.
 
         """
-        if not port:
-            i = host.find(':')
+	if not port and (host.find(':') == host.rfind(':')):
+            i = host.rfind(':')
             if i >= 0:
                 host, port = host[:i], host[i+1:]
                 try: port = int(port)
                 except ValueError:
                     raise socket.error, "nonnumeric port"
         if not port: port = SMTP_PORT
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        if self.debuglevel > 0: print 'connect:', (host, port)
-        try:
-            self.sock.connect((host, port))
-        except socket.error:
-            self.close()
-            raise
-        (code,msg)=self.getreply()
-        if self.debuglevel >0 : print "connect:", msg
-        return (code,msg)
+ 	if self.debuglevel > 0: print 'connect:', (host, port)
+ 	for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
+ 	    af, socktype, proto, canonname, sa = res
+ 	    try:
+ 		self.sock = socket.socket(af, socktype, proto)
+ 		if self.debuglevel > 0: print 'connect:', (host, port)
+ 		self.sock.connect(sa)
+ 	    except socket.error, msg:
+ 		if self.debuglevel > 0: print 'connect fail:', (host, port)
+ 		self.sock.close()
+ 		self.sock = None
+ 		continue
+ 	    break
+	if not self.sock:
+ 	    raise socket.error, msg
+        (code, msg) = self.getreply()
+        if self.debuglevel > 0: print "connect:", msg
+        return (code, msg)
 
     def send(self, str):
         """Send `str' to the server."""
Index: Lib/telnetlib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/telnetlib.py,v
retrieving revision 1.11
diff -u -r1.11 telnetlib.py
--- Lib/telnetlib.py	2001/03/01 04:27:19	1.11
+++ Lib/telnetlib.py	2001/06/24 04:41:48
@@ -136,8 +136,18 @@
             port = TELNET_PORT
         self.host = host
         self.port = port
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.connect((self.host, self.port))
+	for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
+	    af, socktype, proto, canonname, sa = res
+	    try:
+		self.sock = socket.socket(af, socktype, proto)
+		self.sock.connect(sa)
+	    except socket.error, msg:
+		self.sock.close()
+		self.sock = None
+		continue
+	    break
+        if not self.sock:
+	    raise socket.error, msg
 
     def __del__(self):
         """Destructor -- close the connection."""
Index: Modules/socketmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v
retrieving revision 1.144
diff -u -r1.144 socketmodule.c
--- Modules/socketmodule.c	2001/06/23 16:30:13	1.144
+++ Modules/socketmodule.c	2001/06/24 04:41:51
@@ -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
@@ -16,6 +16,7 @@
 
 - socket.error: exception raised for socket specific errors
 - socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd')
+- socket.gethostbyname2(hostname, af) --> host IP address (string)
 - socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...])
 - socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com')
 - socket.getprotobyname(protocolname) --> protocol number
@@ -25,6 +26,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
@@ -178,6 +182,10 @@
 #include <netpacket/packet.h>
 #endif
 
+#ifndef offsetof
+#define	offsetof(type, member)	((size_t)(&((type *)0)->member))
+#endif
+
 #ifndef O_NDELAY
 #define O_NDELAY O_NONBLOCK	/* For QNX only? */
 #endif
@@ -395,6 +403,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
@@ -471,85 +483,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) {
+			PyErr_SetString(PySocket_Error, gai_strerror(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);
+	}
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = af;
+	error = getaddrinfo(name, NULL, &hints, &res);
+	if (error) {
+		PyErr_SetString(PySocket_Error, gai_strerror(error));
+		return -1;
 	}
-	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));
+	memcpy((char *) addr_ret, res->ai_addr, res->ai_addrlen);
+	freeaddrinfo(res);
+	switch (addr_ret->sa_family) {
+	case AF_INET:
 		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");
+#ifdef INET6
+	case AF_INET6:
+		return 16;
 #endif
-#ifdef USE_GETHOSTBYNAME_LOCK
-		PyThread_release_lock(gethostbyname_lock);
-#endif
+	default:
+		PyErr_SetString(PySocket_Error, "unknown address family");
 		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);
-#endif
-	return h_length;
 }
 
 
@@ -558,13 +572,17 @@
    size numbers). */
 
 static PyObject *
-makeipaddr(struct sockaddr_in *addr)
+makeipaddr(struct sockaddr *addr, int addrlen)
 {
-	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) {
+		PyErr_SetString(PySocket_Error, gai_strerror(error));
+		return NULL;
+	}
 	return PyString_FromString(buf);
 }
 
@@ -593,10 +611,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);
 		}
@@ -609,6 +628,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)
@@ -668,7 +703,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;
@@ -691,7 +726,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);
@@ -700,6 +735,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:
 	{
@@ -732,7 +791,6 @@
 	}
 #endif
 
-
 	/* More cases here... */
 
 	default:
@@ -766,6 +824,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:
 	{
@@ -1632,6 +1698,52 @@
 Return the current host name.";
 
 
+/* Python interface to gethostbyname2(name, af). */
+
+/*ARGSUSED*/
+static PyObject *
+PySocket_gethostbyname2_common(char *name, int af)
+{
+	struct sockaddr_storage addrbuf;
+
+	if (setipaddr(name, (struct sockaddr *)&addrbuf, af) < 0)
+		return NULL;
+	switch (addrbuf.ss_family) {
+	case AF_INET:
+		return makeipaddr((struct sockaddr *)&addrbuf,
+			sizeof(struct sockaddr_in));
+#ifdef INET6
+	case AF_INET6:
+		return makeipaddr((struct sockaddr *)&addrbuf,
+			sizeof(struct sockaddr_in6));
+#endif
+	case AF_UNIX:
+		return makeipaddr((struct sockaddr *)&addrbuf,
+			sizeof(struct sockaddr_un));
+	default:
+		return makeipaddr((struct sockaddr *)&addrbuf,
+			sizeof(struct sockaddr));
+	}
+}
+
+/*ARGSUSED*/
+static PyObject *
+PySocket_gethostbyname2(PyObject *self, PyObject *args)
+{
+	char *name;
+	int af;
+
+	if (!PyArg_ParseTuple(args, "si:gethostbyname2", &name, &af))
+		return NULL;
+	return PySocket_gethostbyname2_common(name, af);
+}
+
+static char gethostbyname2_doc[] =
+"gethostbyname2(host, af) -> address\n\
+\n\
+Return the IP address (a string) for a host.";
+
+
 /* Python interface to gethostbyname(name). */
 
 /*ARGSUSED*/
@@ -1639,12 +1751,10 @@
 PySocket_gethostbyname(PyObject *self, PyObject *args)
 {
 	char *name;
-	struct sockaddr_in addrbuf;
+
 	if (!PyArg_ParseTuple(args, "s:gethostbyname", &name))
-		return NULL;
-	if (setipaddr(name, &addrbuf) < 0)
 		return NULL;
-	return makeipaddr(&addrbuf);
+	return PySocket_gethostbyname2_common(name, AF_INET);
 }
 
 static char gethostbyname_doc[] =
@@ -1656,13 +1766,14 @@
 /* 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 */
@@ -1673,6 +1784,28 @@
 #endif
 		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,
+		    "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)
@@ -1689,8 +1822,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);
@@ -1714,7 +1882,7 @@
 {
 	char *name;
 	struct hostent *h;
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
 	PyObject *ret;
 #ifdef HAVE_GETHOSTBYNAME_R
 	struct hostent hp_allocated;
@@ -1729,9 +1897,15 @@
 	int result;
 #endif
 #endif /* HAVE_GETHOSTBYNAME_R */
+#ifdef INET6
+	int af = PF_UNSPEC;
+#else
+	int af = PF_INET;
+#endif
+
 	if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name))
 		return NULL;
-	if (setipaddr(name, &addr) < 0)
+	if (setipaddr(name, (struct sockaddr *)&addr, af) < 0)
 		return NULL;
 	Py_BEGIN_ALLOW_THREADS
 #ifdef HAVE_GETHOSTBYNAME_R
@@ -1751,7 +1925,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
@@ -1771,7 +1945,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;
@@ -1788,40 +1967,55 @@
 	int result;
 #endif
 #endif /* HAVE_GETHOSTBYNAME_R */
+	char *ap;
+	int al;
+	int af;
 
 	if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num))
+		return NULL;
+	af = PF_UNSPEC;
+	if (setipaddr(ip_num, sa, af) < 0)
 		return NULL;
-	if (setipaddr(ip_num, &addr) < 0)
+	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
@@ -2121,6 +2315,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) {
+		PyErr_SetString(PySocket_Error, gai_strerror(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) {
+		PyErr_SetString(PySocket_Error, gai_strerror(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) {
+		PyErr_SetString(PySocket_Error, gai_strerror(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
 
@@ -2348,7 +2692,9 @@
 static PyMethodDef PySocket_methods[] = {
 	{"gethostbyname",	PySocket_gethostbyname,
 	 METH_VARARGS, gethostbyname_doc},
-	{"gethostbyname_ex",	PySocket_gethostbyname_ex,
+	{"gethostbyname2",	PySocket_gethostbyname2, 
+	 METH_VARARGS, gethostbyname2_doc},
+	{"gethostbyname_ex",	PySocket_gethostbyname_ex, 
 	 METH_VARARGS, ghbn_ex_doc},
 	{"gethostbyaddr",	PySocket_gethostbyaddr,
 	 METH_VARARGS, gethostbyaddr_doc},
@@ -2376,6 +2722,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},
@@ -2571,6 +2921,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 */
@@ -2924,6 +3277,98 @@
 	/* IPX options */
 #ifdef	IPX_TYPE
 	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 */
