diff options
-rw-r--r-- | Doc/library/socket.rst | 15 | ||||
-rw-r--r-- | Lib/test/test_socket.py | 44 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2017-12-06-10-10-10.bpo-32221.ideco_.rst | 4 | ||||
-rw-r--r-- | Modules/socketmodule.c | 59 |
4 files changed, 28 insertions, 94 deletions
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 777710f..7edd4ba 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 a971f92..275384c 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1586,50 +1586,6 @@ class GeneralModuleTests(unittest.TestCase): 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 a88dcf4..0000000 --- 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 30afe81..5fe2431 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) { |