diff options
| -rw-r--r-- | Doc/library/socket.rst | 4 | ||||
| -rw-r--r-- | Lib/test/test_socket.py | 16 | ||||
| -rw-r--r-- | Modules/socketmodule.c | 112 | 
3 files changed, 128 insertions, 4 deletions
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 658b8c9..b01238c 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -594,7 +594,7 @@ The module :mod:`socket` exports the following constants and functions:     both the value of *address_family* and the underlying implementation of     :c:func:`inet_pton`. -   Availability: Unix (maybe not all platforms). +   Availability: Unix (maybe not all platforms), Windows.  .. function:: inet_ntop(address_family, packed_ip) @@ -610,7 +610,7 @@ The module :mod:`socket` exports the following constants and functions:     specified address family, :exc:`ValueError` will be raised.  A     :exc:`OSError` is raised for errors from the call to :func:`inet_ntop`. -   Availability: Unix (maybe not all platforms). +   Availability: Unix (maybe not all platforms), Windows.  .. diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index beff31a..a7c2516 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -980,6 +980,14 @@ class GeneralModuleTests(unittest.TestCase):                  return          except ImportError:              return + +        if sys.platform == "win32": +            try: +                inet_pton(AF_INET6, '::') +            except OSError as e: +                if e.winerror == 10022: +                    return # IPv6 might not be installed on this PC +          f = lambda a: inet_pton(AF_INET6, a)          assertInvalid = lambda a: self.assertRaises(              (OSError, ValueError), f, a @@ -1058,6 +1066,14 @@ class GeneralModuleTests(unittest.TestCase):                  return          except ImportError:              return + +        if sys.platform == "win32": +            try: +                inet_ntop(AF_INET6, b'\x00' * 16) +            except OSError as e: +                if e.winerror == 10022: +                    return # IPv6 might not be installed on this PC +          f = lambda a: inet_ntop(AF_INET6, a)          assertInvalid = lambda a: self.assertRaises(              (OSError, ValueError), f, a diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0396bf4..fa61cfd 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -5023,7 +5023,7 @@ socket_inet_ntoa(PyObject *self, PyObject *args)      return PyUnicode_FromString(inet_ntoa(packed_addr));  } -#ifdef HAVE_INET_PTON +#if defined(HAVE_INET_PTON) || defined(MS_WINDOWS)  PyDoc_STRVAR(inet_pton_doc,  "inet_pton(af, ip) -> packed IP address string\n\ @@ -5031,6 +5031,10 @@ PyDoc_STRVAR(inet_pton_doc,  Convert an IP address from string format to a packed string suitable\n\  for use with low-level network functions."); +#endif + +#ifdef HAVE_INET_PTON +  static PyObject *  socket_inet_pton(PyObject *self, PyObject *args)  { @@ -5075,12 +5079,52 @@ socket_inet_pton(PyObject *self, PyObject *args)          return NULL;      }  } +#elif defined(MS_WINDOWS) + +static PyObject * +socket_inet_pton(PyObject *self, PyObject *args) +{ +    int af; +    char* ip; +    struct sockaddr_in6 addr; +    INT ret, size; + +    if (!PyArg_ParseTuple(args, "is:inet_pton", &af, &ip)) { +        return NULL; +    } + +    size = sizeof(addr);  +    ret = WSAStringToAddressA(ip, af, NULL, (LPSOCKADDR)&addr, &size); + +    if (ret) { +        PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); +        return NULL; +    } else if(af == AF_INET) { +        struct sockaddr_in *addr4 = (struct sockaddr_in*)&addr; +        return PyBytes_FromStringAndSize((const char *)&(addr4->sin_addr),  +                                         sizeof(addr4->sin_addr)); +    } else if (af == AF_INET6) { +        return PyBytes_FromStringAndSize((const char *)&(addr.sin6_addr),  +                                          sizeof(addr.sin6_addr)); +    } else { +        PyErr_SetString(PyExc_OSError, "unknown address family"); +        return NULL; +    } +} + +#endif + +#if defined(HAVE_INET_PTON) || defined(MS_WINDOWS)  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."); +#endif + + +#ifdef HAVE_INET_PTON  static PyObject *  socket_inet_ntop(PyObject *self, PyObject *args)  { @@ -5134,6 +5178,70 @@ socket_inet_ntop(PyObject *self, PyObject *args)      return NULL;  } +#elif defined(MS_WINDOWS) + +static PyObject * +socket_inet_ntop(PyObject *self, PyObject *args) +{ +    int af; +    char* packed; +    int len; +    struct sockaddr_in6 addr; +    DWORD addrlen, ret, retlen; +#ifdef ENABLE_IPV6 +    char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; +#else +    char ip[INET_ADDRSTRLEN + 1]; +#endif + +    /* Guarantee NUL-termination for PyUnicode_FromString() below */ +    memset((void *) &ip[0], '\0', sizeof(ip)); + +    if (!PyArg_ParseTuple(args, "iy#:inet_ntop", &af, &packed, &len)) { +        return NULL; +    } + +    if (af == AF_INET) { +        struct sockaddr_in * addr4 = (struct sockaddr_in *)&addr; + +        if (len != sizeof(struct in_addr)) { +            PyErr_SetString(PyExc_ValueError, +                "invalid length of packed IP address string"); +            return NULL; +        } +        memset(addr4, 0, sizeof(struct sockaddr_in)); +        addr4->sin_family = AF_INET; +        memcpy(&(addr4->sin_addr), packed, sizeof(addr4->sin_addr)); +        addrlen = sizeof(struct sockaddr_in); +    } else if (af == AF_INET6) { +        if (len != sizeof(struct in6_addr)) { +            PyErr_SetString(PyExc_ValueError, +                "invalid length of packed IP address string"); +            return NULL; +        } + +        memset(&addr, 0, sizeof(addr)); +        addr.sin6_family = AF_INET6; +        memcpy(&(addr.sin6_addr), packed, sizeof(addr.sin6_addr)); +        addrlen = sizeof(addr); +    } else { +        PyErr_Format(PyExc_ValueError, +            "unknown address family %d", af); +        return NULL; +    } + +    retlen = sizeof(ip); +    ret = WSAAddressToStringA((struct sockaddr*)&addr, addrlen, NULL,  +                              ip, &retlen); + +    if (ret) { +        PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); +        return NULL; +    } else { +        return PyUnicode_FromString(ip); +    } +} +  #endif /* HAVE_INET_PTON */  /* Python interface to getaddrinfo(host, port). */ @@ -5600,7 +5708,7 @@ static PyMethodDef socket_methods[] = {       METH_VARARGS, inet_aton_doc},      {"inet_ntoa",               socket_inet_ntoa,       METH_VARARGS, inet_ntoa_doc}, -#ifdef HAVE_INET_PTON +#if defined(HAVE_INET_PTON) || defined(MS_WINDOWS)      {"inet_pton",               socket_inet_pton,       METH_VARARGS, inet_pton_doc},      {"inet_ntop",               socket_inet_ntop,  | 
