Skip to content

Commit

Permalink
api: respect timeouts on Windows named pipes (docker/docker-py#3112)
Browse files Browse the repository at this point in the history
Cherry-picked from docker/docker-py@9cadad0

Co-authored-by: Imogen <59090860+ImogenBits@users.noreply.github.com>
  • Loading branch information
felixfontein and ImogenBits committed May 10, 2023
1 parent 5a4b4d0 commit e4eec2d
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 13 deletions.
1 change: 1 addition & 0 deletions changelogs/fragments/docker-py.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
bugfixes:
- "vendored Docker SDK for Python code - fix for errors on pipe close in Windows."
- "vendored Docker SDK for Python code - use ``poll()`` instead of ``select()`` except on Windows."
- "vendored Docker SDK for Python code - respect timeouts on Windows named pipes."
49 changes: 36 additions & 13 deletions plugins/module_utils/_api/transport/npipesocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
try:
import win32file
import win32pipe
import pywintypes
import win32event
import win32api
except ImportError:
PYWIN32_IMPORT_ERROR = traceback.format_exc()

Expand Down Expand Up @@ -74,7 +77,9 @@ def connect(self, address, retry_count=0):
0,
None,
win32file.OPEN_EXISTING,
cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT,
(cSECURITY_ANONYMOUS
| cSECURITY_SQOS_PRESENT
| win32file.FILE_FLAG_OVERLAPPED),
0
)
except win32pipe.error as e:
Expand Down Expand Up @@ -154,11 +159,22 @@ def recv_into(self, buf, nbytes=0):
if not isinstance(buf, memoryview):
readbuf = memoryview(buf)

err, data = win32file.ReadFile(
self._handle,
readbuf[:nbytes] if nbytes else readbuf
)
return len(data)
event = win32event.CreateEvent(None, True, True, None)
try:
overlapped = pywintypes.OVERLAPPED()
overlapped.hEvent = event
err, data = win32file.ReadFile(
self._handle,
readbuf[:nbytes] if nbytes else readbuf,
overlapped
)
wait_result = win32event.WaitForSingleObject(event, self._timeout)
if wait_result == win32event.WAIT_TIMEOUT:
win32file.CancelIo(self._handle)
raise TimeoutError
return win32file.GetOverlappedResult(self._handle, overlapped, 0)
finally:
win32api.CloseHandle(event)

def _recv_into_py2(self, buf, nbytes):
err, data = win32file.ReadFile(self._handle, nbytes or len(buf))
Expand All @@ -168,8 +184,18 @@ def _recv_into_py2(self, buf, nbytes):

@check_closed
def send(self, string, flags=0):
err, nbytes = win32file.WriteFile(self._handle, string)
return nbytes
event = win32event.CreateEvent(None, True, True, None)
try:
overlapped = pywintypes.OVERLAPPED()
overlapped.hEvent = event
win32file.WriteFile(self._handle, string, overlapped)
wait_result = win32event.WaitForSingleObject(event, self._timeout)
if wait_result == win32event.WAIT_TIMEOUT:
win32file.CancelIo(self._handle)
raise TimeoutError
return win32file.GetOverlappedResult(self._handle, overlapped, 0)
finally:
win32api.CloseHandle(event)

@check_closed
def sendall(self, string, flags=0):
Expand All @@ -188,15 +214,12 @@ def setblocking(self, flag):
def settimeout(self, value):
if value is None:
# Blocking mode
self._timeout = win32pipe.NMPWAIT_WAIT_FOREVER
self._timeout = win32event.INFINITE
elif not isinstance(value, (float, int)) or value < 0:
raise ValueError('Timeout value out of range')
elif value == 0:
# Non-blocking mode
self._timeout = win32pipe.NMPWAIT_NO_WAIT
else:
# Timeout mode - Value converted to milliseconds
self._timeout = value * 1000
self._timeout = int(value * 1000)

def gettimeout(self):
return self._timeout
Expand Down

0 comments on commit e4eec2d

Please sign in to comment.