Skip to content

[3.7] bpo-32394: Remove some TCP options on old version Windows. (GH-5523) #5910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/library/socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,16 @@ 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.

.. versionchanged:: 3.7
``TCP_NOTSENT_LOWAT`` was added.

On Windows, ``TCP_KEEPIDLE``, ``TCP_KEEPINTVL`` appear if run-time Windows
supports.

.. data:: AF_CAN
PF_CAN
SOL_CAN_*
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -5945,6 +5945,27 @@ 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',
# available starting with Windows 10 1709
'TCP_KEEPIDLE',
'TCP_KEEPINTVL'
}

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]

self.assertEqual([], unknown,
"New TCP flags were discovered. See bpo-32394 for more information")

def test_main():
tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest,
Expand Down Expand Up @@ -6005,6 +6026,7 @@ def test_main():
SendfileUsingSendTest,
SendfileUsingSendfileTest,
])
tests.append(TestMSWindowsTCPFlags)

thread_info = support.threading_setup()
support.run_unittest(*tests)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
socket: Remove TCP_FASTOPEN,TCP_KEEPCNT,TCP_KEEPIDLE,TCP_KEEPINTVL flags on
older version Windows during run-time.
70 changes: 70 additions & 0 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,70 @@ if_indextoname(index) -- return the corresponding interface name\n\
/* Provides the IsWindows7SP1OrGreater() function */
#include <VersionHelpers.h>

/* remove some flags on older version Windows during run-time.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596.aspx */
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 win_runtime_flags[] = {
/* available starting with Windows 10 1709 */
{16299, "TCP_KEEPIDLE"},
{16299, "TCP_KEEPINTVL"},
/* available starting with Windows 10 1703 */
{15063, "TCP_KEEPCNT"},
/* available starting with Windows 10 1607 */
{14393, "TCP_FASTOPEN"}
};

static void
remove_unusable_flags(PyObject *m)
{
PyObject *dict;
OSVERSIONINFOEX info;
DWORDLONG dwlConditionMask;

dict = PyModule_GetDict(m);
if (dict == NULL) {
return;
}

/* set to Windows 10, except BuildNumber. */
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
info.dwMajorVersion = 10;
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);

for (int i=0; i<sizeof(win_runtime_flags)/sizeof(FlagRuntimeInfo); i++) {
info.dwBuildNumber = win_runtime_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,
win_runtime_flags[i].flag_name) != NULL) {
PyDict_DelItemString(
dict,
win_runtime_flags[i].flag_name);
}
}
}
}

#endif

#include <stddef.h>
Expand Down Expand Up @@ -7890,5 +7954,11 @@ PyInit__socket(void)
#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK)
netdb_lock = PyThread_allocate_lock();
#endif

#ifdef MS_WINDOWS
/* remove some flags on older version Windows during run-time */
remove_unusable_flags(m);
#endif

return m;
}