bpo-32394: Remove some TCP options on old version Windows. (GH-5523) · python/cpython@53d3f8a
@@ -305,6 +305,70 @@ if_indextoname(index) -- return the corresponding interface name\n\
305305/* Provides the IsWindows7SP1OrGreater() function */
306306#include <VersionHelpers.h>
307307308+/* remove some flags on older version Windows during run-time.
309+ https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */
310+typedef struct {
311+DWORD build_number; /* available starting with this Win10 BuildNumber */
312+const char flag_name[20];
313+} FlagRuntimeInfo;
314+315+/* IMPORTANT: make sure the list ordered by descending build_number */
316+static FlagRuntimeInfo win_runtime_flags[] = {
317+/* available starting with Windows 10 1709 */
318+ {16299, "TCP_KEEPIDLE"},
319+ {16299, "TCP_KEEPINTVL"},
320+/* available starting with Windows 10 1703 */
321+ {15063, "TCP_KEEPCNT"},
322+/* available starting with Windows 10 1607 */
323+ {14393, "TCP_FASTOPEN"}
324+};
325+326+static void
327+remove_unusable_flags(PyObject *m)
328+{
329+PyObject *dict;
330+OSVERSIONINFOEX info;
331+DWORDLONG dwlConditionMask;
332+333+dict = PyModule_GetDict(m);
334+if (dict == NULL) {
335+return;
336+ }
337+338+/* set to Windows 10, except BuildNumber. */
339+memset(&info, 0, sizeof(info));
340+info.dwOSVersionInfoSize = sizeof(info);
341+info.dwMajorVersion = 10;
342+info.dwMinorVersion = 0;
343+344+/* set Condition Mask */
345+dwlConditionMask = 0;
346+VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
347+VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
348+VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
349+350+for (int i=0; i<sizeof(win_runtime_flags)/sizeof(FlagRuntimeInfo); i++) {
351+info.dwBuildNumber = win_runtime_flags[i].build_number;
352+/* greater than or equal to the specified version?
353+ Compatibility Mode will not cheat VerifyVersionInfo(...) */
354+if (VerifyVersionInfo(
355+&info,
356+VER_MAJORVERSION|VER_MINORVERSION|VER_BUILDNUMBER,
357+dwlConditionMask)) {
358+break;
359+ }
360+else {
361+if (PyDict_GetItemString(
362+dict,
363+win_runtime_flags[i].flag_name) != NULL) {
364+PyDict_DelItemString(
365+dict,
366+win_runtime_flags[i].flag_name);
367+ }
368+ }
369+ }
370+}
371+308372#endif
309373310374#include <stddef.h>
@@ -7890,5 +7954,11 @@ PyInit__socket(void)
78907954#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
78917955netdb_lock = PyThread_allocate_lock();
78927956#endif
7957+7958+#ifdef MS_WINDOWS
7959+/* remove some flags on older version Windows during run-time */
7960+remove_unusable_flags(m);
7961+#endif
7962+78937963return m;
78947964}