Skip to content

Commit 9cadad0

Browse files
authored
api: respect timeouts on Windows named pipes (#3112)
Signed-off-by: Imogen <59090860+ImogenBits@users.noreply.github.com>
1 parent 443a353 commit 9cadad0

File tree

1 file changed

+36
-19
lines changed

1 file changed

+36
-19
lines changed

docker/transport/npipesocket.py

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
import win32file
66
import win32pipe
7+
import pywintypes
8+
import win32event
9+
import win32api
710

811
cERROR_PIPE_BUSY = 0xe7
912
cSECURITY_SQOS_PRESENT = 0x100000
@@ -54,7 +57,9 @@ def connect(self, address, retry_count=0):
5457
0,
5558
None,
5659
win32file.OPEN_EXISTING,
57-
cSECURITY_ANONYMOUS | cSECURITY_SQOS_PRESENT,
60+
(cSECURITY_ANONYMOUS
61+
| cSECURITY_SQOS_PRESENT
62+
| win32file.FILE_FLAG_OVERLAPPED),
5863
0
5964
)
6065
except win32pipe.error as e:
@@ -131,22 +136,37 @@ def recv_into(self, buf, nbytes=0):
131136
if not isinstance(buf, memoryview):
132137
readbuf = memoryview(buf)
133138

134-
err, data = win32file.ReadFile(
135-
self._handle,
136-
readbuf[:nbytes] if nbytes else readbuf
137-
)
138-
return len(data)
139-
140-
def _recv_into_py2(self, buf, nbytes):
141-
err, data = win32file.ReadFile(self._handle, nbytes or len(buf))
142-
n = len(data)
143-
buf[:n] = data
144-
return n
139+
event = win32event.CreateEvent(None, True, True, None)
140+
try:
141+
overlapped = pywintypes.OVERLAPPED()
142+
overlapped.hEvent = event
143+
err, data = win32file.ReadFile(
144+
self._handle,
145+
readbuf[:nbytes] if nbytes else readbuf,
146+
overlapped
147+
)
148+
wait_result = win32event.WaitForSingleObject(event, self._timeout)
149+
if wait_result == win32event.WAIT_TIMEOUT:
150+
win32file.CancelIo(self._handle)
151+
raise TimeoutError
152+
return win32file.GetOverlappedResult(self._handle, overlapped, 0)
153+
finally:
154+
win32api.CloseHandle(event)
145155

146156
@check_closed
147157
def send(self, string, flags=0):
148-
err, nbytes = win32file.WriteFile(self._handle, string)
149-
return nbytes
158+
event = win32event.CreateEvent(None, True, True, None)
159+
try:
160+
overlapped = pywintypes.OVERLAPPED()
161+
overlapped.hEvent = event
162+
win32file.WriteFile(self._handle, string, overlapped)
163+
wait_result = win32event.WaitForSingleObject(event, self._timeout)
164+
if wait_result == win32event.WAIT_TIMEOUT:
165+
win32file.CancelIo(self._handle)
166+
raise TimeoutError
167+
return win32file.GetOverlappedResult(self._handle, overlapped, 0)
168+
finally:
169+
win32api.CloseHandle(event)
150170

151171
@check_closed
152172
def sendall(self, string, flags=0):
@@ -165,15 +185,12 @@ def setblocking(self, flag):
165185
def settimeout(self, value):
166186
if value is None:
167187
# Blocking mode
168-
self._timeout = win32pipe.NMPWAIT_WAIT_FOREVER
188+
self._timeout = win32event.INFINITE
169189
elif not isinstance(value, (float, int)) or value < 0:
170190
raise ValueError('Timeout value out of range')
171-
elif value == 0:
172-
# Non-blocking mode
173-
self._timeout = win32pipe.NMPWAIT_NO_WAIT
174191
else:
175192
# Timeout mode - Value converted to milliseconds
176-
self._timeout = value * 1000
193+
self._timeout = int(value * 1000)
177194

178195
def gettimeout(self):
179196
return self._timeout

0 commit comments

Comments
 (0)