blob: 5e7a1bbba76787c97fe20fd6bf6cc898b8a5ea3f [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
Zackery Spytzaf4eda42020-07-15 12:43:00 -0600296PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
Guido van Rossum90fb9142013-10-30 14:44:05 -0700297{
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(
Zackery Spytzaf4eda42020-07-15 12:43:00 -0600338 &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
Guido van Rossum90fb9142013-10-30 14:44:05 -0700339 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
340 {
Victor Stinner6150f312016-03-16 23:25:02 +0100341 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700342 return SetFromWindowsErr(0);
343 }
344
345 return Py_BuildValue(F_HANDLE, NewWaitObject);
346}
347
Zackery Spytz9650fe02020-07-10 11:43:37 -0600348/*[clinic input]
349_overlapped.UnregisterWait
350
351 WaitHandle: HANDLE
352 /
353
354Unregister wait handle.
355[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700356
357static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600358_overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
359/*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700360{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700361 BOOL ret;
362
Guido van Rossum90fb9142013-10-30 14:44:05 -0700363 Py_BEGIN_ALLOW_THREADS
364 ret = UnregisterWait(WaitHandle);
365 Py_END_ALLOW_THREADS
366
367 if (!ret)
368 return SetFromWindowsErr(0);
369 Py_RETURN_NONE;
370}
371
Zackery Spytz9650fe02020-07-10 11:43:37 -0600372/*[clinic input]
373_overlapped.UnregisterWaitEx
374
375 WaitHandle: HANDLE
376 Event: HANDLE
377 /
378
379Unregister wait handle.
380[clinic start generated code]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100381
382static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600383_overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
384 HANDLE Event)
385/*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100386{
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100387 BOOL ret;
388
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100389 Py_BEGIN_ALLOW_THREADS
390 ret = UnregisterWaitEx(WaitHandle, Event);
391 Py_END_ALLOW_THREADS
392
393 if (!ret)
394 return SetFromWindowsErr(0);
395 Py_RETURN_NONE;
396}
397
Guido van Rossum90fb9142013-10-30 14:44:05 -0700398/*
399 * Event functions -- currently only used by tests
400 */
401
Zackery Spytz9650fe02020-07-10 11:43:37 -0600402/*[clinic input]
403_overlapped.CreateEvent
404
405 EventAttributes: object
406 ManualReset: BOOL
407 InitialState: BOOL
408 Name: Py_UNICODE(accept={str, NoneType})
409 /
410
411Create an event.
412
413EventAttributes must be None.
414[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700415
416static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600417_overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
418 BOOL ManualReset, BOOL InitialState,
419 const Py_UNICODE *Name)
420/*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700421{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700422 HANDLE Event;
423
Guido van Rossum90fb9142013-10-30 14:44:05 -0700424 if (EventAttributes != Py_None) {
425 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
426 return NULL;
427 }
428
429 Py_BEGIN_ALLOW_THREADS
430 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
431 Py_END_ALLOW_THREADS
432
433 if (Event == NULL)
434 return SetFromWindowsErr(0);
435 return Py_BuildValue(F_HANDLE, Event);
436}
437
Zackery Spytz9650fe02020-07-10 11:43:37 -0600438/*[clinic input]
439_overlapped.SetEvent
440
441 Handle: HANDLE
442 /
443
444Set event.
445[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700446
447static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600448_overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
449/*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700450{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700451 BOOL ret;
452
Guido van Rossum90fb9142013-10-30 14:44:05 -0700453 Py_BEGIN_ALLOW_THREADS
454 ret = SetEvent(Handle);
455 Py_END_ALLOW_THREADS
456
457 if (!ret)
458 return SetFromWindowsErr(0);
459 Py_RETURN_NONE;
460}
461
Zackery Spytz9650fe02020-07-10 11:43:37 -0600462/*[clinic input]
463_overlapped.ResetEvent
464
465 Handle: HANDLE
466 /
467
468Reset event.
469[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700470
471static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600472_overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
473/*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700474{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700475 BOOL ret;
476
Guido van Rossum90fb9142013-10-30 14:44:05 -0700477 Py_BEGIN_ALLOW_THREADS
478 ret = ResetEvent(Handle);
479 Py_END_ALLOW_THREADS
480
481 if (!ret)
482 return SetFromWindowsErr(0);
483 Py_RETURN_NONE;
484}
485
486/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700487 * Bind socket handle to local port without doing slow getaddrinfo()
488 */
489
Zackery Spytz9650fe02020-07-10 11:43:37 -0600490/*[clinic input]
491_overlapped.BindLocal
492
493 handle as Socket: HANDLE
494 family as Family: int
495 /
496
497Bind a socket handle to an arbitrary local port.
498
499family should be AF_INET or AF_INET6.
500[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700501
502static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600503_overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
504/*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700505{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700506 BOOL ret;
507
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700508 if (Family == AF_INET) {
509 struct sockaddr_in addr;
510 memset(&addr, 0, sizeof(addr));
511 addr.sin_family = AF_INET;
512 addr.sin_port = 0;
513 addr.sin_addr.S_un.S_addr = INADDR_ANY;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600514 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
515 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700516 } else if (Family == AF_INET6) {
517 struct sockaddr_in6 addr;
518 memset(&addr, 0, sizeof(addr));
519 addr.sin6_family = AF_INET6;
520 addr.sin6_port = 0;
521 addr.sin6_addr = in6addr_any;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600522 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
523 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700524 } else {
525 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
526 return NULL;
527 }
528
529 if (!ret)
530 return SetFromWindowsErr(WSAGetLastError());
531 Py_RETURN_NONE;
532}
533
534/*
535 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
536 */
537
Zackery Spytz9650fe02020-07-10 11:43:37 -0600538/*[clinic input]
539_overlapped.FormatMessage
540
541 error_code as code: DWORD
542 /
543
544Return error message for an error code.
545[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700546
547static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600548_overlapped_FormatMessage_impl(PyObject *module, DWORD code)
549/*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700550{
Zackery Spytz9650fe02020-07-10 11:43:37 -0600551 DWORD n;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700552 WCHAR *lpMsgBuf;
553 PyObject *res;
554
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700555 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600556 FORMAT_MESSAGE_FROM_SYSTEM |
557 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700558 NULL,
559 code,
560 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
561 (LPWSTR) &lpMsgBuf,
562 0,
563 NULL);
564 if (n) {
565 while (iswspace(lpMsgBuf[n-1]))
566 --n;
567 lpMsgBuf[n] = L'\0';
568 res = Py_BuildValue("u", lpMsgBuf);
569 } else {
570 res = PyUnicode_FromFormat("unknown error code %u", code);
571 }
572 LocalFree(lpMsgBuf);
573 return res;
574}
575
576
577/*
578 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
579 */
580
581static void
582mark_as_completed(OVERLAPPED *ov)
583{
584 ov->Internal = 0;
585 if (ov->hEvent != NULL)
586 SetEvent(ov->hEvent);
587}
588
589/*
590 * A Python object wrapping an OVERLAPPED structure and other useful data
591 * for overlapped I/O
592 */
593
Zackery Spytz9650fe02020-07-10 11:43:37 -0600594/*[clinic input]
595@classmethod
596_overlapped.Overlapped.__new__
597
598 event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
599
600OVERLAPPED structure wrapper.
601[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700602
603static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600604_overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
605/*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700606{
607 OverlappedObject *self;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700608
609 if (event == INVALID_HANDLE_VALUE) {
610 event = CreateEvent(NULL, TRUE, FALSE, NULL);
611 if (event == NULL)
612 return SetFromWindowsErr(0);
613 }
614
615 self = PyObject_New(OverlappedObject, type);
616 if (self == NULL) {
617 if (event != NULL)
618 CloseHandle(event);
619 return NULL;
620 }
621
622 self->handle = NULL;
623 self->error = 0;
624 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200625 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700626 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200627 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700628 if (event)
629 self->overlapped.hEvent = event;
630 return (PyObject *)self;
631}
632
Victor Stinner54850852019-01-11 14:35:14 +0100633
634/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
635 buffers while overlapped are still running, to prevent a crash. */
636static int
637Overlapped_clear(OverlappedObject *self)
638{
639 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300640 case TYPE_READ:
641 case TYPE_ACCEPT: {
642 Py_CLEAR(self->allocated_buffer);
643 break;
Victor Stinner54850852019-01-11 14:35:14 +0100644 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300645 case TYPE_READ_FROM: {
646 // An initial call to WSARecvFrom will only allocate the buffer.
647 // The result tuple of (message, address) is only
648 // allocated _after_ a message has been received.
649 if(self->read_from.result) {
650 // We've received a message, free the result tuple.
651 Py_CLEAR(self->read_from.result);
652 }
653 if(self->read_from.allocated_buffer) {
654 Py_CLEAR(self->read_from.allocated_buffer);
655 }
656 break;
657 }
658 case TYPE_WRITE:
659 case TYPE_WRITE_TO:
660 case TYPE_READINTO: {
661 if (self->user_buffer.obj) {
662 PyBuffer_Release(&self->user_buffer);
663 }
664 break;
665 }
Victor Stinner54850852019-01-11 14:35:14 +0100666 }
667 self->type = TYPE_NOT_STARTED;
668 return 0;
669}
670
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700671static void
672Overlapped_dealloc(OverlappedObject *self)
673{
674 DWORD bytes;
675 DWORD olderr = GetLastError();
676 BOOL wait = FALSE;
677 BOOL ret;
678
679 if (!HasOverlappedIoCompleted(&self->overlapped) &&
680 self->type != TYPE_NOT_STARTED)
681 {
682 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
683 wait = TRUE;
684
685 Py_BEGIN_ALLOW_THREADS
686 ret = GetOverlappedResult(self->handle, &self->overlapped,
687 &bytes, wait);
688 Py_END_ALLOW_THREADS
689
690 switch (ret ? ERROR_SUCCESS : GetLastError()) {
691 case ERROR_SUCCESS:
692 case ERROR_NOT_FOUND:
693 case ERROR_OPERATION_ABORTED:
694 break;
695 default:
696 PyErr_Format(
697 PyExc_RuntimeError,
698 "%R still has pending operation at "
699 "deallocation, the process may crash", self);
700 PyErr_WriteUnraisable(NULL);
701 }
702 }
703
Victor Stinner54850852019-01-11 14:35:14 +0100704 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700705 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700706 }
Victor Stinner54850852019-01-11 14:35:14 +0100707
708 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700709 PyObject_Del(self);
710 SetLastError(olderr);
711}
712
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300713
714/* Convert IPv4 sockaddr to a Python str. */
715
716static PyObject *
717make_ipv4_addr(const struct sockaddr_in *addr)
718{
719 char buf[INET_ADDRSTRLEN];
720 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
721 PyErr_SetFromErrno(PyExc_OSError);
722 return NULL;
723 }
724 return PyUnicode_FromString(buf);
725}
726
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300727/* Convert IPv6 sockaddr to a Python str. */
728
729static PyObject *
730make_ipv6_addr(const struct sockaddr_in6 *addr)
731{
732 char buf[INET6_ADDRSTRLEN];
733 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
734 PyErr_SetFromErrno(PyExc_OSError);
735 return NULL;
736 }
737 return PyUnicode_FromString(buf);
738}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300739
740static PyObject*
741unparse_address(LPSOCKADDR Address, DWORD Length)
742{
743 /* The function is adopted from mocketmodule.c makesockaddr()*/
744
745 switch(Address->sa_family) {
746 case AF_INET: {
747 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
748 PyObject *addrobj = make_ipv4_addr(a);
749 PyObject *ret = NULL;
750 if (addrobj) {
751 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
752 Py_DECREF(addrobj);
753 }
754 return ret;
755 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300756 case AF_INET6: {
757 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
758 PyObject *addrobj = make_ipv6_addr(a);
759 PyObject *ret = NULL;
760 if (addrobj) {
761 ret = Py_BuildValue("OiII",
762 addrobj,
763 ntohs(a->sin6_port),
764 ntohl(a->sin6_flowinfo),
765 a->sin6_scope_id);
766 Py_DECREF(addrobj);
767 }
768 return ret;
769 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300770 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200771 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
772 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300773 }
774 }
775}
776
Zackery Spytz9650fe02020-07-10 11:43:37 -0600777/*[clinic input]
778_overlapped.Overlapped.cancel
779
780Cancel overlapped operation.
781[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700782
783static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600784_overlapped_Overlapped_cancel_impl(OverlappedObject *self)
785/*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700786{
787 BOOL ret = TRUE;
788
789 if (self->type == TYPE_NOT_STARTED
790 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
791 Py_RETURN_NONE;
792
793 if (!HasOverlappedIoCompleted(&self->overlapped)) {
794 Py_BEGIN_ALLOW_THREADS
795 if (Py_CancelIoEx)
796 ret = Py_CancelIoEx(self->handle, &self->overlapped);
797 else
798 ret = CancelIo(self->handle);
799 Py_END_ALLOW_THREADS
800 }
801
802 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
803 if (!ret && GetLastError() != ERROR_NOT_FOUND)
804 return SetFromWindowsErr(0);
805 Py_RETURN_NONE;
806}
807
Zackery Spytz9650fe02020-07-10 11:43:37 -0600808/*[clinic input]
809_overlapped.Overlapped.getresult
810
811 wait: BOOL(c_default='FALSE') = False
812 /
813
814Retrieve result of operation.
815
816If wait is true then it blocks until the operation is finished. If wait
817is false and the operation is still pending then an error is raised.
818[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700819
820static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600821_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
822/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700823{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700824 DWORD transferred = 0;
825 BOOL ret;
826 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300827 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700828
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700829 if (self->type == TYPE_NONE) {
830 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
831 return NULL;
832 }
833
834 if (self->type == TYPE_NOT_STARTED) {
835 PyErr_SetString(PyExc_ValueError, "operation failed to start");
836 return NULL;
837 }
838
839 Py_BEGIN_ALLOW_THREADS
840 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
841 wait);
842 Py_END_ALLOW_THREADS
843
844 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
845 switch (err) {
846 case ERROR_SUCCESS:
847 case ERROR_MORE_DATA:
848 break;
849 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300850 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700851 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300852 }
853 else if (self->type == TYPE_READ_FROM &&
854 (self->read_from.result != NULL ||
855 self->read_from.allocated_buffer != NULL))
856 {
857 break;
858 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700859 /* fall through */
860 default:
861 return SetFromWindowsErr(err);
862 }
863
864 switch (self->type) {
865 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200866 assert(PyBytes_CheckExact(self->allocated_buffer));
867 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
868 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700869 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300870
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200871 Py_INCREF(self->allocated_buffer);
872 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300873 case TYPE_READ_FROM:
874 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
875
876 if (transferred != PyBytes_GET_SIZE(
877 self->read_from.allocated_buffer) &&
878 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
879 {
880 return NULL;
881 }
882
883 // unparse the address
884 addr = unparse_address((SOCKADDR*)&self->read_from.address,
885 self->read_from.address_length);
886
887 if (addr == NULL) {
888 return NULL;
889 }
890
891 // The result is a two item tuple: (message, address)
892 self->read_from.result = PyTuple_New(2);
893 if (self->read_from.result == NULL) {
894 Py_CLEAR(addr);
895 return NULL;
896 }
897
898 // first item: message
899 Py_INCREF(self->read_from.allocated_buffer);
900 PyTuple_SET_ITEM(self->read_from.result, 0,
901 self->read_from.allocated_buffer);
902 // second item: address
903 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
904
905 Py_INCREF(self->read_from.result);
906 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700907 default:
908 return PyLong_FromUnsignedLong((unsigned long) transferred);
909 }
910}
911
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200912static PyObject *
913do_ReadFile(OverlappedObject *self, HANDLE handle,
914 char *bufstart, DWORD buflen)
915{
916 DWORD nread;
917 int ret;
918 DWORD err;
919
920 Py_BEGIN_ALLOW_THREADS
921 ret = ReadFile(handle, bufstart, buflen, &nread,
922 &self->overlapped);
923 Py_END_ALLOW_THREADS
924
925 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
926 switch (err) {
927 case ERROR_BROKEN_PIPE:
928 mark_as_completed(&self->overlapped);
929 return SetFromWindowsErr(err);
930 case ERROR_SUCCESS:
931 case ERROR_MORE_DATA:
932 case ERROR_IO_PENDING:
933 Py_RETURN_NONE;
934 default:
Victor Stinner54850852019-01-11 14:35:14 +0100935 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200936 return SetFromWindowsErr(err);
937 }
938}
939
Zackery Spytz9650fe02020-07-10 11:43:37 -0600940/*[clinic input]
941_overlapped.Overlapped.ReadFile
942
943 handle: HANDLE
944 size: DWORD
945 /
946
947Start overlapped read.
948[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700949
950static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600951_overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
952 DWORD size)
953/*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700954{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700955 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700956
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700957 if (self->type != TYPE_NONE) {
958 PyErr_SetString(PyExc_ValueError, "operation already attempted");
959 return NULL;
960 }
961
962#if SIZEOF_SIZE_T <= SIZEOF_LONG
963 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
964#endif
965 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
966 if (buf == NULL)
967 return NULL;
968
969 self->type = TYPE_READ;
970 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200971 self->allocated_buffer = buf;
972
973 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
974}
975
Zackery Spytz9650fe02020-07-10 11:43:37 -0600976/*[clinic input]
977_overlapped.Overlapped.ReadFileInto
978
979 handle: HANDLE
980 buf as bufobj: object
981 /
982
983Start overlapped receive.
984[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200985
986static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600987_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
988 HANDLE handle, PyObject *bufobj)
989/*[clinic end generated code: output=1e9e712e742e5b2a input=16f6cc268d1d0387]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200990{
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200991 if (self->type != TYPE_NONE) {
992 PyErr_SetString(PyExc_ValueError, "operation already attempted");
993 return NULL;
994 }
995
996 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
997 return NULL;
998
999#if SIZEOF_SIZE_T > SIZEOF_LONG
1000 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1001 PyBuffer_Release(&self->user_buffer);
1002 PyErr_SetString(PyExc_ValueError, "buffer too large");
1003 return NULL;
1004 }
1005#endif
1006
1007 self->type = TYPE_READINTO;
1008 self->handle = handle;
1009
1010 return do_ReadFile(self, handle, self->user_buffer.buf,
1011 (DWORD)self->user_buffer.len);
1012}
1013
1014static PyObject *
1015do_WSARecv(OverlappedObject *self, HANDLE handle,
1016 char *bufstart, DWORD buflen, DWORD flags)
1017{
1018 DWORD nread;
1019 WSABUF wsabuf;
1020 int ret;
1021 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +03001022
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001023 wsabuf.buf = bufstart;
1024 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001025
1026 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001027 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1028 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001029 Py_END_ALLOW_THREADS
1030
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001031 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001032 switch (err) {
1033 case ERROR_BROKEN_PIPE:
1034 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +01001035 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001036 case ERROR_SUCCESS:
1037 case ERROR_MORE_DATA:
1038 case ERROR_IO_PENDING:
1039 Py_RETURN_NONE;
1040 default:
Victor Stinner54850852019-01-11 14:35:14 +01001041 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001042 return SetFromWindowsErr(err);
1043 }
1044}
1045
Zackery Spytz9650fe02020-07-10 11:43:37 -06001046/*[clinic input]
1047_overlapped.Overlapped.WSARecv
1048
1049 handle: HANDLE
1050 size: DWORD
1051 flags: DWORD = 0
1052 /
1053
1054Start overlapped receive.
1055[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001056
1057static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001058_overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
1059 DWORD size, DWORD flags)
1060/*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001061{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001062 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001063
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001064 if (self->type != TYPE_NONE) {
1065 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1066 return NULL;
1067 }
1068
1069#if SIZEOF_SIZE_T <= SIZEOF_LONG
1070 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1071#endif
1072 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1073 if (buf == NULL)
1074 return NULL;
1075
1076 self->type = TYPE_READ;
1077 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001078 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001079
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001080 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1081}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001082
Zackery Spytz9650fe02020-07-10 11:43:37 -06001083/*[clinic input]
1084_overlapped.Overlapped.WSARecvInto
1085
1086 handle: HANDLE
1087 buf as bufobj: object
1088 flags: DWORD
1089 /
1090
1091Start overlapped receive.
1092[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001093
1094static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001095_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
1096 HANDLE handle, PyObject *bufobj,
1097 DWORD flags)
1098/*[clinic end generated code: output=9a438abc436fe87c input=4f87c38fc381d525]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001099{
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001100 if (self->type != TYPE_NONE) {
1101 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1102 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001103 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001104
1105 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1106 return NULL;
1107
1108#if SIZEOF_SIZE_T > SIZEOF_LONG
1109 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1110 PyBuffer_Release(&self->user_buffer);
1111 PyErr_SetString(PyExc_ValueError, "buffer too large");
1112 return NULL;
1113 }
1114#endif
1115
1116 self->type = TYPE_READINTO;
1117 self->handle = handle;
1118
1119 return do_WSARecv(self, handle, self->user_buffer.buf,
1120 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001121}
1122
Zackery Spytz9650fe02020-07-10 11:43:37 -06001123/*[clinic input]
1124_overlapped.Overlapped.WriteFile
1125
1126 handle: HANDLE
1127 buf as bufobj: object
1128 /
1129
1130Start overlapped write.
1131[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001132
1133static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001134_overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
1135 PyObject *bufobj)
1136/*[clinic end generated code: output=c376230b6120d877 input=b8d9a7608d8a1e72]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001137{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001138 DWORD written;
1139 BOOL ret;
1140 DWORD err;
1141
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001142 if (self->type != TYPE_NONE) {
1143 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1144 return NULL;
1145 }
1146
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001147 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001148 return NULL;
1149
1150#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001151 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1152 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001153 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001154 return NULL;
1155 }
1156#endif
1157
1158 self->type = TYPE_WRITE;
1159 self->handle = handle;
1160
1161 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001162 ret = WriteFile(handle, self->user_buffer.buf,
1163 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001164 &written, &self->overlapped);
1165 Py_END_ALLOW_THREADS
1166
1167 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1168 switch (err) {
1169 case ERROR_SUCCESS:
1170 case ERROR_IO_PENDING:
1171 Py_RETURN_NONE;
1172 default:
Victor Stinner54850852019-01-11 14:35:14 +01001173 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001174 return SetFromWindowsErr(err);
1175 }
1176}
1177
Zackery Spytz9650fe02020-07-10 11:43:37 -06001178/*[clinic input]
1179_overlapped.Overlapped.WSASend
1180
1181 handle: HANDLE
1182 buf as bufobj: object
1183 flags: DWORD
1184 /
1185
1186Start overlapped send.
1187[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001188
1189static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001190_overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
1191 PyObject *bufobj, DWORD flags)
1192/*[clinic end generated code: output=316031c7467040cc input=932e7cba6d18f708]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001193{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001194 DWORD written;
1195 WSABUF wsabuf;
1196 int ret;
1197 DWORD err;
1198
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001199 if (self->type != TYPE_NONE) {
1200 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1201 return NULL;
1202 }
1203
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001204 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001205 return NULL;
1206
1207#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001208 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1209 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001210 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001211 return NULL;
1212 }
1213#endif
1214
1215 self->type = TYPE_WRITE;
1216 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001217 wsabuf.len = (DWORD)self->user_buffer.len;
1218 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001219
1220 Py_BEGIN_ALLOW_THREADS
1221 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1222 &self->overlapped, NULL);
1223 Py_END_ALLOW_THREADS
1224
1225 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1226 switch (err) {
1227 case ERROR_SUCCESS:
1228 case ERROR_IO_PENDING:
1229 Py_RETURN_NONE;
1230 default:
Victor Stinner54850852019-01-11 14:35:14 +01001231 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001232 return SetFromWindowsErr(err);
1233 }
1234}
1235
Zackery Spytz9650fe02020-07-10 11:43:37 -06001236/*[clinic input]
1237_overlapped.Overlapped.AcceptEx
1238
1239 listen_handle as ListenSocket: HANDLE
1240 accept_handle as AcceptSocket: HANDLE
1241 /
1242
1243Start overlapped wait for client to connect.
1244[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001245
1246static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001247_overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
1248 HANDLE ListenSocket,
1249 HANDLE AcceptSocket)
1250/*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001251{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001252 DWORD BytesReceived;
1253 DWORD size;
1254 PyObject *buf;
1255 BOOL ret;
1256 DWORD err;
1257
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001258 if (self->type != TYPE_NONE) {
1259 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1260 return NULL;
1261 }
1262
1263 size = sizeof(struct sockaddr_in6) + 16;
1264 buf = PyBytes_FromStringAndSize(NULL, size*2);
1265 if (!buf)
1266 return NULL;
1267
1268 self->type = TYPE_ACCEPT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001269 self->handle = ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001270 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001271
1272 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001273 ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
1274 PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
1275 &self->overlapped);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001276 Py_END_ALLOW_THREADS
1277
1278 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1279 switch (err) {
1280 case ERROR_SUCCESS:
1281 case ERROR_IO_PENDING:
1282 Py_RETURN_NONE;
1283 default:
Victor Stinner54850852019-01-11 14:35:14 +01001284 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001285 return SetFromWindowsErr(err);
1286 }
1287}
1288
1289
1290static int
1291parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1292{
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001293 PyObject *Host_obj;
Steve Dowercc16be82016-09-08 10:35:16 -07001294 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001295 unsigned short Port;
1296 unsigned long FlowInfo;
1297 unsigned long ScopeId;
1298
1299 memset(Address, 0, Length);
1300
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001301 switch (PyTuple_GET_SIZE(obj)) {
1302 case 2: {
1303 if (!PyArg_ParseTuple(obj, "UH", &Host_obj, &Port)) {
1304 return -1;
1305 }
1306#if USE_UNICODE_WCHAR_CACHE
1307 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1308#else /* USE_UNICODE_WCHAR_CACHE */
1309 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1310#endif /* USE_UNICODE_WCHAR_CACHE */
1311 if (Host == NULL) {
1312 return -1;
1313 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001314 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001315 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001316 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001317 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001318 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001319 else {
1320 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1321 }
1322#if !USE_UNICODE_WCHAR_CACHE
1323 PyMem_Free(Host);
1324#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001325 return Length;
1326 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001327 case 4: {
1328 if (!PyArg_ParseTuple(obj,
1329 "UHkk;ConnectEx(): illegal address_as_bytes argument",
1330 &Host_obj, &Port, &FlowInfo, &ScopeId))
1331 {
1332 return -1;
1333 }
1334#if USE_UNICODE_WCHAR_CACHE
1335 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1336#else /* USE_UNICODE_WCHAR_CACHE */
1337 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1338#endif /* USE_UNICODE_WCHAR_CACHE */
1339 if (Host == NULL) {
1340 return -1;
1341 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001342 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001343 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001344 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001345 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001346 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001347 else {
1348 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1349 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1350 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1351 }
1352#if !USE_UNICODE_WCHAR_CACHE
1353 PyMem_Free(Host);
1354#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001355 return Length;
1356 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001357 default:
1358 PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument");
1359 return -1;
1360 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001361}
1362
Zackery Spytz9650fe02020-07-10 11:43:37 -06001363/*[clinic input]
1364_overlapped.Overlapped.ConnectEx
1365
1366 client_handle as ConnectSocket: HANDLE
1367 address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1368 /
1369
1370Start overlapped connect.
1371
1372client_handle should be unbound.
1373[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001374
1375static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001376_overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
1377 HANDLE ConnectSocket,
1378 PyObject *AddressObj)
1379/*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001380{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001381 char AddressBuf[sizeof(struct sockaddr_in6)];
1382 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1383 int Length;
1384 BOOL ret;
1385 DWORD err;
1386
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001387 if (self->type != TYPE_NONE) {
1388 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1389 return NULL;
1390 }
1391
1392 Length = sizeof(AddressBuf);
1393 Length = parse_address(AddressObj, Address, Length);
1394 if (Length < 0)
1395 return NULL;
1396
1397 self->type = TYPE_CONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001398 self->handle = ConnectSocket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001399
1400 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001401 ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001402 NULL, 0, NULL, &self->overlapped);
1403 Py_END_ALLOW_THREADS
1404
1405 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1406 switch (err) {
1407 case ERROR_SUCCESS:
1408 case ERROR_IO_PENDING:
1409 Py_RETURN_NONE;
1410 default:
Victor Stinner54850852019-01-11 14:35:14 +01001411 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001412 return SetFromWindowsErr(err);
1413 }
1414}
1415
Zackery Spytz9650fe02020-07-10 11:43:37 -06001416/*[clinic input]
1417_overlapped.Overlapped.DisconnectEx
1418
1419 handle as Socket: HANDLE
1420 flags: DWORD
1421 /
1422
1423[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001424
1425static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001426_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
1427 HANDLE Socket, DWORD flags)
1428/*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001429{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001430 BOOL ret;
1431 DWORD err;
1432
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001433 if (self->type != TYPE_NONE) {
1434 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1435 return NULL;
1436 }
1437
1438 self->type = TYPE_DISCONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001439 self->handle = Socket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001440
1441 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001442 ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001443 Py_END_ALLOW_THREADS
1444
1445 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1446 switch (err) {
1447 case ERROR_SUCCESS:
1448 case ERROR_IO_PENDING:
1449 Py_RETURN_NONE;
1450 default:
Victor Stinner54850852019-01-11 14:35:14 +01001451 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001452 return SetFromWindowsErr(err);
1453 }
1454}
1455
Zackery Spytz9650fe02020-07-10 11:43:37 -06001456/*[clinic input]
1457_overlapped.Overlapped.TransmitFile
1458
1459 socket as Socket: HANDLE
1460 file as File: HANDLE
1461 offset: DWORD
1462 offset_high: DWORD
1463 count_to_write: DWORD
1464 count_per_send: DWORD
1465 flags: DWORD
1466 /
1467
1468Transmit file data over a connected socket.
1469[clinic start generated code]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001470
1471static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001472_overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
1473 HANDLE Socket, HANDLE File,
1474 DWORD offset, DWORD offset_high,
1475 DWORD count_to_write,
1476 DWORD count_per_send, DWORD flags)
1477/*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001478{
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001479 BOOL ret;
1480 DWORD err;
1481
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001482 if (self->type != TYPE_NONE) {
1483 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1484 return NULL;
1485 }
1486
1487 self->type = TYPE_TRANSMIT_FILE;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001488 self->handle = Socket;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001489 self->overlapped.Offset = offset;
1490 self->overlapped.OffsetHigh = offset_high;
1491
1492 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001493 ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
1494 count_per_send, &self->overlapped, NULL, flags);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001495 Py_END_ALLOW_THREADS
1496
1497 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1498 switch (err) {
1499 case ERROR_SUCCESS:
1500 case ERROR_IO_PENDING:
1501 Py_RETURN_NONE;
1502 default:
Victor Stinner54850852019-01-11 14:35:14 +01001503 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001504 return SetFromWindowsErr(err);
1505 }
1506}
1507
Zackery Spytz9650fe02020-07-10 11:43:37 -06001508/*[clinic input]
1509_overlapped.Overlapped.ConnectNamedPipe
1510
1511 handle as Pipe: HANDLE
1512 /
1513
1514Start overlapped wait for a client to connect.
1515[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001516
1517static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001518_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
1519 HANDLE Pipe)
1520/*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001521{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001522 BOOL ret;
1523 DWORD err;
1524
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001525 if (self->type != TYPE_NONE) {
1526 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1527 return NULL;
1528 }
1529
1530 self->type = TYPE_CONNECT_NAMED_PIPE;
1531 self->handle = Pipe;
1532
1533 Py_BEGIN_ALLOW_THREADS
1534 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1535 Py_END_ALLOW_THREADS
1536
1537 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1538 switch (err) {
1539 case ERROR_PIPE_CONNECTED:
1540 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001541 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001542 case ERROR_SUCCESS:
1543 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001544 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001545 default:
Victor Stinner54850852019-01-11 14:35:14 +01001546 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001547 return SetFromWindowsErr(err);
1548 }
1549}
1550
Zackery Spytz9650fe02020-07-10 11:43:37 -06001551/*[clinic input]
1552_overlapped.Overlapped.ConnectPipe
1553
1554 addr as Address: Py_UNICODE
1555 /
1556
1557Connect to the pipe for asynchronous I/O (overlapped).
1558[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001559
1560static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001561_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
1562 const Py_UNICODE *Address)
1563/*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001564{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001565 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001566
Victor Stinner498b1f62015-01-26 22:43:39 +01001567 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001568 PipeHandle = CreateFileW(Address,
1569 GENERIC_READ | GENERIC_WRITE,
1570 0, NULL, OPEN_EXISTING,
1571 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001572 Py_END_ALLOW_THREADS
1573
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001574 if (PipeHandle == INVALID_HANDLE_VALUE)
1575 return SetFromWindowsErr(0);
1576 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001577}
1578
1579static PyObject*
1580Overlapped_getaddress(OverlappedObject *self)
1581{
1582 return PyLong_FromVoidPtr(&self->overlapped);
1583}
1584
1585static PyObject*
1586Overlapped_getpending(OverlappedObject *self)
1587{
1588 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1589 self->type != TYPE_NOT_STARTED);
1590}
1591
Victor Stinner54850852019-01-11 14:35:14 +01001592static int
1593Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1594{
1595 switch (self->type) {
1596 case TYPE_READ:
1597 case TYPE_ACCEPT:
1598 Py_VISIT(self->allocated_buffer);
1599 break;
1600 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001601 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001602 case TYPE_READINTO:
1603 if (self->user_buffer.obj) {
1604 Py_VISIT(&self->user_buffer.obj);
1605 }
1606 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001607 case TYPE_READ_FROM:
Hai Shi47a23fc2020-06-07 20:05:36 +08001608 Py_VISIT(self->read_from.result);
1609 Py_VISIT(self->read_from.allocated_buffer);
Victor Stinner54850852019-01-11 14:35:14 +01001610 }
1611 return 0;
1612}
1613
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001614// UDP functions
1615
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001616/*
1617 * Note: WSAConnect does not support Overlapped I/O so this function should
1618 * _only_ be used for connectionless sockets (UDP).
1619 */
Zackery Spytz9650fe02020-07-10 11:43:37 -06001620
1621/*[clinic input]
1622_overlapped.WSAConnect
1623
1624 client_handle as ConnectSocket: HANDLE
1625 address_as_bytes as AddressObj: object
1626 /
1627
1628Bind a remote address to a connectionless (UDP) socket.
1629[clinic start generated code]*/
1630
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001631static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001632_overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
1633 PyObject *AddressObj)
1634/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001635{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001636 char AddressBuf[sizeof(struct sockaddr_in6)];
1637 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1638 int Length;
1639 int err;
1640
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001641 Length = sizeof(AddressBuf);
1642 Length = parse_address(AddressObj, Address, Length);
1643 if (Length < 0) {
1644 return NULL;
1645 }
1646
1647 Py_BEGIN_ALLOW_THREADS
1648 // WSAConnect does not support overlapped I/O so this call will
1649 // successfully complete immediately.
Zackery Spytz9650fe02020-07-10 11:43:37 -06001650 err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001651 NULL, NULL, NULL, NULL);
1652 Py_END_ALLOW_THREADS
1653
1654 if (err == 0) {
1655 Py_RETURN_NONE;
1656 }
1657 else {
1658 return SetFromWindowsErr(WSAGetLastError());
1659 }
1660}
1661
Zackery Spytz9650fe02020-07-10 11:43:37 -06001662/*[clinic input]
1663_overlapped.Overlapped.WSASendTo
1664
1665 handle: HANDLE
1666 buf as bufobj: object
1667 flags: DWORD
1668 address_as_bytes as AddressObj: object
1669 /
1670
1671Start overlapped sendto over a connectionless (UDP) socket.
1672[clinic start generated code]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001673
1674static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001675_overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
1676 PyObject *bufobj, DWORD flags,
1677 PyObject *AddressObj)
1678/*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001679{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001680 char AddressBuf[sizeof(struct sockaddr_in6)];
1681 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1682 int AddressLength;
1683 DWORD written;
1684 WSABUF wsabuf;
1685 int ret;
1686 DWORD err;
1687
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001688 // Parse the "to" address
1689 AddressLength = sizeof(AddressBuf);
1690 AddressLength = parse_address(AddressObj, Address, AddressLength);
1691 if (AddressLength < 0) {
1692 return NULL;
1693 }
1694
1695 if (self->type != TYPE_NONE) {
1696 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1697 return NULL;
1698 }
1699
1700 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1701 return NULL;
1702 }
1703
1704#if SIZEOF_SIZE_T > SIZEOF_LONG
1705 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1706 PyBuffer_Release(&self->user_buffer);
1707 PyErr_SetString(PyExc_ValueError, "buffer too large");
1708 return NULL;
1709 }
1710#endif
1711
1712 self->type = TYPE_WRITE_TO;
1713 self->handle = handle;
1714 wsabuf.len = (DWORD)self->user_buffer.len;
1715 wsabuf.buf = self->user_buffer.buf;
1716
1717 Py_BEGIN_ALLOW_THREADS
1718 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1719 Address, AddressLength, &self->overlapped, NULL);
1720 Py_END_ALLOW_THREADS
1721
1722 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1723 ERROR_SUCCESS);
1724
1725 switch(err) {
1726 case ERROR_SUCCESS:
1727 case ERROR_IO_PENDING:
1728 Py_RETURN_NONE;
1729 default:
1730 self->type = TYPE_NOT_STARTED;
1731 return SetFromWindowsErr(err);
1732 }
1733}
1734
1735
1736
1737PyDoc_STRVAR(
1738 Overlapped_WSARecvFrom_doc,
1739 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1740 "Start overlapped receive");
1741
Zackery Spytz9650fe02020-07-10 11:43:37 -06001742/*[clinic input]
1743_overlapped.Overlapped.WSARecvFrom
1744
1745 handle: HANDLE
1746 size: DWORD
1747 flags: DWORD = 0
1748 /
1749
1750Start overlapped receive.
1751[clinic start generated code]*/
1752
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001753static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001754_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
1755 HANDLE handle, DWORD size,
1756 DWORD flags)
1757/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001758{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001759 DWORD nread;
1760 PyObject *buf;
1761 WSABUF wsabuf;
1762 int ret;
1763 DWORD err;
1764
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001765 if (self->type != TYPE_NONE) {
1766 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1767 return NULL;
1768 }
1769
1770#if SIZEOF_SIZE_T <= SIZEOF_LONG
1771 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1772#endif
1773 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1774 if (buf == NULL) {
1775 return NULL;
1776 }
1777
1778 wsabuf.len = size;
1779 wsabuf.buf = PyBytes_AS_STRING(buf);
1780
1781 self->type = TYPE_READ_FROM;
1782 self->handle = handle;
1783 self->read_from.allocated_buffer = buf;
1784 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1785 self->read_from.address_length = sizeof(self->read_from.address);
1786
1787 Py_BEGIN_ALLOW_THREADS
1788 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1789 (SOCKADDR*)&self->read_from.address,
1790 &self->read_from.address_length,
1791 &self->overlapped, NULL);
1792 Py_END_ALLOW_THREADS
1793
1794 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1795
1796 switch(err) {
1797 case ERROR_BROKEN_PIPE:
1798 mark_as_completed(&self->overlapped);
1799 return SetFromWindowsErr(err);
1800 case ERROR_SUCCESS:
1801 case ERROR_MORE_DATA:
1802 case ERROR_IO_PENDING:
1803 Py_RETURN_NONE;
1804 default:
1805 self->type = TYPE_NOT_STARTED;
1806 return SetFromWindowsErr(err);
1807 }
1808}
1809
Zackery Spytz9650fe02020-07-10 11:43:37 -06001810#include "clinic/overlapped.c.h"
Victor Stinner54850852019-01-11 14:35:14 +01001811
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001812static PyMethodDef Overlapped_methods[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001813 _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
1814 _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
1815 _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
1816 _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
1817 _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
1818 _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
1819 _OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
1820 _OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
1821 _OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
1822 _OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
1823 _OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
1824 _OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
1825 _OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
1826 _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1827 _OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001828 {NULL}
1829};
1830
1831static PyMemberDef Overlapped_members[] = {
1832 {"error", T_ULONG,
1833 offsetof(OverlappedObject, error),
1834 READONLY, "Error from last operation"},
1835 {"event", T_HANDLE,
1836 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1837 READONLY, "Overlapped event handle"},
1838 {NULL}
1839};
1840
1841static PyGetSetDef Overlapped_getsets[] = {
1842 {"address", (getter)Overlapped_getaddress, NULL,
1843 "Address of overlapped structure"},
1844 {"pending", (getter)Overlapped_getpending, NULL,
1845 "Whether the operation is pending"},
1846 {NULL},
1847};
1848
1849PyTypeObject OverlappedType = {
1850 PyVarObject_HEAD_INIT(NULL, 0)
1851 /* tp_name */ "_overlapped.Overlapped",
1852 /* tp_basicsize */ sizeof(OverlappedObject),
1853 /* tp_itemsize */ 0,
1854 /* tp_dealloc */ (destructor) Overlapped_dealloc,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001855 /* tp_vectorcall_offset */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001856 /* tp_getattr */ 0,
1857 /* tp_setattr */ 0,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001858 /* tp_as_async */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001859 /* tp_repr */ 0,
1860 /* tp_as_number */ 0,
1861 /* tp_as_sequence */ 0,
1862 /* tp_as_mapping */ 0,
1863 /* tp_hash */ 0,
1864 /* tp_call */ 0,
1865 /* tp_str */ 0,
1866 /* tp_getattro */ 0,
1867 /* tp_setattro */ 0,
1868 /* tp_as_buffer */ 0,
1869 /* tp_flags */ Py_TPFLAGS_DEFAULT,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001870 /* tp_doc */ _overlapped_Overlapped__doc__,
Victor Stinner54850852019-01-11 14:35:14 +01001871 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001872 /* tp_clear */ 0,
1873 /* tp_richcompare */ 0,
1874 /* tp_weaklistoffset */ 0,
1875 /* tp_iter */ 0,
1876 /* tp_iternext */ 0,
1877 /* tp_methods */ Overlapped_methods,
1878 /* tp_members */ Overlapped_members,
1879 /* tp_getset */ Overlapped_getsets,
1880 /* tp_base */ 0,
1881 /* tp_dict */ 0,
1882 /* tp_descr_get */ 0,
1883 /* tp_descr_set */ 0,
1884 /* tp_dictoffset */ 0,
1885 /* tp_init */ 0,
1886 /* tp_alloc */ 0,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001887 /* tp_new */ _overlapped_Overlapped,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001888};
1889
1890static PyMethodDef overlapped_functions[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001891 _OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
1892 _OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
1893 _OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
1894 _OVERLAPPED_FORMATMESSAGE_METHODDEF
1895 _OVERLAPPED_BINDLOCAL_METHODDEF
1896 _OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
1897 _OVERLAPPED_UNREGISTERWAIT_METHODDEF
1898 _OVERLAPPED_UNREGISTERWAITEX_METHODDEF
1899 _OVERLAPPED_CREATEEVENT_METHODDEF
1900 _OVERLAPPED_SETEVENT_METHODDEF
1901 _OVERLAPPED_RESETEVENT_METHODDEF
1902 _OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
1903 _OVERLAPPED_WSACONNECT_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001904 {NULL}
1905};
1906
1907static struct PyModuleDef overlapped_module = {
1908 PyModuleDef_HEAD_INIT,
1909 "_overlapped",
1910 NULL,
1911 -1,
1912 overlapped_functions,
1913 NULL,
1914 NULL,
1915 NULL,
1916 NULL
1917};
1918
1919#define WINAPI_CONSTANT(fmt, con) \
1920 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1921
1922PyMODINIT_FUNC
1923PyInit__overlapped(void)
1924{
1925 PyObject *m, *d;
1926
1927 /* Ensure WSAStartup() called before initializing function pointers */
1928 m = PyImport_ImportModule("_socket");
1929 if (!m)
1930 return NULL;
1931 Py_DECREF(m);
1932
1933 if (initialize_function_pointers() < 0)
1934 return NULL;
1935
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001936 m = PyModule_Create(&overlapped_module);
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001937 if (PyModule_AddType(m, &OverlappedType) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001938 return NULL;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001939 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001940
1941 d = PyModule_GetDict(m);
1942
1943 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1944 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001945 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001946 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001947 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001948 WINAPI_CONSTANT(F_DWORD, INFINITE);
1949 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1950 WINAPI_CONSTANT(F_HANDLE, NULL);
1951 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1952 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1953 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1954
1955 return m;
1956}