[Python-checkins] Revert "bpo-32221: makeipaddr(): remove interface part + speedup (GH-4724)" (#5394)

Yury Selivanov webhook-mailer at python.org
Sun Jan 28 16:08:35 EST 2018


https://github.com/python/cpython/commit/0ceb717689b04c0540d78c1ba93c0572c66c0994
commit: 0ceb717689b04c0540d78c1ba93c0572c66c0994
branch: master
author: Yury Selivanov <yury at magic.io>
committer: GitHub <noreply at github.com>
date: 2018-01-28T16:08:32-05:00
summary:

Revert "bpo-32221: makeipaddr(): remove interface part + speedup (GH-4724)" (#5394)

This reverts commit 47c0b1f7d4115e6f15e6776c1f91d28e7d96fe0c.

files:
D Misc/NEWS.d/next/Library/2017-12-06-10-10-10.bpo-32221.ideco_.rst
M Doc/library/socket.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c

diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 777710f16f26..7edd4ba36043 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -77,11 +77,6 @@ created.  Socket addresses are represented as follows:
   backward compatibility.  Note, however, omission of *scopeid* can cause problems
   in manipulating scoped IPv6 addresses.
 
-  .. versionchanged:: 3.7
-     For multicast addresses (with *scopeid* meaningful) *address* may not contain
-     ``%scope`` (or ``zone id``) part. This information is superfluous and may
-     be safely omitted (recommended).
-
 - :const:`AF_NETLINK` sockets are represented as pairs ``(pid, groups)``.
 
 - Linux-only support for TIPC is available using the :const:`AF_TIPC`
@@ -635,10 +630,6 @@ The :mod:`socket` module also offers various network-related services:
    .. versionchanged:: 3.2
       parameters can now be passed using keyword arguments.
 
-   .. versionchanged:: 3.7
-      for IPv6 multicast addresses, string representing an address will not
-      contain ``%scope`` part.
-
 .. function:: getfqdn([name])
 
    Return a fully qualified domain name for *name*. If *name* is omitted or empty,
@@ -697,8 +688,6 @@ The :mod:`socket` module also offers various network-related services:
    or numeric address representation in *host*.  Similarly, *port* can contain a
    string port name or a numeric port number.
 
-   For IPv6 addresses, ``%scope`` is appended to the host part if *sockaddr*
-   contains meaningful *scopeid*. Usually this happens for multicast addresses.
 
 .. function:: getprotobyname(protocolname)
 
@@ -1189,10 +1178,6 @@ to sockets.
       an exception, the method now retries the system call instead of raising
       an :exc:`InterruptedError` exception (see :pep:`475` for the rationale).
 
-   .. versionchanged:: 3.7
-      For multicast IPv6 address, first item of *address* does not contain
-      ``%scope`` part anymore. In order to get full IPv6 address use
-      :func:`getnameinfo`.
 
 .. method:: socket.recvmsg(bufsize[, ancbufsize[, flags]])
 
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index a971f921546f..275384c28fb3 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1586,50 +1586,6 @@ def test_flowinfo(self):
         with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
             self.assertRaises(OverflowError, s.bind, (support.HOSTv6, 0, -10))
 
-    @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
-    def test_getaddrinfo_ipv6_basic(self):
-        ((*_, sockaddr),) = socket.getaddrinfo(
-            'ff02::1de:c0:face:8D',  # Note capital letter `D`.
-            1234, socket.AF_INET6,
-            socket.SOCK_DGRAM,
-            socket.IPPROTO_UDP
-        )
-        self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 0))
-
-    @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
-    @unittest.skipUnless(
-        hasattr(socket, 'if_nameindex'),
-        'IPv6 scope id by interface name is not supported'
-    )
-    def test_getaddrinfo_ipv6_scopeid(self):
-        test_interface = 'lo'
-        ifindex = socket.if_nametoindex(test_interface)
-        ((*_, sockaddr),) = socket.getaddrinfo(
-            'ff02::1de:c0:face:8D%' + test_interface,
-            1234, socket.AF_INET6,
-            socket.SOCK_DGRAM,
-            socket.IPPROTO_UDP
-        )
-        # Note missing interface name part in IPv6 address
-        self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex))
-
-    @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
-    def test_getaddrinfo_ipv6_scopeid_numeric(self):
-        ((*_, sockaddr),) = socket.getaddrinfo(
-            'ff02::1de:c0:face:8D%42',
-            1234, socket.AF_INET6,
-            socket.SOCK_DGRAM,
-            socket.IPPROTO_UDP
-        )
-        # Note missing interface name part in IPv6 address
-        self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 42))
-
-    @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
-    def test_getnameinfo_ipv6_scopeid(self):
-        sockaddr = ('ff02::1de:c0:face:8D', 1234, 0, 100500)  # Note capital letter `D`.
-        nameinfo = socket.getnameinfo(sockaddr, socket.NI_NUMERICHOST | socket.NI_NUMERICSERV)
-        self.assertEqual(nameinfo, ('ff02::1de:c0:face:8d%100500', '1234'))
-
     def test_str_for_enums(self):
         # Make sure that the AF_* and SOCK_* constants have enum-like string
         # reprs.
diff --git a/Misc/NEWS.d/next/Library/2017-12-06-10-10-10.bpo-32221.ideco_.rst b/Misc/NEWS.d/next/Library/2017-12-06-10-10-10.bpo-32221.ideco_.rst
deleted file mode 100644
index a88dcf48e02b..000000000000
--- a/Misc/NEWS.d/next/Library/2017-12-06-10-10-10.bpo-32221.ideco_.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-Various functions returning tuple containig IPv6 addresses now omit ``%scope``
-part since the same information is already encoded in *scopeid* tuple item.
-Especially this speeds up :func:`socket.recvfrom` when it receives multicast
-packet since useless resolving of network interface name is omitted.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 30afe81d6352..5fe2431bee84 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1094,33 +1094,25 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int
 }
 
 
-/* Convert IPv4 sockaddr to a Python str. */
+/* Create a string object representing an IP address.
+   This is always a string of the form 'dd.dd.dd.dd' (with variable
+   size numbers). */
 
 static PyObject *
-make_ipv4_addr(const struct sockaddr_in *addr)
+makeipaddr(struct sockaddr *addr, int addrlen)
 {
-    char buf[INET_ADDRSTRLEN];
-    if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
-        return NULL;
-    }
-    return PyUnicode_FromString(buf);
-}
-
-#ifdef ENABLE_IPV6
-/* Convert IPv6 sockaddr to a Python str. */
+    char buf[NI_MAXHOST];
+    int error;
 
-static PyObject *
-make_ipv6_addr(const struct sockaddr_in6 *addr)
-{
-    char buf[INET6_ADDRSTRLEN];
-    if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
-        PyErr_SetFromErrno(PyExc_OSError);
+    error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0,
+        NI_NUMERICHOST);
+    if (error) {
+        set_gaierror(error);
         return NULL;
     }
     return PyUnicode_FromString(buf);
 }
-#endif
+
 
 #ifdef USE_BLUETOOTH
 /* Convert a string representation of a Bluetooth address into a numeric
@@ -1185,10 +1177,11 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
 
     case AF_INET:
     {
-        const struct sockaddr_in *a = (const struct sockaddr_in *)addr;
-        PyObject *addrobj = make_ipv4_addr(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);
         }
@@ -1232,10 +1225,11 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
 #ifdef ENABLE_IPV6
     case AF_INET6:
     {
-        const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)addr;
-        PyObject *addrobj = make_ipv6_addr(a);
+        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),
@@ -5042,14 +5036,14 @@ static PyObject *
 socket_gethostbyname(PyObject *self, PyObject *args)
 {
     char *name;
-    struct sockaddr_in addrbuf;
+    sock_addr_t addrbuf;
     PyObject *ret = NULL;
 
     if (!PyArg_ParseTuple(args, "et:gethostbyname", "idna", &name))
         return NULL;
-    if (setipaddr(name, (struct sockaddr *)&addrbuf,  sizeof(addrbuf), AF_INET) < 0)
+    if (setipaddr(name, SAS2SA(&addrbuf),  sizeof(addrbuf), AF_INET) < 0)
         goto finally;
-    ret = make_ipv4_addr(&addrbuf);
+    ret = makeipaddr(SAS2SA(&addrbuf), sizeof(struct sockaddr_in));
 finally:
     PyMem_Free(name);
     return ret;
@@ -5151,7 +5145,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
             sin.sin_len = sizeof(sin);
 #endif
             memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr));
-            tmp = make_ipv4_addr(&sin);
+            tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin));
 
             if (pch == h->h_addr_list && alen >= sizeof(sin))
                 memcpy((char *) addr, &sin, sizeof(sin));
@@ -5168,7 +5162,8 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
             sin6.sin6_len = sizeof(sin6);
 #endif
             memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr));
-            tmp = make_ipv6_addr(&sin6);
+            tmp = makeipaddr((struct sockaddr *)&sin6,
+                sizeof(sin6));
 
             if (pch == h->h_addr_list && alen >= sizeof(sin6))
                 memcpy((char *) addr, &sin6, sizeof(sin6));
@@ -5939,11 +5934,14 @@ socket_inet_ntop(PyObject *self, PyObject *args)
     Py_buffer packed_ip;
     const char* retval;
 #ifdef ENABLE_IPV6
-    char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+    char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1];
 #else
-    char ip[INET_ADDRSTRLEN];
+    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_ip)) {
         return NULL;
     }
@@ -5971,7 +5969,6 @@ socket_inet_ntop(PyObject *self, PyObject *args)
         return NULL;
     }
 
-    /* inet_ntop guarantee NUL-termination of resulting string. */
     retval = inet_ntop(af, packed_ip.buf, ip, sizeof(ip));
     PyBuffer_Release(&packed_ip);
     if (!retval) {



More information about the Python-checkins mailing list