blob: 4f0ba85d7983e00fafc4b2a6de3b1f2cd51bac68 [file] [log] [blame]
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001/*
2 * Support for overlapped IO
3 *
4 * Some code borrowed from Modules/_winapi.c of CPython
5 */
6
7/* XXX check overflow and DWORD <-> Py_ssize_t conversions
8 Check itemsize */
9
10#include "Python.h"
Victor Stinner4a21e572020-04-15 02:35:41 +020011#include "structmember.h" // PyMemberDef
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070012
13#define WINDOWS_LEAN_AND_MEAN
14#include <winsock2.h>
15#include <ws2tcpip.h>
16#include <mswsock.h>
17
18#if defined(MS_WIN32) && !defined(MS_WIN64)
19# define F_POINTER "k"
20# define T_POINTER T_ULONG
21#else
22# define F_POINTER "K"
23# define T_POINTER T_ULONGLONG
24#endif
25
Victor Stinnerccdbe802016-04-01 21:37:41 +020026/* Compatibility with Python 3.3 */
27#if PY_VERSION_HEX < 0x03040000
28# define PyMem_RawMalloc PyMem_Malloc
29# define PyMem_RawFree PyMem_Free
30#endif
31
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070032#define F_HANDLE F_POINTER
33#define F_ULONG_PTR F_POINTER
34#define F_DWORD "k"
35#define F_BOOL "i"
36#define F_UINT "I"
37
38#define T_HANDLE T_POINTER
39
Zackery Spytz9650fe02020-07-10 11:43:37 -060040/*[python input]
41class OVERLAPPED_converter(CConverter):
42 type = 'OVERLAPPED *'
43 format_unit = '"F_POINTER"'
44
45class HANDLE_converter(CConverter):
46 type = 'HANDLE'
47 format_unit = '"F_HANDLE"'
48
49class ULONG_PTR_converter(CConverter):
50 type = 'ULONG_PTR'
51 format_unit = '"F_ULONG_PTR"'
52
53class DWORD_converter(CConverter):
54 type = 'DWORD'
55 format_unit = 'k'
56
57class BOOL_converter(CConverter):
58 type = 'BOOL'
59 format_unit = 'i'
60[python start generated code]*/
61/*[python end generated code: output=da39a3ee5e6b4b0d input=83bb8c2c2514f2a8]*/
62
63/*[clinic input]
64module _overlapped
65class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType"
66[clinic start generated code]*/
67/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92e5a799db35b96c]*/
68
69
Antoine Pitrou525f40d2017-10-19 21:46:40 +020070enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
71 TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030072 TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
73 TYPE_WRITE_TO};
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070074
75typedef struct {
76 PyObject_HEAD
77 OVERLAPPED overlapped;
78 /* For convenience, we store the file handle too */
79 HANDLE handle;
80 /* Error returned by last method call */
81 DWORD error;
82 /* Type of operation */
83 DWORD type;
84 union {
Antoine Pitrou525f40d2017-10-19 21:46:40 +020085 /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
86 PyObject *allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030087 /* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */
Antoine Pitrou525f40d2017-10-19 21:46:40 +020088 Py_buffer user_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030089
90 /* Data used for reading from a connectionless socket:
91 TYPE_READ_FROM */
92 struct {
93 // A (buffer, (host, port)) tuple
94 PyObject *result;
95 // The actual read buffer
96 PyObject *allocated_buffer;
97 struct sockaddr_in6 address;
98 int address_length;
99 } read_from;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700100 };
101} OverlappedObject;
102
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700103/*
104 * Map Windows error codes to subclasses of OSError
105 */
106
107static PyObject *
108SetFromWindowsErr(DWORD err)
109{
110 PyObject *exception_type;
111
112 if (err == 0)
113 err = GetLastError();
114 switch (err) {
115 case ERROR_CONNECTION_REFUSED:
116 exception_type = PyExc_ConnectionRefusedError;
117 break;
118 case ERROR_CONNECTION_ABORTED:
119 exception_type = PyExc_ConnectionAbortedError;
120 break;
121 default:
122 exception_type = PyExc_OSError;
123 }
124 return PyErr_SetExcFromWindowsErr(exception_type, err);
125}
126
127/*
128 * Some functions should be loaded at runtime
129 */
130
131static LPFN_ACCEPTEX Py_AcceptEx = NULL;
132static LPFN_CONNECTEX Py_ConnectEx = NULL;
133static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300134static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700135static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
136
137#define GET_WSA_POINTER(s, x) \
138 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
139 &Guid##x, sizeof(Guid##x), &Py_##x, \
140 sizeof(Py_##x), &dwBytes, NULL, NULL))
141
142static int
143initialize_function_pointers(void)
144{
145 GUID GuidAcceptEx = WSAID_ACCEPTEX;
146 GUID GuidConnectEx = WSAID_CONNECTEX;
147 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300148 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700149 HINSTANCE hKernel32;
150 SOCKET s;
151 DWORD dwBytes;
152
153 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
154 if (s == INVALID_SOCKET) {
155 SetFromWindowsErr(WSAGetLastError());
156 return -1;
157 }
158
159 if (!GET_WSA_POINTER(s, AcceptEx) ||
160 !GET_WSA_POINTER(s, ConnectEx) ||
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300161 !GET_WSA_POINTER(s, DisconnectEx) ||
162 !GET_WSA_POINTER(s, TransmitFile))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700163 {
164 closesocket(s);
165 SetFromWindowsErr(WSAGetLastError());
166 return -1;
167 }
168
169 closesocket(s);
170
171 /* On WinXP we will have Py_CancelIoEx == NULL */
Tony Roberts4860f012019-02-02 18:16:42 +0100172 Py_BEGIN_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700173 hKernel32 = GetModuleHandle("KERNEL32");
174 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Tony Roberts4860f012019-02-02 18:16:42 +0100175 Py_END_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700176 return 0;
177}
178
179/*
180 * Completion port stuff
181 */
182
Zackery Spytz9650fe02020-07-10 11:43:37 -0600183/*[clinic input]
184_overlapped.CreateIoCompletionPort
185
186 handle as FileHandle: HANDLE
187 port as ExistingCompletionPort: HANDLE
188 key as CompletionKey: ULONG_PTR
189 concurrency as NumberOfConcurrentThreads: DWORD
190 /
191
192Create a completion port or register a handle with a port.
193[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700194
195static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600196_overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle,
197 HANDLE ExistingCompletionPort,
198 ULONG_PTR CompletionKey,
199 DWORD NumberOfConcurrentThreads)
200/*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700201{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700202 HANDLE ret;
203
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700204 Py_BEGIN_ALLOW_THREADS
205 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
206 CompletionKey, NumberOfConcurrentThreads);
207 Py_END_ALLOW_THREADS
208
209 if (ret == NULL)
210 return SetFromWindowsErr(0);
211 return Py_BuildValue(F_HANDLE, ret);
212}
213
Zackery Spytz9650fe02020-07-10 11:43:37 -0600214/*[clinic input]
215_overlapped.GetQueuedCompletionStatus
216
217 port as CompletionPort: HANDLE
218 msecs as Milliseconds: DWORD
219 /
220
221Get a message from completion port.
222
223Wait for up to msecs milliseconds.
224[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700225
226static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600227_overlapped_GetQueuedCompletionStatus_impl(PyObject *module,
228 HANDLE CompletionPort,
229 DWORD Milliseconds)
230/*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700231{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700232 DWORD NumberOfBytes = 0;
233 ULONG_PTR CompletionKey = 0;
234 OVERLAPPED *Overlapped = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700235 DWORD err;
236 BOOL ret;
237
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700238 Py_BEGIN_ALLOW_THREADS
239 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
240 &CompletionKey, &Overlapped, Milliseconds);
241 Py_END_ALLOW_THREADS
242
243 err = ret ? ERROR_SUCCESS : GetLastError();
244 if (Overlapped == NULL) {
245 if (err == WAIT_TIMEOUT)
246 Py_RETURN_NONE;
247 else
248 return SetFromWindowsErr(err);
249 }
250 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
251 err, NumberOfBytes, CompletionKey, Overlapped);
252}
253
Zackery Spytz9650fe02020-07-10 11:43:37 -0600254/*[clinic input]
255_overlapped.PostQueuedCompletionStatus
256
257 port as CompletionPort: HANDLE
258 bytes as NumberOfBytes: DWORD
259 key as CompletionKey: ULONG_PTR
260 address as Overlapped: OVERLAPPED
261 /
262
263Post a message to completion port.
264[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700265
266static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600267_overlapped_PostQueuedCompletionStatus_impl(PyObject *module,
268 HANDLE CompletionPort,
269 DWORD NumberOfBytes,
270 ULONG_PTR CompletionKey,
271 OVERLAPPED *Overlapped)
272/*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700273{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700274 BOOL ret;
275
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700276 Py_BEGIN_ALLOW_THREADS
277 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
278 CompletionKey, Overlapped);
279 Py_END_ALLOW_THREADS
280
281 if (!ret)
282 return SetFromWindowsErr(0);
283 Py_RETURN_NONE;
284}
285
286/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700287 * Wait for a handle
288 */
289
290struct PostCallbackData {
291 HANDLE CompletionPort;
292 LPOVERLAPPED Overlapped;
293};
294
295static VOID CALLBACK
296PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
297{
298 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
299
300 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
301 0, p->Overlapped);
302 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100303 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700304}
305
Zackery Spytz9650fe02020-07-10 11:43:37 -0600306/*[clinic input]
307_overlapped.RegisterWaitWithQueue
308
309 Object: HANDLE
310 CompletionPort: HANDLE
311 Overlapped: OVERLAPPED
312 Timeout as Milliseconds: DWORD
313 /
314
315Register wait for Object; when complete CompletionPort is notified.
316[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700317
318static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600319_overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
320 HANDLE CompletionPort,
321 OVERLAPPED *Overlapped,
322 DWORD Milliseconds)
323/*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700324{
325 HANDLE NewWaitObject;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600326 struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata;
Guido van Rossum90fb9142013-10-30 14:44:05 -0700327
Victor Stinner6150f312016-03-16 23:25:02 +0100328 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
329 PostToQueueCallback() will call PyMem_Free() from a new C thread
330 which doesn't hold the GIL. */
331 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700332 if (pdata == NULL)
333 return SetFromWindowsErr(0);
334
335 *pdata = data;
336
337 if (!RegisterWaitForSingleObject(
338 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
339 pdata, Milliseconds,
340 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
341 {
Victor Stinner6150f312016-03-16 23:25:02 +0100342 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700343 return SetFromWindowsErr(0);
344 }
345
346 return Py_BuildValue(F_HANDLE, NewWaitObject);
347}
348
Zackery Spytz9650fe02020-07-10 11:43:37 -0600349/*[clinic input]
350_overlapped.UnregisterWait
351
352 WaitHandle: HANDLE
353 /
354
355Unregister wait handle.
356[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700357
358static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600359_overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
360/*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700361{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700362 BOOL ret;
363
Guido van Rossum90fb9142013-10-30 14:44:05 -0700364 Py_BEGIN_ALLOW_THREADS
365 ret = UnregisterWait(WaitHandle);
366 Py_END_ALLOW_THREADS
367
368 if (!ret)
369 return SetFromWindowsErr(0);
370 Py_RETURN_NONE;
371}
372
Zackery Spytz9650fe02020-07-10 11:43:37 -0600373/*[clinic input]
374_overlapped.UnregisterWaitEx
375
376 WaitHandle: HANDLE
377 Event: HANDLE
378 /
379
380Unregister wait handle.
381[clinic start generated code]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100382
383static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600384_overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
385 HANDLE Event)
386/*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100387{
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100388 BOOL ret;
389
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100390 Py_BEGIN_ALLOW_THREADS
391 ret = UnregisterWaitEx(WaitHandle, Event);
392 Py_END_ALLOW_THREADS
393
394 if (!ret)
395 return SetFromWindowsErr(0);
396 Py_RETURN_NONE;
397}
398
Guido van Rossum90fb9142013-10-30 14:44:05 -0700399/*
400 * Event functions -- currently only used by tests
401 */
402
Zackery Spytz9650fe02020-07-10 11:43:37 -0600403/*[clinic input]
404_overlapped.CreateEvent
405
406 EventAttributes: object
407 ManualReset: BOOL
408 InitialState: BOOL
409 Name: Py_UNICODE(accept={str, NoneType})
410 /
411
412Create an event.
413
414EventAttributes must be None.
415[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700416
417static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600418_overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
419 BOOL ManualReset, BOOL InitialState,
420 const Py_UNICODE *Name)
421/*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700422{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700423 HANDLE Event;
424
Guido van Rossum90fb9142013-10-30 14:44:05 -0700425 if (EventAttributes != Py_None) {
426 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
427 return NULL;
428 }
429
430 Py_BEGIN_ALLOW_THREADS
431 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
432 Py_END_ALLOW_THREADS
433
434 if (Event == NULL)
435 return SetFromWindowsErr(0);
436 return Py_BuildValue(F_HANDLE, Event);
437}
438
Zackery Spytz9650fe02020-07-10 11:43:37 -0600439/*[clinic input]
440_overlapped.SetEvent
441
442 Handle: HANDLE
443 /
444
445Set event.
446[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700447
448static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600449_overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
450/*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700451{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700452 BOOL ret;
453
Guido van Rossum90fb9142013-10-30 14:44:05 -0700454 Py_BEGIN_ALLOW_THREADS
455 ret = SetEvent(Handle);
456 Py_END_ALLOW_THREADS
457
458 if (!ret)
459 return SetFromWindowsErr(0);
460 Py_RETURN_NONE;
461}
462
Zackery Spytz9650fe02020-07-10 11:43:37 -0600463/*[clinic input]
464_overlapped.ResetEvent
465
466 Handle: HANDLE
467 /
468
469Reset event.
470[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700471
472static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600473_overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
474/*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700475{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700476 BOOL ret;
477
Guido van Rossum90fb9142013-10-30 14:44:05 -0700478 Py_BEGIN_ALLOW_THREADS
479 ret = ResetEvent(Handle);
480 Py_END_ALLOW_THREADS
481
482 if (!ret)
483 return SetFromWindowsErr(0);
484 Py_RETURN_NONE;
485}
486
487/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700488 * Bind socket handle to local port without doing slow getaddrinfo()
489 */
490
Zackery Spytz9650fe02020-07-10 11:43:37 -0600491/*[clinic input]
492_overlapped.BindLocal
493
494 handle as Socket: HANDLE
495 family as Family: int
496 /
497
498Bind a socket handle to an arbitrary local port.
499
500family should be AF_INET or AF_INET6.
501[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700502
503static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600504_overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
505/*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700506{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700507 BOOL ret;
508
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700509 if (Family == AF_INET) {
510 struct sockaddr_in addr;
511 memset(&addr, 0, sizeof(addr));
512 addr.sin_family = AF_INET;
513 addr.sin_port = 0;
514 addr.sin_addr.S_un.S_addr = INADDR_ANY;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600515 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
516 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700517 } else if (Family == AF_INET6) {
518 struct sockaddr_in6 addr;
519 memset(&addr, 0, sizeof(addr));
520 addr.sin6_family = AF_INET6;
521 addr.sin6_port = 0;
522 addr.sin6_addr = in6addr_any;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600523 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
524 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700525 } else {
526 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
527 return NULL;
528 }
529
530 if (!ret)
531 return SetFromWindowsErr(WSAGetLastError());
532 Py_RETURN_NONE;
533}
534
535/*
536 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
537 */
538
Zackery Spytz9650fe02020-07-10 11:43:37 -0600539/*[clinic input]
540_overlapped.FormatMessage
541
542 error_code as code: DWORD
543 /
544
545Return error message for an error code.
546[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700547
548static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600549_overlapped_FormatMessage_impl(PyObject *module, DWORD code)
550/*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700551{
Zackery Spytz9650fe02020-07-10 11:43:37 -0600552 DWORD n;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700553 WCHAR *lpMsgBuf;
554 PyObject *res;
555
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700556 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600557 FORMAT_MESSAGE_FROM_SYSTEM |
558 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700559 NULL,
560 code,
561 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
562 (LPWSTR) &lpMsgBuf,
563 0,
564 NULL);
565 if (n) {
566 while (iswspace(lpMsgBuf[n-1]))
567 --n;
568 lpMsgBuf[n] = L'\0';
569 res = Py_BuildValue("u", lpMsgBuf);
570 } else {
571 res = PyUnicode_FromFormat("unknown error code %u", code);
572 }
573 LocalFree(lpMsgBuf);
574 return res;
575}
576
577
578/*
579 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
580 */
581
582static void
583mark_as_completed(OVERLAPPED *ov)
584{
585 ov->Internal = 0;
586 if (ov->hEvent != NULL)
587 SetEvent(ov->hEvent);
588}
589
590/*
591 * A Python object wrapping an OVERLAPPED structure and other useful data
592 * for overlapped I/O
593 */
594
Zackery Spytz9650fe02020-07-10 11:43:37 -0600595/*[clinic input]
596@classmethod
597_overlapped.Overlapped.__new__
598
599 event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
600
601OVERLAPPED structure wrapper.
602[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700603
604static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600605_overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
606/*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700607{
608 OverlappedObject *self;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700609
610 if (event == INVALID_HANDLE_VALUE) {
611 event = CreateEvent(NULL, TRUE, FALSE, NULL);
612 if (event == NULL)
613 return SetFromWindowsErr(0);
614 }
615
616 self = PyObject_New(OverlappedObject, type);
617 if (self == NULL) {
618 if (event != NULL)
619 CloseHandle(event);
620 return NULL;
621 }
622
623 self->handle = NULL;
624 self->error = 0;
625 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200626 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700627 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200628 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700629 if (event)
630 self->overlapped.hEvent = event;
631 return (PyObject *)self;
632}
633
Victor Stinner54850852019-01-11 14:35:14 +0100634
635/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
636 buffers while overlapped are still running, to prevent a crash. */
637static int
638Overlapped_clear(OverlappedObject *self)
639{
640 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300641 case TYPE_READ:
642 case TYPE_ACCEPT: {
643 Py_CLEAR(self->allocated_buffer);
644 break;
Victor Stinner54850852019-01-11 14:35:14 +0100645 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300646 case TYPE_READ_FROM: {
647 // An initial call to WSARecvFrom will only allocate the buffer.
648 // The result tuple of (message, address) is only
649 // allocated _after_ a message has been received.
650 if(self->read_from.result) {
651 // We've received a message, free the result tuple.
652 Py_CLEAR(self->read_from.result);
653 }
654 if(self->read_from.allocated_buffer) {
655 Py_CLEAR(self->read_from.allocated_buffer);
656 }
657 break;
658 }
659 case TYPE_WRITE:
660 case TYPE_WRITE_TO:
661 case TYPE_READINTO: {
662 if (self->user_buffer.obj) {
663 PyBuffer_Release(&self->user_buffer);
664 }
665 break;
666 }
Victor Stinner54850852019-01-11 14:35:14 +0100667 }
668 self->type = TYPE_NOT_STARTED;
669 return 0;
670}
671
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700672static void
673Overlapped_dealloc(OverlappedObject *self)
674{
675 DWORD bytes;
676 DWORD olderr = GetLastError();
677 BOOL wait = FALSE;
678 BOOL ret;
679
680 if (!HasOverlappedIoCompleted(&self->overlapped) &&
681 self->type != TYPE_NOT_STARTED)
682 {
683 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
684 wait = TRUE;
685
686 Py_BEGIN_ALLOW_THREADS
687 ret = GetOverlappedResult(self->handle, &self->overlapped,
688 &bytes, wait);
689 Py_END_ALLOW_THREADS
690
691 switch (ret ? ERROR_SUCCESS : GetLastError()) {
692 case ERROR_SUCCESS:
693 case ERROR_NOT_FOUND:
694 case ERROR_OPERATION_ABORTED:
695 break;
696 default:
697 PyErr_Format(
698 PyExc_RuntimeError,
699 "%R still has pending operation at "
700 "deallocation, the process may crash", self);
701 PyErr_WriteUnraisable(NULL);
702 }
703 }
704
Victor Stinner54850852019-01-11 14:35:14 +0100705 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700706 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700707 }
Victor Stinner54850852019-01-11 14:35:14 +0100708
709 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700710 PyObject_Del(self);
711 SetLastError(olderr);
712}
713
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300714
715/* Convert IPv4 sockaddr to a Python str. */
716
717static PyObject *
718make_ipv4_addr(const struct sockaddr_in *addr)
719{
720 char buf[INET_ADDRSTRLEN];
721 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
722 PyErr_SetFromErrno(PyExc_OSError);
723 return NULL;
724 }
725 return PyUnicode_FromString(buf);
726}
727
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300728/* Convert IPv6 sockaddr to a Python str. */
729
730static PyObject *
731make_ipv6_addr(const struct sockaddr_in6 *addr)
732{
733 char buf[INET6_ADDRSTRLEN];
734 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
735 PyErr_SetFromErrno(PyExc_OSError);
736 return NULL;
737 }
738 return PyUnicode_FromString(buf);
739}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300740
741static PyObject*
742unparse_address(LPSOCKADDR Address, DWORD Length)
743{
744 /* The function is adopted from mocketmodule.c makesockaddr()*/
745
746 switch(Address->sa_family) {
747 case AF_INET: {
748 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
749 PyObject *addrobj = make_ipv4_addr(a);
750 PyObject *ret = NULL;
751 if (addrobj) {
752 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
753 Py_DECREF(addrobj);
754 }
755 return ret;
756 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300757 case AF_INET6: {
758 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
759 PyObject *addrobj = make_ipv6_addr(a);
760 PyObject *ret = NULL;
761 if (addrobj) {
762 ret = Py_BuildValue("OiII",
763 addrobj,
764 ntohs(a->sin6_port),
765 ntohl(a->sin6_flowinfo),
766 a->sin6_scope_id);
767 Py_DECREF(addrobj);
768 }
769 return ret;
770 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300771 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200772 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
773 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300774 }
775 }
776}
777
Zackery Spytz9650fe02020-07-10 11:43:37 -0600778/*[clinic input]
779_overlapped.Overlapped.cancel
780
781Cancel overlapped operation.
782[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700783
784static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600785_overlapped_Overlapped_cancel_impl(OverlappedObject *self)
786/*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700787{
788 BOOL ret = TRUE;
789
790 if (self->type == TYPE_NOT_STARTED
791 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
792 Py_RETURN_NONE;
793
794 if (!HasOverlappedIoCompleted(&self->overlapped)) {
795 Py_BEGIN_ALLOW_THREADS
796 if (Py_CancelIoEx)
797 ret = Py_CancelIoEx(self->handle, &self->overlapped);
798 else
799 ret = CancelIo(self->handle);
800 Py_END_ALLOW_THREADS
801 }
802
803 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
804 if (!ret && GetLastError() != ERROR_NOT_FOUND)
805 return SetFromWindowsErr(0);
806 Py_RETURN_NONE;
807}
808
Zackery Spytz9650fe02020-07-10 11:43:37 -0600809/*[clinic input]
810_overlapped.Overlapped.getresult
811
812 wait: BOOL(c_default='FALSE') = False
813 /
814
815Retrieve result of operation.
816
817If wait is true then it blocks until the operation is finished. If wait
818is false and the operation is still pending then an error is raised.
819[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700820
821static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600822_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
823/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700824{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700825 DWORD transferred = 0;
826 BOOL ret;
827 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300828 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700829
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700830 if (self->type == TYPE_NONE) {
831 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
832 return NULL;
833 }
834
835 if (self->type == TYPE_NOT_STARTED) {
836 PyErr_SetString(PyExc_ValueError, "operation failed to start");
837 return NULL;
838 }
839
840 Py_BEGIN_ALLOW_THREADS
841 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
842 wait);
843 Py_END_ALLOW_THREADS
844
845 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
846 switch (err) {
847 case ERROR_SUCCESS:
848 case ERROR_MORE_DATA:
849 break;
850 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300851 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700852 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300853 }
854 else if (self->type == TYPE_READ_FROM &&
855 (self->read_from.result != NULL ||
856 self->read_from.allocated_buffer != NULL))
857 {
858 break;
859 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700860 /* fall through */
861 default:
862 return SetFromWindowsErr(err);
863 }
864
865 switch (self->type) {
866 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200867 assert(PyBytes_CheckExact(self->allocated_buffer));
868 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
869 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700870 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300871
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200872 Py_INCREF(self->allocated_buffer);
873 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300874 case TYPE_READ_FROM:
875 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
876
877 if (transferred != PyBytes_GET_SIZE(
878 self->read_from.allocated_buffer) &&
879 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
880 {
881 return NULL;
882 }
883
884 // unparse the address
885 addr = unparse_address((SOCKADDR*)&self->read_from.address,
886 self->read_from.address_length);
887
888 if (addr == NULL) {
889 return NULL;
890 }
891
892 // The result is a two item tuple: (message, address)
893 self->read_from.result = PyTuple_New(2);
894 if (self->read_from.result == NULL) {
895 Py_CLEAR(addr);
896 return NULL;
897 }
898
899 // first item: message
900 Py_INCREF(self->read_from.allocated_buffer);
901 PyTuple_SET_ITEM(self->read_from.result, 0,
902 self->read_from.allocated_buffer);
903 // second item: address
904 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
905
906 Py_INCREF(self->read_from.result);
907 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700908 default:
909 return PyLong_FromUnsignedLong((unsigned long) transferred);
910 }
911}
912
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200913static PyObject *
914do_ReadFile(OverlappedObject *self, HANDLE handle,
915 char *bufstart, DWORD buflen)
916{
917 DWORD nread;
918 int ret;
919 DWORD err;
920
921 Py_BEGIN_ALLOW_THREADS
922 ret = ReadFile(handle, bufstart, buflen, &nread,
923 &self->overlapped);
924 Py_END_ALLOW_THREADS
925
926 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
927 switch (err) {
928 case ERROR_BROKEN_PIPE:
929 mark_as_completed(&self->overlapped);
930 return SetFromWindowsErr(err);
931 case ERROR_SUCCESS:
932 case ERROR_MORE_DATA:
933 case ERROR_IO_PENDING:
934 Py_RETURN_NONE;
935 default:
Victor Stinner54850852019-01-11 14:35:14 +0100936 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200937 return SetFromWindowsErr(err);
938 }
939}
940
Zackery Spytz9650fe02020-07-10 11:43:37 -0600941/*[clinic input]
942_overlapped.Overlapped.ReadFile
943
944 handle: HANDLE
945 size: DWORD
946 /
947
948Start overlapped read.
949[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700950
951static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600952_overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
953 DWORD size)
954/*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700955{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700956 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700957
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700958 if (self->type != TYPE_NONE) {
959 PyErr_SetString(PyExc_ValueError, "operation already attempted");
960 return NULL;
961 }
962
963#if SIZEOF_SIZE_T <= SIZEOF_LONG
964 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
965#endif
966 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
967 if (buf == NULL)
968 return NULL;
969
970 self->type = TYPE_READ;
971 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200972 self->allocated_buffer = buf;
973
974 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
975}
976
Zackery Spytz9650fe02020-07-10 11:43:37 -0600977/*[clinic input]
978_overlapped.Overlapped.ReadFileInto
979
980 handle: HANDLE
981 buf as bufobj: object
982 /
983
984Start overlapped receive.
985[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200986
987static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600988_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
989 HANDLE handle, PyObject *bufobj)
990/*[clinic end generated code: output=1e9e712e742e5b2a input=16f6cc268d1d0387]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200991{
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200992 if (self->type != TYPE_NONE) {
993 PyErr_SetString(PyExc_ValueError, "operation already attempted");
994 return NULL;
995 }
996
997 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
998 return NULL;
999
1000#if SIZEOF_SIZE_T > SIZEOF_LONG
1001 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1002 PyBuffer_Release(&self->user_buffer);
1003 PyErr_SetString(PyExc_ValueError, "buffer too large");
1004 return NULL;
1005 }
1006#endif
1007
1008 self->type = TYPE_READINTO;
1009 self->handle = handle;
1010
1011 return do_ReadFile(self, handle, self->user_buffer.buf,
1012 (DWORD)self->user_buffer.len);
1013}
1014
1015static PyObject *
1016do_WSARecv(OverlappedObject *self, HANDLE handle,
1017 char *bufstart, DWORD buflen, DWORD flags)
1018{
1019 DWORD nread;
1020 WSABUF wsabuf;
1021 int ret;
1022 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +03001023
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001024 wsabuf.buf = bufstart;
1025 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001026
1027 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001028 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1029 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001030 Py_END_ALLOW_THREADS
1031
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001032 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001033 switch (err) {
1034 case ERROR_BROKEN_PIPE:
1035 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +01001036 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001037 case ERROR_SUCCESS:
1038 case ERROR_MORE_DATA:
1039 case ERROR_IO_PENDING:
1040 Py_RETURN_NONE;
1041 default:
Victor Stinner54850852019-01-11 14:35:14 +01001042 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001043 return SetFromWindowsErr(err);
1044 }
1045}
1046
Zackery Spytz9650fe02020-07-10 11:43:37 -06001047/*[clinic input]
1048_overlapped.Overlapped.WSARecv
1049
1050 handle: HANDLE
1051 size: DWORD
1052 flags: DWORD = 0
1053 /
1054
1055Start overlapped receive.
1056[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001057
1058static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001059_overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
1060 DWORD size, DWORD flags)
1061/*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001062{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001063 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001064
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001065 if (self->type != TYPE_NONE) {
1066 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1067 return NULL;
1068 }
1069
1070#if SIZEOF_SIZE_T <= SIZEOF_LONG
1071 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1072#endif
1073 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1074 if (buf == NULL)
1075 return NULL;
1076
1077 self->type = TYPE_READ;
1078 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001079 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001080
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001081 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1082}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001083
Zackery Spytz9650fe02020-07-10 11:43:37 -06001084/*[clinic input]
1085_overlapped.Overlapped.WSARecvInto
1086
1087 handle: HANDLE
1088 buf as bufobj: object
1089 flags: DWORD
1090 /
1091
1092Start overlapped receive.
1093[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001094
1095static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001096_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
1097 HANDLE handle, PyObject *bufobj,
1098 DWORD flags)
1099/*[clinic end generated code: output=9a438abc436fe87c input=4f87c38fc381d525]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001100{
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001101 if (self->type != TYPE_NONE) {
1102 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1103 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001104 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001105
1106 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1107 return NULL;
1108
1109#if SIZEOF_SIZE_T > SIZEOF_LONG
1110 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1111 PyBuffer_Release(&self->user_buffer);
1112 PyErr_SetString(PyExc_ValueError, "buffer too large");
1113 return NULL;
1114 }
1115#endif
1116
1117 self->type = TYPE_READINTO;
1118 self->handle = handle;
1119
1120 return do_WSARecv(self, handle, self->user_buffer.buf,
1121 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001122}
1123
Zackery Spytz9650fe02020-07-10 11:43:37 -06001124/*[clinic input]
1125_overlapped.Overlapped.WriteFile
1126
1127 handle: HANDLE
1128 buf as bufobj: object
1129 /
1130
1131Start overlapped write.
1132[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001133
1134static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001135_overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
1136 PyObject *bufobj)
1137/*[clinic end generated code: output=c376230b6120d877 input=b8d9a7608d8a1e72]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001138{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001139 DWORD written;
1140 BOOL ret;
1141 DWORD err;
1142
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001143 if (self->type != TYPE_NONE) {
1144 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1145 return NULL;
1146 }
1147
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001148 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001149 return NULL;
1150
1151#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001152 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1153 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001154 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001155 return NULL;
1156 }
1157#endif
1158
1159 self->type = TYPE_WRITE;
1160 self->handle = handle;
1161
1162 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001163 ret = WriteFile(handle, self->user_buffer.buf,
1164 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001165 &written, &self->overlapped);
1166 Py_END_ALLOW_THREADS
1167
1168 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1169 switch (err) {
1170 case ERROR_SUCCESS:
1171 case ERROR_IO_PENDING:
1172 Py_RETURN_NONE;
1173 default:
Victor Stinner54850852019-01-11 14:35:14 +01001174 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001175 return SetFromWindowsErr(err);
1176 }
1177}
1178
Zackery Spytz9650fe02020-07-10 11:43:37 -06001179/*[clinic input]
1180_overlapped.Overlapped.WSASend
1181
1182 handle: HANDLE
1183 buf as bufobj: object
1184 flags: DWORD
1185 /
1186
1187Start overlapped send.
1188[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001189
1190static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001191_overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
1192 PyObject *bufobj, DWORD flags)
1193/*[clinic end generated code: output=316031c7467040cc input=932e7cba6d18f708]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001194{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001195 DWORD written;
1196 WSABUF wsabuf;
1197 int ret;
1198 DWORD err;
1199
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001200 if (self->type != TYPE_NONE) {
1201 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1202 return NULL;
1203 }
1204
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001205 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001206 return NULL;
1207
1208#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001209 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1210 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001211 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001212 return NULL;
1213 }
1214#endif
1215
1216 self->type = TYPE_WRITE;
1217 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001218 wsabuf.len = (DWORD)self->user_buffer.len;
1219 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001220
1221 Py_BEGIN_ALLOW_THREADS
1222 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1223 &self->overlapped, NULL);
1224 Py_END_ALLOW_THREADS
1225
1226 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1227 switch (err) {
1228 case ERROR_SUCCESS:
1229 case ERROR_IO_PENDING:
1230 Py_RETURN_NONE;
1231 default:
Victor Stinner54850852019-01-11 14:35:14 +01001232 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001233 return SetFromWindowsErr(err);
1234 }
1235}
1236
Zackery Spytz9650fe02020-07-10 11:43:37 -06001237/*[clinic input]
1238_overlapped.Overlapped.AcceptEx
1239
1240 listen_handle as ListenSocket: HANDLE
1241 accept_handle as AcceptSocket: HANDLE
1242 /
1243
1244Start overlapped wait for client to connect.
1245[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001246
1247static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001248_overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
1249 HANDLE ListenSocket,
1250 HANDLE AcceptSocket)
1251/*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001252{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001253 DWORD BytesReceived;
1254 DWORD size;
1255 PyObject *buf;
1256 BOOL ret;
1257 DWORD err;
1258
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001259 if (self->type != TYPE_NONE) {
1260 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1261 return NULL;
1262 }
1263
1264 size = sizeof(struct sockaddr_in6) + 16;
1265 buf = PyBytes_FromStringAndSize(NULL, size*2);
1266 if (!buf)
1267 return NULL;
1268
1269 self->type = TYPE_ACCEPT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001270 self->handle = ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001271 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001272
1273 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001274 ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
1275 PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
1276 &self->overlapped);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001277 Py_END_ALLOW_THREADS
1278
1279 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1280 switch (err) {
1281 case ERROR_SUCCESS:
1282 case ERROR_IO_PENDING:
1283 Py_RETURN_NONE;
1284 default:
Victor Stinner54850852019-01-11 14:35:14 +01001285 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001286 return SetFromWindowsErr(err);
1287 }
1288}
1289
1290
1291static int
1292parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1293{
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001294 PyObject *Host_obj;
Steve Dowercc16be82016-09-08 10:35:16 -07001295 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001296 unsigned short Port;
1297 unsigned long FlowInfo;
1298 unsigned long ScopeId;
1299
1300 memset(Address, 0, Length);
1301
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001302 switch (PyTuple_GET_SIZE(obj)) {
1303 case 2: {
1304 if (!PyArg_ParseTuple(obj, "UH", &Host_obj, &Port)) {
1305 return -1;
1306 }
1307#if USE_UNICODE_WCHAR_CACHE
1308 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1309#else /* USE_UNICODE_WCHAR_CACHE */
1310 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1311#endif /* USE_UNICODE_WCHAR_CACHE */
1312 if (Host == NULL) {
1313 return -1;
1314 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001315 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001316 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001317 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001318 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001319 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001320 else {
1321 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1322 }
1323#if !USE_UNICODE_WCHAR_CACHE
1324 PyMem_Free(Host);
1325#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001326 return Length;
1327 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001328 case 4: {
1329 if (!PyArg_ParseTuple(obj,
1330 "UHkk;ConnectEx(): illegal address_as_bytes argument",
1331 &Host_obj, &Port, &FlowInfo, &ScopeId))
1332 {
1333 return -1;
1334 }
1335#if USE_UNICODE_WCHAR_CACHE
1336 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1337#else /* USE_UNICODE_WCHAR_CACHE */
1338 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1339#endif /* USE_UNICODE_WCHAR_CACHE */
1340 if (Host == NULL) {
1341 return -1;
1342 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001343 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001344 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001345 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001346 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001347 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001348 else {
1349 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1350 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1351 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1352 }
1353#if !USE_UNICODE_WCHAR_CACHE
1354 PyMem_Free(Host);
1355#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001356 return Length;
1357 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001358 default:
1359 PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument");
1360 return -1;
1361 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001362}
1363
Zackery Spytz9650fe02020-07-10 11:43:37 -06001364/*[clinic input]
1365_overlapped.Overlapped.ConnectEx
1366
1367 client_handle as ConnectSocket: HANDLE
1368 address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1369 /
1370
1371Start overlapped connect.
1372
1373client_handle should be unbound.
1374[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001375
1376static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001377_overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
1378 HANDLE ConnectSocket,
1379 PyObject *AddressObj)
1380/*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001381{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001382 char AddressBuf[sizeof(struct sockaddr_in6)];
1383 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1384 int Length;
1385 BOOL ret;
1386 DWORD err;
1387
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001388 if (self->type != TYPE_NONE) {
1389 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1390 return NULL;
1391 }
1392
1393 Length = sizeof(AddressBuf);
1394 Length = parse_address(AddressObj, Address, Length);
1395 if (Length < 0)
1396 return NULL;
1397
1398 self->type = TYPE_CONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001399 self->handle = ConnectSocket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001400
1401 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001402 ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001403 NULL, 0, NULL, &self->overlapped);
1404 Py_END_ALLOW_THREADS
1405
1406 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1407 switch (err) {
1408 case ERROR_SUCCESS:
1409 case ERROR_IO_PENDING:
1410 Py_RETURN_NONE;
1411 default:
Victor Stinner54850852019-01-11 14:35:14 +01001412 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001413 return SetFromWindowsErr(err);
1414 }
1415}
1416
Zackery Spytz9650fe02020-07-10 11:43:37 -06001417/*[clinic input]
1418_overlapped.Overlapped.DisconnectEx
1419
1420 handle as Socket: HANDLE
1421 flags: DWORD
1422 /
1423
1424[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001425
1426static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001427_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
1428 HANDLE Socket, DWORD flags)
1429/*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001430{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001431 BOOL ret;
1432 DWORD err;
1433
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001434 if (self->type != TYPE_NONE) {
1435 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1436 return NULL;
1437 }
1438
1439 self->type = TYPE_DISCONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001440 self->handle = Socket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001441
1442 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001443 ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001444 Py_END_ALLOW_THREADS
1445
1446 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1447 switch (err) {
1448 case ERROR_SUCCESS:
1449 case ERROR_IO_PENDING:
1450 Py_RETURN_NONE;
1451 default:
Victor Stinner54850852019-01-11 14:35:14 +01001452 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001453 return SetFromWindowsErr(err);
1454 }
1455}
1456
Zackery Spytz9650fe02020-07-10 11:43:37 -06001457/*[clinic input]
1458_overlapped.Overlapped.TransmitFile
1459
1460 socket as Socket: HANDLE
1461 file as File: HANDLE
1462 offset: DWORD
1463 offset_high: DWORD
1464 count_to_write: DWORD
1465 count_per_send: DWORD
1466 flags: DWORD
1467 /
1468
1469Transmit file data over a connected socket.
1470[clinic start generated code]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001471
1472static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001473_overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
1474 HANDLE Socket, HANDLE File,
1475 DWORD offset, DWORD offset_high,
1476 DWORD count_to_write,
1477 DWORD count_per_send, DWORD flags)
1478/*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001479{
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001480 BOOL ret;
1481 DWORD err;
1482
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001483 if (self->type != TYPE_NONE) {
1484 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1485 return NULL;
1486 }
1487
1488 self->type = TYPE_TRANSMIT_FILE;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001489 self->handle = Socket;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001490 self->overlapped.Offset = offset;
1491 self->overlapped.OffsetHigh = offset_high;
1492
1493 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001494 ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
1495 count_per_send, &self->overlapped, NULL, flags);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001496 Py_END_ALLOW_THREADS
1497
1498 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1499 switch (err) {
1500 case ERROR_SUCCESS:
1501 case ERROR_IO_PENDING:
1502 Py_RETURN_NONE;
1503 default:
Victor Stinner54850852019-01-11 14:35:14 +01001504 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001505 return SetFromWindowsErr(err);
1506 }
1507}
1508
Zackery Spytz9650fe02020-07-10 11:43:37 -06001509/*[clinic input]
1510_overlapped.Overlapped.ConnectNamedPipe
1511
1512 handle as Pipe: HANDLE
1513 /
1514
1515Start overlapped wait for a client to connect.
1516[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001517
1518static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001519_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
1520 HANDLE Pipe)
1521/*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001522{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001523 BOOL ret;
1524 DWORD err;
1525
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001526 if (self->type != TYPE_NONE) {
1527 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1528 return NULL;
1529 }
1530
1531 self->type = TYPE_CONNECT_NAMED_PIPE;
1532 self->handle = Pipe;
1533
1534 Py_BEGIN_ALLOW_THREADS
1535 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1536 Py_END_ALLOW_THREADS
1537
1538 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1539 switch (err) {
1540 case ERROR_PIPE_CONNECTED:
1541 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001542 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001543 case ERROR_SUCCESS:
1544 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001545 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001546 default:
Victor Stinner54850852019-01-11 14:35:14 +01001547 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001548 return SetFromWindowsErr(err);
1549 }
1550}
1551
Zackery Spytz9650fe02020-07-10 11:43:37 -06001552/*[clinic input]
1553_overlapped.Overlapped.ConnectPipe
1554
1555 addr as Address: Py_UNICODE
1556 /
1557
1558Connect to the pipe for asynchronous I/O (overlapped).
1559[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001560
1561static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001562_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
1563 const Py_UNICODE *Address)
1564/*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001565{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001566 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001567
Victor Stinner498b1f62015-01-26 22:43:39 +01001568 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001569 PipeHandle = CreateFileW(Address,
1570 GENERIC_READ | GENERIC_WRITE,
1571 0, NULL, OPEN_EXISTING,
1572 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001573 Py_END_ALLOW_THREADS
1574
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001575 if (PipeHandle == INVALID_HANDLE_VALUE)
1576 return SetFromWindowsErr(0);
1577 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001578}
1579
1580static PyObject*
1581Overlapped_getaddress(OverlappedObject *self)
1582{
1583 return PyLong_FromVoidPtr(&self->overlapped);
1584}
1585
1586static PyObject*
1587Overlapped_getpending(OverlappedObject *self)
1588{
1589 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1590 self->type != TYPE_NOT_STARTED);
1591}
1592
Victor Stinner54850852019-01-11 14:35:14 +01001593static int
1594Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1595{
1596 switch (self->type) {
1597 case TYPE_READ:
1598 case TYPE_ACCEPT:
1599 Py_VISIT(self->allocated_buffer);
1600 break;
1601 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001602 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001603 case TYPE_READINTO:
1604 if (self->user_buffer.obj) {
1605 Py_VISIT(&self->user_buffer.obj);
1606 }
1607 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001608 case TYPE_READ_FROM:
Hai Shi47a23fc2020-06-07 20:05:36 +08001609 Py_VISIT(self->read_from.result);
1610 Py_VISIT(self->read_from.allocated_buffer);
Victor Stinner54850852019-01-11 14:35:14 +01001611 }
1612 return 0;
1613}
1614
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001615// UDP functions
1616
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001617/*
1618 * Note: WSAConnect does not support Overlapped I/O so this function should
1619 * _only_ be used for connectionless sockets (UDP).
1620 */
Zackery Spytz9650fe02020-07-10 11:43:37 -06001621
1622/*[clinic input]
1623_overlapped.WSAConnect
1624
1625 client_handle as ConnectSocket: HANDLE
1626 address_as_bytes as AddressObj: object
1627 /
1628
1629Bind a remote address to a connectionless (UDP) socket.
1630[clinic start generated code]*/
1631
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001632static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001633_overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
1634 PyObject *AddressObj)
1635/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001636{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001637 char AddressBuf[sizeof(struct sockaddr_in6)];
1638 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1639 int Length;
1640 int err;
1641
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001642 Length = sizeof(AddressBuf);
1643 Length = parse_address(AddressObj, Address, Length);
1644 if (Length < 0) {
1645 return NULL;
1646 }
1647
1648 Py_BEGIN_ALLOW_THREADS
1649 // WSAConnect does not support overlapped I/O so this call will
1650 // successfully complete immediately.
Zackery Spytz9650fe02020-07-10 11:43:37 -06001651 err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001652 NULL, NULL, NULL, NULL);
1653 Py_END_ALLOW_THREADS
1654
1655 if (err == 0) {
1656 Py_RETURN_NONE;
1657 }
1658 else {
1659 return SetFromWindowsErr(WSAGetLastError());
1660 }
1661}
1662
Zackery Spytz9650fe02020-07-10 11:43:37 -06001663/*[clinic input]
1664_overlapped.Overlapped.WSASendTo
1665
1666 handle: HANDLE
1667 buf as bufobj: object
1668 flags: DWORD
1669 address_as_bytes as AddressObj: object
1670 /
1671
1672Start overlapped sendto over a connectionless (UDP) socket.
1673[clinic start generated code]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001674
1675static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001676_overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
1677 PyObject *bufobj, DWORD flags,
1678 PyObject *AddressObj)
1679/*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001680{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001681 char AddressBuf[sizeof(struct sockaddr_in6)];
1682 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1683 int AddressLength;
1684 DWORD written;
1685 WSABUF wsabuf;
1686 int ret;
1687 DWORD err;
1688
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001689 // Parse the "to" address
1690 AddressLength = sizeof(AddressBuf);
1691 AddressLength = parse_address(AddressObj, Address, AddressLength);
1692 if (AddressLength < 0) {
1693 return NULL;
1694 }
1695
1696 if (self->type != TYPE_NONE) {
1697 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1698 return NULL;
1699 }
1700
1701 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1702 return NULL;
1703 }
1704
1705#if SIZEOF_SIZE_T > SIZEOF_LONG
1706 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1707 PyBuffer_Release(&self->user_buffer);
1708 PyErr_SetString(PyExc_ValueError, "buffer too large");
1709 return NULL;
1710 }
1711#endif
1712
1713 self->type = TYPE_WRITE_TO;
1714 self->handle = handle;
1715 wsabuf.len = (DWORD)self->user_buffer.len;
1716 wsabuf.buf = self->user_buffer.buf;
1717
1718 Py_BEGIN_ALLOW_THREADS
1719 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1720 Address, AddressLength, &self->overlapped, NULL);
1721 Py_END_ALLOW_THREADS
1722
1723 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1724 ERROR_SUCCESS);
1725
1726 switch(err) {
1727 case ERROR_SUCCESS:
1728 case ERROR_IO_PENDING:
1729 Py_RETURN_NONE;
1730 default:
1731 self->type = TYPE_NOT_STARTED;
1732 return SetFromWindowsErr(err);
1733 }
1734}
1735
1736
1737
1738PyDoc_STRVAR(
1739 Overlapped_WSARecvFrom_doc,
1740 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1741 "Start overlapped receive");
1742
Zackery Spytz9650fe02020-07-10 11:43:37 -06001743/*[clinic input]
1744_overlapped.Overlapped.WSARecvFrom
1745
1746 handle: HANDLE
1747 size: DWORD
1748 flags: DWORD = 0
1749 /
1750
1751Start overlapped receive.
1752[clinic start generated code]*/
1753
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001754static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001755_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
1756 HANDLE handle, DWORD size,
1757 DWORD flags)
1758/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001759{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001760 DWORD nread;
1761 PyObject *buf;
1762 WSABUF wsabuf;
1763 int ret;
1764 DWORD err;
1765
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001766 if (self->type != TYPE_NONE) {
1767 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1768 return NULL;
1769 }
1770
1771#if SIZEOF_SIZE_T <= SIZEOF_LONG
1772 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1773#endif
1774 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1775 if (buf == NULL) {
1776 return NULL;
1777 }
1778
1779 wsabuf.len = size;
1780 wsabuf.buf = PyBytes_AS_STRING(buf);
1781
1782 self->type = TYPE_READ_FROM;
1783 self->handle = handle;
1784 self->read_from.allocated_buffer = buf;
1785 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1786 self->read_from.address_length = sizeof(self->read_from.address);
1787
1788 Py_BEGIN_ALLOW_THREADS
1789 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1790 (SOCKADDR*)&self->read_from.address,
1791 &self->read_from.address_length,
1792 &self->overlapped, NULL);
1793 Py_END_ALLOW_THREADS
1794
1795 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1796
1797 switch(err) {
1798 case ERROR_BROKEN_PIPE:
1799 mark_as_completed(&self->overlapped);
1800 return SetFromWindowsErr(err);
1801 case ERROR_SUCCESS:
1802 case ERROR_MORE_DATA:
1803 case ERROR_IO_PENDING:
1804 Py_RETURN_NONE;
1805 default:
1806 self->type = TYPE_NOT_STARTED;
1807 return SetFromWindowsErr(err);
1808 }
1809}
1810
Zackery Spytz9650fe02020-07-10 11:43:37 -06001811#include "clinic/overlapped.c.h"
Victor Stinner54850852019-01-11 14:35:14 +01001812
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001813static PyMethodDef Overlapped_methods[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001814 _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
1815 _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
1816 _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
1817 _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
1818 _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
1819 _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
1820 _OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
1821 _OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
1822 _OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
1823 _OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
1824 _OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
1825 _OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
1826 _OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
1827 _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1828 _OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001829 {NULL}
1830};
1831
1832static PyMemberDef Overlapped_members[] = {
1833 {"error", T_ULONG,
1834 offsetof(OverlappedObject, error),
1835 READONLY, "Error from last operation"},
1836 {"event", T_HANDLE,
1837 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1838 READONLY, "Overlapped event handle"},
1839 {NULL}
1840};
1841
1842static PyGetSetDef Overlapped_getsets[] = {
1843 {"address", (getter)Overlapped_getaddress, NULL,
1844 "Address of overlapped structure"},
1845 {"pending", (getter)Overlapped_getpending, NULL,
1846 "Whether the operation is pending"},
1847 {NULL},
1848};
1849
1850PyTypeObject OverlappedType = {
1851 PyVarObject_HEAD_INIT(NULL, 0)
1852 /* tp_name */ "_overlapped.Overlapped",
1853 /* tp_basicsize */ sizeof(OverlappedObject),
1854 /* tp_itemsize */ 0,
1855 /* tp_dealloc */ (destructor) Overlapped_dealloc,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001856 /* tp_vectorcall_offset */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001857 /* tp_getattr */ 0,
1858 /* tp_setattr */ 0,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001859 /* tp_as_async */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001860 /* tp_repr */ 0,
1861 /* tp_as_number */ 0,
1862 /* tp_as_sequence */ 0,
1863 /* tp_as_mapping */ 0,
1864 /* tp_hash */ 0,
1865 /* tp_call */ 0,
1866 /* tp_str */ 0,
1867 /* tp_getattro */ 0,
1868 /* tp_setattro */ 0,
1869 /* tp_as_buffer */ 0,
1870 /* tp_flags */ Py_TPFLAGS_DEFAULT,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001871 /* tp_doc */ _overlapped_Overlapped__doc__,
Victor Stinner54850852019-01-11 14:35:14 +01001872 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001873 /* tp_clear */ 0,
1874 /* tp_richcompare */ 0,
1875 /* tp_weaklistoffset */ 0,
1876 /* tp_iter */ 0,
1877 /* tp_iternext */ 0,
1878 /* tp_methods */ Overlapped_methods,
1879 /* tp_members */ Overlapped_members,
1880 /* tp_getset */ Overlapped_getsets,
1881 /* tp_base */ 0,
1882 /* tp_dict */ 0,
1883 /* tp_descr_get */ 0,
1884 /* tp_descr_set */ 0,
1885 /* tp_dictoffset */ 0,
1886 /* tp_init */ 0,
1887 /* tp_alloc */ 0,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001888 /* tp_new */ _overlapped_Overlapped,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001889};
1890
1891static PyMethodDef overlapped_functions[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001892 _OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
1893 _OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
1894 _OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
1895 _OVERLAPPED_FORMATMESSAGE_METHODDEF
1896 _OVERLAPPED_BINDLOCAL_METHODDEF
1897 _OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
1898 _OVERLAPPED_UNREGISTERWAIT_METHODDEF
1899 _OVERLAPPED_UNREGISTERWAITEX_METHODDEF
1900 _OVERLAPPED_CREATEEVENT_METHODDEF
1901 _OVERLAPPED_SETEVENT_METHODDEF
1902 _OVERLAPPED_RESETEVENT_METHODDEF
1903 _OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
1904 _OVERLAPPED_WSACONNECT_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001905 {NULL}
1906};
1907
1908static struct PyModuleDef overlapped_module = {
1909 PyModuleDef_HEAD_INIT,
1910 "_overlapped",
1911 NULL,
1912 -1,
1913 overlapped_functions,
1914 NULL,
1915 NULL,
1916 NULL,
1917 NULL
1918};
1919
1920#define WINAPI_CONSTANT(fmt, con) \
1921 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1922
1923PyMODINIT_FUNC
1924PyInit__overlapped(void)
1925{
1926 PyObject *m, *d;
1927
1928 /* Ensure WSAStartup() called before initializing function pointers */
1929 m = PyImport_ImportModule("_socket");
1930 if (!m)
1931 return NULL;
1932 Py_DECREF(m);
1933
1934 if (initialize_function_pointers() < 0)
1935 return NULL;
1936
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001937 m = PyModule_Create(&overlapped_module);
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001938 if (PyModule_AddType(m, &OverlappedType) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001939 return NULL;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001940 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001941
1942 d = PyModule_GetDict(m);
1943
1944 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1945 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001946 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001947 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001948 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001949 WINAPI_CONSTANT(F_DWORD, INFINITE);
1950 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1951 WINAPI_CONSTANT(F_HANDLE, NULL);
1952 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1953 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1954 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1955
1956 return m;
1957}