From 5111b60df13bc3003e0fa1c39443acf117bbbfea Mon Sep 17 00:00:00 2001 From: animalize Date: Thu, 8 Feb 2018 08:27:50 +0800 Subject: [PATCH 1/5] fix --- Doc/library/socket.rst | 4 +++ Lib/socket.py | 25 ++++++++++++++++++- .../2018-02-08-08-18-26.bpo-32394.6E_7X7.rst | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2018-02-08-08-18-26.bpo-32394.6E_7X7.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 678e32ce57f1d3..512c38e785d22f 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -303,6 +303,10 @@ Constants ``SO_DOMAIN``, ``SO_PROTOCOL``, ``SO_PEERSEC``, ``SO_PASSSEC``, ``TCP_USER_TIMEOUT``, ``TCP_CONGESTION`` were added. + .. versionchanged:: 3.6.5 + On Windows, ``TCP_FASTOPEN``, ``TCP_KEEPCNT`` appear if run-time Windows + supports. + .. data:: AF_CAN PF_CAN SOL_CAN_* diff --git a/Lib/socket.py b/Lib/socket.py index 1ada24d3326422..3687d49312f3f2 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -47,11 +47,34 @@ """ import _socket -from _socket import * import os, sys, io, selectors from enum import IntEnum, IntFlag +# Remove some options on old version Windows. +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx +if hasattr(sys, 'getwindowsversion'): + # (new_option, win10_buildnumber) + # make sure the list ordered by descending win10_buildnumber + _new_flags = [ + ('TCP_KEEPCNT', 15063), # Windows 10 1703 + ('TCP_FASTOPEN', 14393) # Windows 10 1607 + ] + _WIN_MAJOR, _WIN_MINOR, _WIN_BUILD, *_ = sys.getwindowsversion() + if _WIN_MAJOR == 10 and _WIN_MINOR == 0: + for _flag, _build in _new_flags: + if _WIN_BUILD < _build: + if hasattr(_socket, _flag): + delattr(_socket, _flag) + else: + break + elif _WIN_MAJOR < 10: + for _flag, _ in _new_flags: + if hasattr(_socket, _flag): + delattr(_socket, _flag) + +from _socket import * + try: import errno except ImportError: diff --git a/Misc/NEWS.d/next/Library/2018-02-08-08-18-26.bpo-32394.6E_7X7.rst b/Misc/NEWS.d/next/Library/2018-02-08-08-18-26.bpo-32394.6E_7X7.rst new file mode 100644 index 00000000000000..f7fb42d8e7a3e5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-02-08-08-18-26.bpo-32394.6E_7X7.rst @@ -0,0 +1,2 @@ +socket: Remove TCP_FASTOPEN, TCP_KEEPCNT flags on older version Windows +during run-time. From 961cb795157e672212ca823f07f792bdcd8760d5 Mon Sep 17 00:00:00 2001 From: animalize Date: Sun, 11 Feb 2018 07:48:53 +0800 Subject: [PATCH 2/5] user VerifyVersionInfo(...) --- Lib/socket.py | 25 +--------------- Lib/test/test_socket.py | 27 +++++++++++++++++ Modules/socketmodule.c | 64 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 24 deletions(-) diff --git a/Lib/socket.py b/Lib/socket.py index 3687d49312f3f2..1ada24d3326422 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -47,34 +47,11 @@ """ import _socket +from _socket import * import os, sys, io, selectors from enum import IntEnum, IntFlag -# Remove some options on old version Windows. -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx -if hasattr(sys, 'getwindowsversion'): - # (new_option, win10_buildnumber) - # make sure the list ordered by descending win10_buildnumber - _new_flags = [ - ('TCP_KEEPCNT', 15063), # Windows 10 1703 - ('TCP_FASTOPEN', 14393) # Windows 10 1607 - ] - _WIN_MAJOR, _WIN_MINOR, _WIN_BUILD, *_ = sys.getwindowsversion() - if _WIN_MAJOR == 10 and _WIN_MINOR == 0: - for _flag, _build in _new_flags: - if _WIN_BUILD < _build: - if hasattr(_socket, _flag): - delattr(_socket, _flag) - else: - break - elif _WIN_MAJOR < 10: - for _flag, _ in _new_flags: - if hasattr(_socket, _flag): - delattr(_socket, _flag) - -from _socket import * - try: import errno except ImportError: diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 00237626d6c473..a0f85c3c0c4c00 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5583,6 +5583,32 @@ def test_sendmsg_afalg_args(self): with self.assertRaises(TypeError): sock.sendmsg_afalg(op=socket.ALG_OP_ENCRYPT, assoclen=-1) +@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") +class TestMSWindowsTCPFlags(unittest.TestCase): + knownTCPFlags = { + # avaliable since long time ago + 'TCP_MAXSEG', + 'TCP_NODELAY', + # available starting with Windows 10 1607 + 'TCP_FASTOPEN', + # available starting with Windows 10 1703 + 'TCP_KEEPCNT', + } + + def testNewTCPFlags(self): + provided = [s for s in dir(socket) if s.startswith('TCP')] + unknown = [s for s in provided if s not in self.knownTCPFlags] + + if unknown: + msg = ("\nFound new TCP flags %s, probably you are building" + " CPython with a newer Windows SDK than official build's.\n" + "If you insist on building CPython with the current " + "Windows SDK, maybe you need to remove them on older " + "version MS-Windows during run-time via hard code patch, " + "see issue32394.\n" + "Full avaliable TCP flags on this system: %s" + ) % (unknown, provided) + raise Exception(msg) def test_main(): tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, @@ -5639,6 +5665,7 @@ def test_main(): SendfileUsingSendTest, SendfileUsingSendfileTest, ]) + tests.append(TestMSWindowsTCPFlags) thread_info = support.threading_setup() support.run_unittest(*tests) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 968dad07cd84e4..4a618cd061c6b1 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -317,6 +317,65 @@ if_indextoname(index) -- return the corresponding interface name\n\ #include #endif +/* This block removes some flags on older version Windows during run-time. + https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */ +#if 1 +typedef struct{ + DWORD build_number; /* available starting with this Win10 BuildNumber */ + const char flag_name[20]; +} FlagRuntimeInfo; + +/* IMPORTANT: make sure the list ordered by descending build_number */ +static FlagRuntimeInfo flags[] = { + /* available starting with Windows 10 1703 */ + {15063, "TCP_KEEPCNT"}, + /* available starting with Windows 10 1607 */ + {14393, "TCP_FASTOPEN"} +}; + +static PyObject * +remove_unusable_flags(PyObject *m) +{ + PyObject *dict; + OSVERSIONINFOEX info; + DWORDLONG dwlConditionMask = 0; + + dict = PyModule_GetDict(m); + if (dict == NULL) { + return m; + } + + /* set to Windows 10, except BuildNumber. */ + memset(&info, 0, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + info.dwMajorVersion = 10; + info.dwMinorVersion = 0; + + /* set Condition Mask */ + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); + + for (int i = 0; i < sizeof(flags)/sizeof(FlagRuntimeInfo); i++) { + info.dwBuildNumber = flags[i].build_number; + /* greater than or equal to the specified version? + Compatibility Mode will not cheat VerifyVersionInfo(...) */ + if (VerifyVersionInfo( + &info, + VER_MAJORVERSION|VER_MINORVERSION|VER_BUILDNUMBER, + dwlConditionMask)) { + break; + } + else { + if (PyDict_GetItemString(dict, flags[i].flag_name) != NULL) { + PyDict_DelItemString(dict, flags[i].flag_name); + } + } + } + return m; +} +#endif + #endif #include @@ -7694,7 +7753,12 @@ PyInit__socket(void) #if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) netdb_lock = PyThread_allocate_lock(); #endif + +#ifdef MS_WINDOWS + return remove_unusable_flags(m); +#else return m; +#endif } From 4191db087ffce77ddf68c5c3fb0c9a715d350c10 Mon Sep 17 00:00:00 2001 From: animalize Date: Tue, 13 Feb 2018 10:15:27 +0800 Subject: [PATCH 3/5] minor --- Modules/socketmodule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 4a618cd061c6b1..79f4b1a4838ffa 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -320,7 +320,7 @@ if_indextoname(index) -- return the corresponding interface name\n\ /* This block removes some flags on older version Windows during run-time. https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */ #if 1 -typedef struct{ +typedef struct { DWORD build_number; /* available starting with this Win10 BuildNumber */ const char flag_name[20]; } FlagRuntimeInfo; @@ -338,7 +338,7 @@ remove_unusable_flags(PyObject *m) { PyObject *dict; OSVERSIONINFOEX info; - DWORDLONG dwlConditionMask = 0; + DWORDLONG dwlConditionMask; dict = PyModule_GetDict(m); if (dict == NULL) { @@ -352,6 +352,7 @@ remove_unusable_flags(PyObject *m) info.dwMinorVersion = 0; /* set Condition Mask */ + dwlConditionMask = 0; VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); From afd5d526ed447ba2f750d46c71c5900f69397493 Mon Sep 17 00:00:00 2001 From: animalize Date: Tue, 20 Feb 2018 09:30:21 +0800 Subject: [PATCH 4/5] For Changes requested --- Lib/test/test_socket.py | 14 +++----------- Modules/socketmodule.c | 25 ++++++++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index a0f85c3c0c4c00..faa4868587cdc2 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5595,20 +5595,12 @@ class TestMSWindowsTCPFlags(unittest.TestCase): 'TCP_KEEPCNT', } - def testNewTCPFlags(self): + def test_new_tcp_flags(self): provided = [s for s in dir(socket) if s.startswith('TCP')] unknown = [s for s in provided if s not in self.knownTCPFlags] - if unknown: - msg = ("\nFound new TCP flags %s, probably you are building" - " CPython with a newer Windows SDK than official build's.\n" - "If you insist on building CPython with the current " - "Windows SDK, maybe you need to remove them on older " - "version MS-Windows during run-time via hard code patch, " - "see issue32394.\n" - "Full avaliable TCP flags on this system: %s" - ) % (unknown, provided) - raise Exception(msg) + self.assertEqual([], unknown, + "New TCP flags were discovered. See bpo-32394 for more information") def test_main(): tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 79f4b1a4838ffa..1a53466a21cdbf 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -317,16 +317,15 @@ if_indextoname(index) -- return the corresponding interface name\n\ #include #endif -/* This block removes 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 */ -#if 1 typedef struct { DWORD build_number; /* available starting with this Win10 BuildNumber */ const char flag_name[20]; } FlagRuntimeInfo; /* IMPORTANT: make sure the list ordered by descending build_number */ -static FlagRuntimeInfo flags[] = { +static FlagRuntimeInfo win_runtime_flags[] = { /* available starting with Windows 10 1703 */ {15063, "TCP_KEEPCNT"}, /* available starting with Windows 10 1607 */ @@ -357,8 +356,8 @@ remove_unusable_flags(PyObject *m) VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); - for (int i = 0; i < sizeof(flags)/sizeof(FlagRuntimeInfo); i++) { - info.dwBuildNumber = flags[i].build_number; + for (int i=0; i Date: Tue, 20 Feb 2018 12:18:26 +0800 Subject: [PATCH 5/5] remove_unusable_flags no return value --- Modules/socketmodule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 1a53466a21cdbf..5a07b296952d45 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -332,7 +332,7 @@ static FlagRuntimeInfo win_runtime_flags[] = { {14393, "TCP_FASTOPEN"} }; -static PyObject * +static void remove_unusable_flags(PyObject *m) { PyObject *dict; @@ -341,7 +341,7 @@ remove_unusable_flags(PyObject *m) dict = PyModule_GetDict(m); if (dict == NULL) { - return m; + return; } /* set to Windows 10, except BuildNumber. */ @@ -376,7 +376,6 @@ remove_unusable_flags(PyObject *m) } } } - return m; } #endif