diff --git a/scapy/automaton.py b/scapy/automaton.py index a0ad54232be..a702a0368a2 100644 --- a/scapy/automaton.py +++ b/scapy/automaton.py @@ -144,7 +144,13 @@ def select_objects(inputs, remain): False, remainms ) - if res != 0xFFFFFFFF and res != 0x00000102: # Failed or Timeout + # ctypes' default signed c_int restype returns WAIT_FAILED as -1. + if res == -1 or res == 0xFFFFFFFF: + error = ctypes.WinError() + for evt in created: + ctypes.windll.ws2_32.WSACloseEvent(evt) + raise error + if res != 0x00000102: # Timeout results.add(events_to_inputs[res]) if len(events) > 1: # Now poll the others, if any @@ -153,6 +159,11 @@ def select_objects(inputs, remain): ctypes.c_void_p(evt), 0 # poll: don't wait ) + if res == -1 or res == 0xFFFFFFFF: + error = ctypes.WinError() + for created_evt in created: + ctypes.windll.ws2_32.WSACloseEvent(created_evt) + raise error if res == 0: results.add(events_to_inputs[i]) # Cleanup created events, if any diff --git a/test/windows.uts b/test/windows.uts index 4d8a232e65b..04af091c5e2 100644 --- a/test/windows.uts +++ b/test/windows.uts @@ -5,6 +5,7 @@ + Configuration = Imports +~ automaton from unittest import mock @@ -49,6 +50,51 @@ if WINDOWS: readable.close() b.close() += Automaton - WaitFor* errors are raised +~ automaton + +import ctypes as _ctypes +import scapy.automaton as _automaton + +for failure, input_count, use_native_socket in [ + (-1, 1, True), + (0xFFFFFFFF, 2, False), + (0, 2, True)]: + inputs = [mock.Mock() for _ in range(input_count)] + for index, obj in enumerate(inputs): + obj.fileno.return_value = index + 10 + obj.__selectable_force_select__ = False + if use_native_socket: + inputs[0].__selectable_force_select__ = True + kernel32 = mock.Mock() + if input_count == 1: + kernel32.WaitForSingleObject.return_value = failure + elif use_native_socket: + kernel32.WaitForMultipleObjects.return_value = 0 + kernel32.WaitForSingleObject.return_value = -1 + else: + kernel32.WaitForMultipleObjects.return_value = failure + ws2_32 = mock.Mock() + ws2_32.WSACreateEvent.return_value = 100 + ws2_32.WSAEventSelect.return_value = 0 + windll = mock.Mock(kernel32=kernel32, ws2_32=ws2_32) + with mock.patch.object(_automaton, "WINDOWS", True): + with mock.patch.object(_automaton, "ctypes", _ctypes, create=True): + with mock.patch.object( + _ctypes, "windll", windll, create=True): + with mock.patch.object( + _ctypes, "WinError", + return_value=OSError("wait failed"), create=True + ) as win_error: + try: + select_objects(inputs, 0) + except OSError: + pass + else: + assert False, "WAIT_FAILED must raise an OSError" + win_error.assert_called_once_with() + if use_native_socket: + assert ws2_32.WSACloseEvent.call_count == 1 ############ ############ + Windows arch unit tests