Commit 47dfa4a8 authored by Guido van Rossum's avatar Guido van Rossum

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).
parent 45f41300
...@@ -150,6 +150,11 @@ those symbols that are defined in the \UNIX{} header files are defined; ...@@ -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. ...@@ -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: ...@@ -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): ...@@ -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 ...@@ -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 ...@@ -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: ...@@ -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: ...@@ -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) ...@@ -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[] = { ...@@ -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."); ...@@ -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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment