Index: Lib/socket.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/socket.py,v retrieving revision 1.35 diff -c -r1.35 socket.py *** Lib/socket.py 22 Aug 2002 17:31:16 -0000 1.35 --- Lib/socket.py 5 Feb 2003 02:30:17 -0000 *************** *** 30,35 **** --- 30,36 ---- SocketType -- type object for socket objects error -- exception raised for I/O errors + has_ipv6 -- boolean value indicating if IPv6 is supported Integer constants: Index: Modules/socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.252 diff -c -r1.252 socketmodule.c *** Modules/socketmodule.c 31 Jan 2003 18:15:58 -0000 1.252 --- Modules/socketmodule.c 5 Feb 2003 02:30:19 -0000 *************** *** 35,40 **** --- 35,41 ---- --> List of (family, socktype, proto, canonname, sockaddr) - socket.getnameinfo(sockaddr, flags) --> (host, port) - socket.AF_INET, socket.SOCK_STREAM, etc.: constants from + - socket.has_ipv6: boolean value indicating if IPv6 is supported - socket.inet_aton(IP address) -> 32-bit packed IP representation - socket.inet_ntoa(packed IP) -> IP address string - socket.getdefaulttimeout() -> None | float *************** *** 2757,2762 **** --- 2758,2867 ---- return PyString_FromString(inet_ntoa(packed_addr)); } + PyDoc_STRVAR(inet_pton_doc, + "inet_pton(af, ip) -> packed IP address string\n\ + \n\ + Convert an IP address from string format to a packed string suitable\n\ + for use with low-level network functions."); + + static PyObject * + socket_inet_pton(PyObject *self, PyObject *args) + { + int af; + char* ip; + int retval; + #ifdef ENABLE_IPV6 + char packed[MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; + #else + char packed[sizeof(struct in_addr)]; + #endif + + if (!PyArg_ParseTuple(args, "is:inet_pton", &af, &ip)) { + return NULL; + } + + retval = inet_pton(af, ip, packed); + if (retval < 0) { + PyErr_SetFromErrno(socket_error); + return NULL; + } else if (retval == 0) { + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_pton"); + return NULL; + } else if (af == AF_INET) { + return PyString_FromStringAndSize(packed, + sizeof(struct in_addr)); + #ifdef ENABLE_IPV6 + } else if (af == AF_INET6) { + return PyString_FromStringAndSize(packed, + sizeof(struct in6_addr)); + #endif + } else { + PyErr_SetString(socket_error, "unknown address family"); + return NULL; + } + } + + PyDoc_STRVAR(inet_ntop_doc, + "inet_ntop(af, packed_ip) -> string formatted IP address\n\ + \n\ + Convert a packed IP address of the given family to string format."); + + static PyObject * + socket_inet_ntop(PyObject *self, PyObject *args) + { + int af; + char* packed; + int len; + const char* retval; + #ifdef ENABLE_IPV6 + char ip[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + #else + char ip[INET_ADDRSTRLEN]; + #endif + if (!PyArg_ParseTuple(args, "is#:inet_ntop", &af, &packed, &len)) { + return NULL; + } + + if (af == AF_INET) { + if (len != sizeof(struct in_addr)) { + PyErr_SetString(PyExc_ValueError, + "invalid length of packed IP address string"); + return NULL; + } + } + #ifdef ENABLE_IPV6 + } else if (af == AF_INET6) { + if (len != sizeof(struct in6_addr)) { + PyErr_SetString(PyExc_ValueError, + "invalid length of packed IP address string"); + return NULL; + } + } + #endif + else { + PyErr_Format(PyExc_ValueError, + "unknown address family %d", af); + return NULL; + } + + retval = inet_ntop(af, packed, ip, sizeof(ip)); + if (!retval) { + PyErr_SetFromErrno(socket_error); + return NULL; + } else if (af == AF_INET) { + return PyString_FromString(retval); + #ifdef ENABLE_IPV6 + } else if (af == AF_INET6) { + return PyString_FromString(retval); + #endif + } + + /* NOTREACHED */ + PyErr_SetString(PyExc_RuntimeError, "invalid handling of inet_ntop"); + return NULL; + } + /* Python interface to getaddrinfo(host, port). */ /*ARGSUSED*/ *************** *** 2998,3003 **** --- 3103,3112 ---- METH_VARARGS, inet_aton_doc}, {"inet_ntoa", socket_inet_ntoa, METH_VARARGS, inet_ntoa_doc}, + {"inet_pton", socket_inet_pton, + METH_VARARGS, inet_pton_doc}, + {"inet_ntop", socket_inet_ntop, + METH_VARARGS, inet_ntop_doc}, {"getaddrinfo", socket_getaddrinfo, METH_VARARGS, getaddrinfo_doc}, {"getnameinfo", socket_getnameinfo, *************** *** 3141,3147 **** PyMODINIT_FUNC init_socket(void) { ! PyObject *m; if (!os_init()) return; --- 3250,3256 ---- PyMODINIT_FUNC init_socket(void) { ! PyObject *m, *has_ipv6; if (!os_init()) return; *************** *** 3176,3181 **** --- 3285,3298 ---- if (PyModule_AddObject(m, "socket", (PyObject *)&sock_type) != 0) return; + + #ifdef ENABLE_IPV6 + has_ipv6 = Py_True; + #else + has_ipv6 = Py_False; + #endif + Py_INCREF(has_ipv6); + PyModule_AddObject(m, "has_ipv6", has_ipv6); /* Export C API */ if (PyModule_AddObject(m, PySocket_CAPI_NAME, Index: Lib/test/test_socket.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_socket.py,v retrieving revision 1.61 diff -c -r1.61 test_socket.py *** Lib/test/test_socket.py 26 Dec 2002 17:04:45 -0000 1.61 --- Lib/test/test_socket.py 5 Feb 2003 02:30:20 -0000 *************** *** 318,323 **** --- 318,382 ---- # Check that setting it to an invalid type raises TypeError self.assertRaises(TypeError, socket.setdefaulttimeout, "spam") + def testIPv4toString(self): + from socket import inet_aton as f, inet_pton, AF_INET + g = lambda a: inet_pton(AF_INET, a) + + self.assertEquals('\x00\x00\x00\x00', f('0.0.0.0')) + self.assertEquals('\xff\x00\xff\x00', f('255.0.255.0')) + self.assertEquals('\xaa\xaa\xaa\xaa', f('170.170.170.170')) + self.assertEquals('\x01\x02\x03\x04', f('1.2.3.4')) + + self.assertEquals('\x00\x00\x00\x00', g('0.0.0.0')) + self.assertEquals('\xff\x00\xff\x00', g('255.0.255.0')) + self.assertEquals('\xaa\xaa\xaa\xaa', g('170.170.170.170')) + + def testIPv6toString(self): + try: + from socket import inet_pton, AF_INET6, has_ipv6 + if not has_ipv6: + return + except ImportError: + return + f = lambda a: inet_pton(AF_INET6, a) + + self.assertEquals('\x00' * 16, f('::')) + self.assertEquals('\x00' * 16, f('0::0')) + self.assertEquals('\x00\x01' + '\x00' * 14, f('1::')) + self.assertEquals( + '\x45\xef\x76\xcb\x00\x1a\x56\xef\xaf\xeb\x0b\xac\x19\x24\xae\xae', + f('45ef:76cb:1a:56ef:afeb:bac:1924:aeae') + ) + + def testStringToIPv4(self): + from socket import inet_ntoa as f, inet_ntop, AF_INET + g = lambda a: inet_ntop(AF_INET, a) + + self.assertEquals('1.0.1.0', f('\x01\x00\x01\x00')) + self.assertEquals('170.85.170.85', f('\xaa\x55\xaa\x55')) + self.assertEquals('255.255.255.255', f('\xff\xff\xff\xff')) + self.assertEquals('1.2.3.4', f('\x01\x02\x03\x04')) + + self.assertEquals('1.0.1.0', g('\x01\x00\x01\x00')) + self.assertEquals('170.85.170.85', g('\xaa\x55\xaa\x55')) + self.assertEquals('255.255.255.255', g('\xff\xff\xff\xff')) + + def testStringToIPv6(self): + try: + from socket import inet_ntop, AF_INET6, has_ipv6 + if not has_ipv6: + return + except ImportError: + return + f = lambda a: inet_ntop(AF_INET6, a) + + self.assertEquals('::', f('\x00' * 16)) + self.assertEquals('::1', f('\x00' * 15 + '\x01')) + self.assertEquals( + 'aef:b01:506:1001:ffff:9997:55:170', + f('\x0a\xef\x0b\x01\x05\x06\x10\x01\xff\xff\x99\x97\x00\x55\x01\x70') + ) + # XXX The following don't test module-level functionality... def testSockName(self): Index: Misc/ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/ACKS,v retrieving revision 1.225 diff -c -r1.225 ACKS *** Misc/ACKS 27 Jan 2003 22:19:55 -0000 1.225 --- Misc/ACKS 5 Feb 2003 02:30:20 -0000 *************** *** 81,86 **** --- 81,87 ---- Tarn Weisner Burton Lee Busby Ralph Butler + Jp Calderone Daniel Calvelo Brett Cannon Mike Carlton Index: Misc/NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.638 diff -c -r1.638 NEWS *** Misc/NEWS 3 Feb 2003 15:48:10 -0000 1.638 --- Misc/NEWS 5 Feb 2003 02:30:23 -0000 *************** *** 33,38 **** --- 33,42 ---- Extension modules ----------------- + - The socket module now provides the functions inet_pton and inet_ntop + for converting between string and packed representation of IP addresses. + See SF patch #658327. + - Added an itertools module containing high speed, memory efficient looping constructs inspired by tools from Haskell and SML. Index: Doc/lib/libsocket.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsocket.tex,v retrieving revision 1.68 diff -c -r1.68 libsocket.tex *** Doc/lib/libsocket.tex 13 Jun 2002 15:07:43 -0000 1.68 --- Doc/lib/libsocket.tex 5 Feb 2003 02:30:23 -0000 *************** *** 150,155 **** --- 150,160 ---- for a few symbols, default values are provided. \end{datadesc} + \begin{datadesc}{has_ipv6} + This constant contains a boolean value which indicates if IPv6 is + supported on this platform. + \end{datadesc} + \begin{funcdesc}{getaddrinfo}{host, port\optional{, family, socktype, proto, flags}} Resolves the \var{host}/\var{port} argument, into a sequence of *************** *** 347,352 **** --- 352,394 ---- \function{inet_ntoa()} does not support IPv6, and \function{getnameinfo()} should be used instead for IPv4/v6 dual stack support. + \end{funcdesc} + + \begin{funcdesc}{inet_pton}{address_family, ip_string} + Convert an IP address from its family-specific string format to a packed, + binary format. + + Supported values for address_family are currently \constant{AF_INET} + and \constant{AF_INET6}. + + \function{inet_pton()} is useful when a library or network protocol calls for + an object of type \ctype{struct in_addr} (similar to \function{inet_aton()}) + or \ctype{struct in6_addr}. + + If the IP address string passed to this function is invalid, + \exception{socket.error} will be raised. Note that exactly what is valid + depends on both the value of \var{address_family} and the underlying + implementation of \cfunction{inet_pton()}. + \versionadded{2.3} + \end{funcdesc} + + \begin{funcdesc}{inet_ntop}{address_family, packed_ip} + Convert a packed IP address (a string of some number of characters) to its + standard, family-specific string representation (for example, '7.10.0.5' or + '5aef:2b::8') + + Supported values for address_family are currently \constant{AF_INET} + and \constant{AF_INET6}. + + \function{inet_pton()} is useful when a library or network protocol calls for + an object of type \ctype{struct in_addr} (similar to \function{inet_aton()}) + or \ctype{struct in6_addr}. + + If the string passed to this function is not the correct length for the + specified address family, \exception{ValueError} will be raised. + A \exception{socket.error} is raised for errors from the call to + \function{inet_ntop()}. + \versionadded{2.3} \end{funcdesc} \begin{datadesc}{SocketType}