Patch by Jp Calderone:
- 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. This still needs a bit of work in the doc area, because it is not available on all platforms (especially not on Windows).
This commit is contained in:
parent
45f4130029
commit
47dfa4a89a
@ -150,6 +150,11 @@ those symbols that are defined in the \UNIX{} header files are defined;
|
|||||||
for a few symbols, default values are provided.
|
for a few symbols, default values are provided.
|
||||||
\end{datadesc}
|
\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}}
|
\begin{funcdesc}{getaddrinfo}{host, port\optional{, family, socktype, proto, flags}}
|
||||||
|
|
||||||
Resolves the \var{host}/\var{port} argument, into a sequence of
|
Resolves the \var{host}/\var{port} argument, into a sequence of
|
||||||
@ -349,6 +354,43 @@ length, \exception{socket.error} will be raised.
|
|||||||
support.
|
support.
|
||||||
\end{funcdesc}
|
\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{funcdesc}{getdefaulttimeout}{}
|
\begin{funcdesc}{getdefaulttimeout}{}
|
||||||
Return the default timeout in floating seconds for new socket objects.
|
Return the default timeout in floating seconds for new socket objects.
|
||||||
A value of \code{None} indicates that new socket objects have no timeout.
|
A value of \code{None} indicates that new socket objects have no timeout.
|
||||||
|
@ -30,6 +30,7 @@ Special objects:
|
|||||||
|
|
||||||
SocketType -- type object for socket objects
|
SocketType -- type object for socket objects
|
||||||
error -- exception raised for I/O errors
|
error -- exception raised for I/O errors
|
||||||
|
has_ipv6 -- boolean value indicating if IPv6 is supported
|
||||||
|
|
||||||
Integer constants:
|
Integer constants:
|
||||||
|
|
||||||
|
@ -318,6 +318,65 @@ class GeneralModuleTests(unittest.TestCase):
|
|||||||
# Check that setting it to an invalid type raises TypeError
|
# Check that setting it to an invalid type raises TypeError
|
||||||
self.assertRaises(TypeError, socket.setdefaulttimeout, "spam")
|
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...
|
# XXX The following don't test module-level functionality...
|
||||||
|
|
||||||
def testSockName(self):
|
def testSockName(self):
|
||||||
|
@ -83,6 +83,7 @@ Alastair Burt
|
|||||||
Tarn Weisner Burton
|
Tarn Weisner Burton
|
||||||
Lee Busby
|
Lee Busby
|
||||||
Ralph Butler
|
Ralph Butler
|
||||||
|
Jp Calderone
|
||||||
Daniel Calvelo
|
Daniel Calvelo
|
||||||
Brett Cannon
|
Brett Cannon
|
||||||
Mike Carlton
|
Mike Carlton
|
||||||
|
@ -383,6 +383,10 @@ Extension modules
|
|||||||
zlib test suite using the unittest module. (SF bug #640230 and
|
zlib test suite using the unittest module. (SF bug #640230 and
|
||||||
patch #678531.)
|
patch #678531.)
|
||||||
|
|
||||||
|
- 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
|
- Added an itertools module containing high speed, memory efficient
|
||||||
looping constructs inspired by tools from Haskell and SML.
|
looping constructs inspired by tools from Haskell and SML.
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ Module interface:
|
|||||||
--> List of (family, socktype, proto, canonname, sockaddr)
|
--> List of (family, socktype, proto, canonname, sockaddr)
|
||||||
- socket.getnameinfo(sockaddr, flags) --> (host, port)
|
- socket.getnameinfo(sockaddr, flags) --> (host, port)
|
||||||
- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
|
- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h>
|
||||||
|
- socket.has_ipv6: boolean value indicating if IPv6 is supported
|
||||||
- socket.inet_aton(IP address) -> 32-bit packed IP representation
|
- socket.inet_aton(IP address) -> 32-bit packed IP representation
|
||||||
- socket.inet_ntoa(packed IP) -> IP address string
|
- socket.inet_ntoa(packed IP) -> IP address string
|
||||||
- socket.getdefaulttimeout() -> None | float
|
- socket.getdefaulttimeout() -> None | float
|
||||||
@ -62,6 +63,9 @@ Local naming conventions:
|
|||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
#undef MAX
|
||||||
|
#define MAX(x, y) ((x) < (y) ? (y) : (x))
|
||||||
|
|
||||||
/* Socket object documentation */
|
/* Socket object documentation */
|
||||||
PyDoc_STRVAR(sock_doc,
|
PyDoc_STRVAR(sock_doc,
|
||||||
"socket([family[, type[, proto]]]) -> socket object\n\
|
"socket([family[, type[, proto]]]) -> socket object\n\
|
||||||
@ -2776,6 +2780,100 @@ socket_inet_ntoa(PyObject *self, PyObject *args)
|
|||||||
return PyString_FromString(inet_ntoa(packed_addr));
|
return PyString_FromString(inet_ntoa(packed_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_INET_PTON
|
||||||
|
|
||||||
|
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;
|
||||||
|
char packed[MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
|
||||||
|
|
||||||
|
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));
|
||||||
|
} else if (af == AF_INET6) {
|
||||||
|
return PyString_FromStringAndSize(packed,
|
||||||
|
sizeof(struct in6_addr));
|
||||||
|
} 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;
|
||||||
|
char ip[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
|
||||||
|
|
||||||
|
/* Guarantee NUL-termination for PyString_FromString() below */
|
||||||
|
memset((void *) &ip[0], '\0', sizeof(ip) + 1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else if (af == AF_INET6) {
|
||||||
|
if (len != sizeof(struct in6_addr)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"invalid length of packed IP address string");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} 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 {
|
||||||
|
return PyString_FromString(retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "invalid handling of inet_ntop");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_INET_PTON */
|
||||||
|
|
||||||
/* Python interface to getaddrinfo(host, port). */
|
/* Python interface to getaddrinfo(host, port). */
|
||||||
|
|
||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
@ -3035,6 +3133,12 @@ static PyMethodDef socket_methods[] = {
|
|||||||
METH_VARARGS, inet_aton_doc},
|
METH_VARARGS, inet_aton_doc},
|
||||||
{"inet_ntoa", socket_inet_ntoa,
|
{"inet_ntoa", socket_inet_ntoa,
|
||||||
METH_VARARGS, inet_ntoa_doc},
|
METH_VARARGS, inet_ntoa_doc},
|
||||||
|
#ifdef HAVE_INET_PTON
|
||||||
|
{"inet_pton", socket_inet_pton,
|
||||||
|
METH_VARARGS, inet_pton_doc},
|
||||||
|
{"inet_ntop", socket_inet_ntop,
|
||||||
|
METH_VARARGS, inet_ntop_doc},
|
||||||
|
#endif
|
||||||
{"getaddrinfo", socket_getaddrinfo,
|
{"getaddrinfo", socket_getaddrinfo,
|
||||||
METH_VARARGS, getaddrinfo_doc},
|
METH_VARARGS, getaddrinfo_doc},
|
||||||
{"getnameinfo", socket_getnameinfo,
|
{"getnameinfo", socket_getnameinfo,
|
||||||
@ -3178,7 +3282,7 @@ See the socket module for documentation.");
|
|||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
init_socket(void)
|
init_socket(void)
|
||||||
{
|
{
|
||||||
PyObject *m;
|
PyObject *m, *has_ipv6;
|
||||||
|
|
||||||
if (!os_init())
|
if (!os_init())
|
||||||
return;
|
return;
|
||||||
@ -3214,6 +3318,14 @@ init_socket(void)
|
|||||||
(PyObject *)&sock_type) != 0)
|
(PyObject *)&sock_type) != 0)
|
||||||
return;
|
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 */
|
/* Export C API */
|
||||||
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
|
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
|
||||||
PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL)
|
PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL)
|
||||||
@ -3800,6 +3912,7 @@ init_socket(void)
|
|||||||
#ifndef HAVE_INET_PTON
|
#ifndef HAVE_INET_PTON
|
||||||
|
|
||||||
/* Simplistic emulation code for inet_pton that only works for IPv4 */
|
/* Simplistic emulation code for inet_pton that only works for IPv4 */
|
||||||
|
/* These are not exposed because they do not set errno properly */
|
||||||
|
|
||||||
int
|
int
|
||||||
inet_pton(int af, const char *src, void *dst)
|
inet_pton(int af, const char *src, void *dst)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user