mirror of
				https://github.com/python/cpython.git
				synced 2025-10-25 18:54:53 +00:00 
			
		
		
		
	bpo-37007: Implement socket.if_nametoindex(), if_indextoname() and if_nameindex() on Windows (GH-13522)
This commit is contained in:
		
							parent
							
								
									fecb75c1bb
								
							
						
					
					
						commit
						8f96c9f8ed
					
				
					 6 changed files with 79 additions and 28 deletions
				
			
		|  | @ -1034,10 +1034,13 @@ The :mod:`socket` module also offers various network-related services: | ||||||
|    (index int, name string) tuples. |    (index int, name string) tuples. | ||||||
|    :exc:`OSError` if the system call fails. |    :exc:`OSError` if the system call fails. | ||||||
| 
 | 
 | ||||||
|    .. availability:: Unix. |    .. availability:: Unix, Windows. | ||||||
| 
 | 
 | ||||||
|    .. versionadded:: 3.3 |    .. versionadded:: 3.3 | ||||||
| 
 | 
 | ||||||
|  |    .. versionchanged:: 3.8 | ||||||
|  |       Windows support was added. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: if_nametoindex(if_name) | .. function:: if_nametoindex(if_name) | ||||||
| 
 | 
 | ||||||
|  | @ -1045,10 +1048,13 @@ The :mod:`socket` module also offers various network-related services: | ||||||
|    interface name. |    interface name. | ||||||
|    :exc:`OSError` if no interface with the given name exists. |    :exc:`OSError` if no interface with the given name exists. | ||||||
| 
 | 
 | ||||||
|    .. availability:: Unix. |    .. availability:: Unix, Windows. | ||||||
| 
 | 
 | ||||||
|    .. versionadded:: 3.3 |    .. versionadded:: 3.3 | ||||||
| 
 | 
 | ||||||
|  |    .. versionchanged:: 3.8 | ||||||
|  |       Windows support was added. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| .. function:: if_indextoname(if_index) | .. function:: if_indextoname(if_index) | ||||||
| 
 | 
 | ||||||
|  | @ -1056,10 +1062,13 @@ The :mod:`socket` module also offers various network-related services: | ||||||
|    interface index number. |    interface index number. | ||||||
|    :exc:`OSError` if no interface with the given index exists. |    :exc:`OSError` if no interface with the given index exists. | ||||||
| 
 | 
 | ||||||
|    .. availability:: Unix. |    .. availability:: Unix, Windows. | ||||||
| 
 | 
 | ||||||
|    .. versionadded:: 3.3 |    .. versionadded:: 3.3 | ||||||
| 
 | 
 | ||||||
|  |    .. versionchanged:: 3.8 | ||||||
|  |       Windows support was added. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| .. _socket-objects: | .. _socket-objects: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -556,6 +556,10 @@ convenience functions to automate the necessary tasks usually involved when | ||||||
| creating a server socket, including accepting both IPv4 and IPv6 connections | creating a server socket, including accepting both IPv4 and IPv6 connections | ||||||
| on the same socket.  (Contributed by Giampaolo Rodola in :issue:`17561`.) | on the same socket.  (Contributed by Giampaolo Rodola in :issue:`17561`.) | ||||||
| 
 | 
 | ||||||
|  | The :func:`socket.if_nameindex()`, :func:`socket.if_nametoindex()`, and | ||||||
|  | :func:`socket.if_indextoname()` functions have been implemented on Windows. | ||||||
|  | (Contributed by Zackery Spytz in :issue:`37007`.) | ||||||
|  | 
 | ||||||
| shlex | shlex | ||||||
| ---------- | ---------- | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -973,16 +973,18 @@ def testInterfaceNameIndex(self): | ||||||
|             self.assertIsInstance(_name, str) |             self.assertIsInstance(_name, str) | ||||||
|             self.assertEqual(name, _name) |             self.assertEqual(name, _name) | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(hasattr(socket, 'if_nameindex'), |     @unittest.skipUnless(hasattr(socket, 'if_indextoname'), | ||||||
|                          'socket.if_nameindex() not available.') |                          'socket.if_indextoname() not available.') | ||||||
|     def testInvalidInterfaceNameIndex(self): |     def testInvalidInterfaceIndexToName(self): | ||||||
|         # test nonexistent interface index/name |  | ||||||
|         self.assertRaises(OSError, socket.if_indextoname, 0) |         self.assertRaises(OSError, socket.if_indextoname, 0) | ||||||
|         self.assertRaises(OSError, socket.if_nametoindex, '_DEADBEEF') |  | ||||||
|         # test with invalid values |  | ||||||
|         self.assertRaises(TypeError, socket.if_nametoindex, 0) |  | ||||||
|         self.assertRaises(TypeError, socket.if_indextoname, '_DEADBEEF') |         self.assertRaises(TypeError, socket.if_indextoname, '_DEADBEEF') | ||||||
| 
 | 
 | ||||||
|  |     @unittest.skipUnless(hasattr(socket, 'if_nametoindex'), | ||||||
|  |                          'socket.if_nametoindex() not available.') | ||||||
|  |     def testInvalidInterfaceNameToIndex(self): | ||||||
|  |         self.assertRaises(TypeError, socket.if_nametoindex, 0) | ||||||
|  |         self.assertRaises(OSError, socket.if_nametoindex, '_DEADBEEF') | ||||||
|  | 
 | ||||||
|     @unittest.skipUnless(hasattr(sys, 'getrefcount'), |     @unittest.skipUnless(hasattr(sys, 'getrefcount'), | ||||||
|                          'test needs sys.getrefcount()') |                          'test needs sys.getrefcount()') | ||||||
|     def testRefCountGetNameInfo(self): |     def testRefCountGetNameInfo(self): | ||||||
|  | @ -1638,9 +1640,7 @@ def test_getaddrinfo_ipv6_basic(self): | ||||||
|         self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 0)) |         self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, 0)) | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') |     @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') | ||||||
|     @unittest.skipUnless( |     @unittest.skipIf(sys.platform == 'win32', 'does not work on Windows') | ||||||
|         hasattr(socket, 'if_nameindex'), |  | ||||||
|         'if_nameindex is not supported') |  | ||||||
|     @unittest.skipIf(AIX, 'Symbolic scope id does not work') |     @unittest.skipIf(AIX, 'Symbolic scope id does not work') | ||||||
|     def test_getaddrinfo_ipv6_scopeid_symbolic(self): |     def test_getaddrinfo_ipv6_scopeid_symbolic(self): | ||||||
|         # Just pick up any network interface (Linux, Mac OS X) |         # Just pick up any network interface (Linux, Mac OS X) | ||||||
|  | @ -1672,9 +1672,7 @@ def test_getaddrinfo_ipv6_scopeid_numeric(self): | ||||||
|         self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex)) |         self.assertEqual(sockaddr, ('ff02::1de:c0:face:8d', 1234, 0, ifindex)) | ||||||
| 
 | 
 | ||||||
|     @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') |     @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.') | ||||||
|     @unittest.skipUnless( |     @unittest.skipIf(sys.platform == 'win32', 'does not work on Windows') | ||||||
|         hasattr(socket, 'if_nameindex'), |  | ||||||
|         'if_nameindex is not supported') |  | ||||||
|     @unittest.skipIf(AIX, 'Symbolic scope id does not work') |     @unittest.skipIf(AIX, 'Symbolic scope id does not work') | ||||||
|     def test_getnameinfo_ipv6_scopeid_symbolic(self): |     def test_getnameinfo_ipv6_scopeid_symbolic(self): | ||||||
|         # Just pick up any network interface. |         # Just pick up any network interface. | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | Implement :func:`socket.if_nameindex()`, :func:`socket.if_nametoindex()`, and | ||||||
|  | :func:`socket.if_indextoname()` on Windows. | ||||||
|  | @ -345,6 +345,8 @@ if_indextoname(index) -- return the corresponding interface name\n\ | ||||||
| 
 | 
 | ||||||
| /* Provides the IsWindows7SP1OrGreater() function */ | /* Provides the IsWindows7SP1OrGreater() function */ | ||||||
| #include <versionhelpers.h> | #include <versionhelpers.h> | ||||||
|  | // For if_nametoindex() and if_indextoname()
 | ||||||
|  | #include <iphlpapi.h> | ||||||
| 
 | 
 | ||||||
| /* remove some flags on older version Windows during run-time.
 | /* remove some flags on older version Windows during run-time.
 | ||||||
|    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */
 |    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */
 | ||||||
|  | @ -6667,28 +6669,56 @@ Set the default timeout in seconds (float) for new socket objects.\n\ | ||||||
| A value of None indicates that new socket objects have no timeout.\n\ | A value of None indicates that new socket objects have no timeout.\n\ | ||||||
| When the socket module is first imported, the default is None."); | When the socket module is first imported, the default is None."); | ||||||
| 
 | 
 | ||||||
| #ifdef HAVE_IF_NAMEINDEX | #if defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS) | ||||||
| /* Python API for getting interface indices and names */ | /* Python API for getting interface indices and names */ | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| socket_if_nameindex(PyObject *self, PyObject *arg) | socket_if_nameindex(PyObject *self, PyObject *arg) | ||||||
| { | { | ||||||
|     PyObject *list; |     PyObject *list = PyList_New(0); | ||||||
|  |     if (list == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  |     PMIB_IF_TABLE2 tbl; | ||||||
|  |     int ret; | ||||||
|  |     if ((ret = GetIfTable2Ex(MibIfTableRaw, &tbl)) != NO_ERROR) { | ||||||
|  |         Py_DECREF(list); | ||||||
|  |         // ret is used instead of GetLastError()
 | ||||||
|  |         return PyErr_SetFromWindowsErr(ret); | ||||||
|  |     } | ||||||
|  |     for (ULONG i = 0; i < tbl->NumEntries; ++i) { | ||||||
|  |         MIB_IF_ROW2 r = tbl->Table[i]; | ||||||
|  |         WCHAR buf[NDIS_IF_MAX_STRING_SIZE + 1]; | ||||||
|  |         if ((ret = ConvertInterfaceLuidToNameW(&r.InterfaceLuid, buf, | ||||||
|  |                                                Py_ARRAY_LENGTH(buf)))) { | ||||||
|  |             Py_DECREF(list); | ||||||
|  |             FreeMibTable(tbl); | ||||||
|  |             // ret is used instead of GetLastError()
 | ||||||
|  |             return PyErr_SetFromWindowsErr(ret); | ||||||
|  |         } | ||||||
|  |         PyObject *tuple = Py_BuildValue("Iu", r.InterfaceIndex, buf); | ||||||
|  |         if (tuple == NULL || PyList_Append(list, tuple) == -1) { | ||||||
|  |             Py_XDECREF(tuple); | ||||||
|  |             Py_DECREF(list); | ||||||
|  |             FreeMibTable(tbl); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |         Py_DECREF(tuple); | ||||||
|  |     } | ||||||
|  |     FreeMibTable(tbl); | ||||||
|  |     return list; | ||||||
|  | #else | ||||||
|     int i; |     int i; | ||||||
|     struct if_nameindex *ni; |     struct if_nameindex *ni; | ||||||
| 
 | 
 | ||||||
|     ni = if_nameindex(); |     ni = if_nameindex(); | ||||||
|     if (ni == NULL) { |     if (ni == NULL) { | ||||||
|  |         Py_DECREF(list); | ||||||
|         PyErr_SetFromErrno(PyExc_OSError); |         PyErr_SetFromErrno(PyExc_OSError); | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     list = PyList_New(0); |  | ||||||
|     if (list == NULL) { |  | ||||||
|         if_freenameindex(ni); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #ifdef _Py_MEMORY_SANITIZER | #ifdef _Py_MEMORY_SANITIZER | ||||||
|     __msan_unpoison(ni, sizeof(ni)); |     __msan_unpoison(ni, sizeof(ni)); | ||||||
|     __msan_unpoison(&ni[0], sizeof(ni[0])); |     __msan_unpoison(&ni[0], sizeof(ni[0])); | ||||||
|  | @ -6720,6 +6750,7 @@ socket_if_nameindex(PyObject *self, PyObject *arg) | ||||||
| 
 | 
 | ||||||
|     if_freenameindex(ni); |     if_freenameindex(ni); | ||||||
|     return list; |     return list; | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PyDoc_STRVAR(if_nameindex_doc, | PyDoc_STRVAR(if_nameindex_doc, | ||||||
|  | @ -6731,8 +6762,11 @@ static PyObject * | ||||||
| socket_if_nametoindex(PyObject *self, PyObject *args) | socket_if_nametoindex(PyObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     PyObject *oname; |     PyObject *oname; | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  |     NET_IFINDEX index; | ||||||
|  | #else | ||||||
|     unsigned long index; |     unsigned long index; | ||||||
| 
 | #endif | ||||||
|     if (!PyArg_ParseTuple(args, "O&:if_nametoindex", |     if (!PyArg_ParseTuple(args, "O&:if_nametoindex", | ||||||
|                           PyUnicode_FSConverter, &oname)) |                           PyUnicode_FSConverter, &oname)) | ||||||
|         return NULL; |         return NULL; | ||||||
|  | @ -6756,7 +6790,11 @@ Returns the interface index corresponding to the interface name if_name."); | ||||||
| static PyObject * | static PyObject * | ||||||
| socket_if_indextoname(PyObject *self, PyObject *arg) | socket_if_indextoname(PyObject *self, PyObject *arg) | ||||||
| { | { | ||||||
|  | #ifdef MS_WINDOWS | ||||||
|  |     NET_IFINDEX index; | ||||||
|  | #else | ||||||
|     unsigned long index; |     unsigned long index; | ||||||
|  | #endif | ||||||
|     char name[IF_NAMESIZE + 1]; |     char name[IF_NAMESIZE + 1]; | ||||||
| 
 | 
 | ||||||
|     index = PyLong_AsUnsignedLong(arg); |     index = PyLong_AsUnsignedLong(arg); | ||||||
|  | @ -6776,7 +6814,7 @@ PyDoc_STRVAR(if_indextoname_doc, | ||||||
| \n\ | \n\ | ||||||
| Returns the interface name corresponding to the interface index if_index."); | Returns the interface name corresponding to the interface index if_index."); | ||||||
| 
 | 
 | ||||||
| #endif  /* HAVE_IF_NAMEINDEX */ | #endif // defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS)
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #ifdef CMSG_LEN | #ifdef CMSG_LEN | ||||||
|  | @ -6898,7 +6936,7 @@ static PyMethodDef socket_methods[] = { | ||||||
|      METH_NOARGS, getdefaulttimeout_doc}, |      METH_NOARGS, getdefaulttimeout_doc}, | ||||||
|     {"setdefaulttimeout",       socket_setdefaulttimeout, |     {"setdefaulttimeout",       socket_setdefaulttimeout, | ||||||
|      METH_O, setdefaulttimeout_doc}, |      METH_O, setdefaulttimeout_doc}, | ||||||
| #ifdef HAVE_IF_NAMEINDEX | #if defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS) | ||||||
|     {"if_nameindex", socket_if_nameindex, |     {"if_nameindex", socket_if_nameindex, | ||||||
|      METH_NOARGS, if_nameindex_doc}, |      METH_NOARGS, if_nameindex_doc}, | ||||||
|     {"if_nametoindex", socket_if_nametoindex, |     {"if_nametoindex", socket_if_nametoindex, | ||||||
|  |  | ||||||
|  | @ -93,7 +93,7 @@ | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|   <ItemDefinitionGroup> |   <ItemDefinitionGroup> | ||||||
|     <Link> |     <Link> | ||||||
|       <AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> |       <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> | ||||||
|     </Link> |     </Link> | ||||||
|   </ItemDefinitionGroup> |   </ItemDefinitionGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zackery Spytz
						Zackery Spytz