blob: 3829932070a96112823082ea895c55e25d60bc18 [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
Mohamed Koubaa2aabc322020-09-07 08:12:40 -0500103typedef struct {
104 PyTypeObject *overlapped_type;
105} OverlappedState;
106
107static inline OverlappedState*
108overlapped_get_state(PyObject *module)
109{
110 void *state = PyModule_GetState(module);
111 assert(state != NULL);
112 return (OverlappedState *)state;
113}
114
115
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700116/*
117 * Map Windows error codes to subclasses of OSError
118 */
119
120static PyObject *
121SetFromWindowsErr(DWORD err)
122{
123 PyObject *exception_type;
124
125 if (err == 0)
126 err = GetLastError();
127 switch (err) {
128 case ERROR_CONNECTION_REFUSED:
129 exception_type = PyExc_ConnectionRefusedError;
130 break;
131 case ERROR_CONNECTION_ABORTED:
132 exception_type = PyExc_ConnectionAbortedError;
133 break;
134 default:
135 exception_type = PyExc_OSError;
136 }
137 return PyErr_SetExcFromWindowsErr(exception_type, err);
138}
139
140/*
141 * Some functions should be loaded at runtime
142 */
143
144static LPFN_ACCEPTEX Py_AcceptEx = NULL;
145static LPFN_CONNECTEX Py_ConnectEx = NULL;
146static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300147static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700148static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
149
150#define GET_WSA_POINTER(s, x) \
151 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
152 &Guid##x, sizeof(Guid##x), &Py_##x, \
153 sizeof(Py_##x), &dwBytes, NULL, NULL))
154
155static int
156initialize_function_pointers(void)
157{
158 GUID GuidAcceptEx = WSAID_ACCEPTEX;
159 GUID GuidConnectEx = WSAID_CONNECTEX;
160 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300161 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700162 HINSTANCE hKernel32;
163 SOCKET s;
164 DWORD dwBytes;
165
166 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
167 if (s == INVALID_SOCKET) {
168 SetFromWindowsErr(WSAGetLastError());
169 return -1;
170 }
171
172 if (!GET_WSA_POINTER(s, AcceptEx) ||
173 !GET_WSA_POINTER(s, ConnectEx) ||
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300174 !GET_WSA_POINTER(s, DisconnectEx) ||
175 !GET_WSA_POINTER(s, TransmitFile))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700176 {
177 closesocket(s);
178 SetFromWindowsErr(WSAGetLastError());
179 return -1;
180 }
181
182 closesocket(s);
183
184 /* On WinXP we will have Py_CancelIoEx == NULL */
Tony Roberts4860f012019-02-02 18:16:42 +0100185 Py_BEGIN_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700186 hKernel32 = GetModuleHandle("KERNEL32");
187 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Tony Roberts4860f012019-02-02 18:16:42 +0100188 Py_END_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700189 return 0;
190}
191
192/*
193 * Completion port stuff
194 */
195
Zackery Spytz9650fe02020-07-10 11:43:37 -0600196/*[clinic input]
197_overlapped.CreateIoCompletionPort
198
199 handle as FileHandle: HANDLE
200 port as ExistingCompletionPort: HANDLE
201 key as CompletionKey: ULONG_PTR
202 concurrency as NumberOfConcurrentThreads: DWORD
203 /
204
205Create a completion port or register a handle with a port.
206[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700207
208static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600209_overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle,
210 HANDLE ExistingCompletionPort,
211 ULONG_PTR CompletionKey,
212 DWORD NumberOfConcurrentThreads)
213/*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700214{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700215 HANDLE ret;
216
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700217 Py_BEGIN_ALLOW_THREADS
218 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
219 CompletionKey, NumberOfConcurrentThreads);
220 Py_END_ALLOW_THREADS
221
222 if (ret == NULL)
223 return SetFromWindowsErr(0);
224 return Py_BuildValue(F_HANDLE, ret);
225}
226
Zackery Spytz9650fe02020-07-10 11:43:37 -0600227/*[clinic input]
228_overlapped.GetQueuedCompletionStatus
229
230 port as CompletionPort: HANDLE
231 msecs as Milliseconds: DWORD
232 /
233
234Get a message from completion port.
235
236Wait for up to msecs milliseconds.
237[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700238
239static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600240_overlapped_GetQueuedCompletionStatus_impl(PyObject *module,
241 HANDLE CompletionPort,
242 DWORD Milliseconds)
243/*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700244{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700245 DWORD NumberOfBytes = 0;
246 ULONG_PTR CompletionKey = 0;
247 OVERLAPPED *Overlapped = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700248 DWORD err;
249 BOOL ret;
250
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700251 Py_BEGIN_ALLOW_THREADS
252 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
253 &CompletionKey, &Overlapped, Milliseconds);
254 Py_END_ALLOW_THREADS
255
256 err = ret ? ERROR_SUCCESS : GetLastError();
257 if (Overlapped == NULL) {
258 if (err == WAIT_TIMEOUT)
259 Py_RETURN_NONE;
260 else
261 return SetFromWindowsErr(err);
262 }
263 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
264 err, NumberOfBytes, CompletionKey, Overlapped);
265}
266
Zackery Spytz9650fe02020-07-10 11:43:37 -0600267/*[clinic input]
268_overlapped.PostQueuedCompletionStatus
269
270 port as CompletionPort: HANDLE
271 bytes as NumberOfBytes: DWORD
272 key as CompletionKey: ULONG_PTR
273 address as Overlapped: OVERLAPPED
274 /
275
276Post a message to completion port.
277[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700278
279static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600280_overlapped_PostQueuedCompletionStatus_impl(PyObject *module,
281 HANDLE CompletionPort,
282 DWORD NumberOfBytes,
283 ULONG_PTR CompletionKey,
284 OVERLAPPED *Overlapped)
285/*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700286{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700287 BOOL ret;
288
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700289 Py_BEGIN_ALLOW_THREADS
290 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
291 CompletionKey, Overlapped);
292 Py_END_ALLOW_THREADS
293
294 if (!ret)
295 return SetFromWindowsErr(0);
296 Py_RETURN_NONE;
297}
298
299/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700300 * Wait for a handle
301 */
302
303struct PostCallbackData {
304 HANDLE CompletionPort;
305 LPOVERLAPPED Overlapped;
306};
307
308static VOID CALLBACK
Zackery Spytzaf4eda42020-07-15 12:43:00 -0600309PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
Guido van Rossum90fb9142013-10-30 14:44:05 -0700310{
311 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
312
313 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
314 0, p->Overlapped);
315 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100316 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700317}
318
Zackery Spytz9650fe02020-07-10 11:43:37 -0600319/*[clinic input]
320_overlapped.RegisterWaitWithQueue
321
322 Object: HANDLE
323 CompletionPort: HANDLE
324 Overlapped: OVERLAPPED
325 Timeout as Milliseconds: DWORD
326 /
327
328Register wait for Object; when complete CompletionPort is notified.
329[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700330
331static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600332_overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
333 HANDLE CompletionPort,
334 OVERLAPPED *Overlapped,
335 DWORD Milliseconds)
336/*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700337{
338 HANDLE NewWaitObject;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600339 struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata;
Guido van Rossum90fb9142013-10-30 14:44:05 -0700340
Victor Stinner6150f312016-03-16 23:25:02 +0100341 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
342 PostToQueueCallback() will call PyMem_Free() from a new C thread
343 which doesn't hold the GIL. */
344 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700345 if (pdata == NULL)
346 return SetFromWindowsErr(0);
347
348 *pdata = data;
349
350 if (!RegisterWaitForSingleObject(
Zackery Spytzaf4eda42020-07-15 12:43:00 -0600351 &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
Guido van Rossum90fb9142013-10-30 14:44:05 -0700352 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
353 {
Victor Stinner6150f312016-03-16 23:25:02 +0100354 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700355 return SetFromWindowsErr(0);
356 }
357
358 return Py_BuildValue(F_HANDLE, NewWaitObject);
359}
360
Zackery Spytz9650fe02020-07-10 11:43:37 -0600361/*[clinic input]
362_overlapped.UnregisterWait
363
364 WaitHandle: HANDLE
365 /
366
367Unregister wait handle.
368[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700369
370static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600371_overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
372/*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700373{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700374 BOOL ret;
375
Guido van Rossum90fb9142013-10-30 14:44:05 -0700376 Py_BEGIN_ALLOW_THREADS
377 ret = UnregisterWait(WaitHandle);
378 Py_END_ALLOW_THREADS
379
380 if (!ret)
381 return SetFromWindowsErr(0);
382 Py_RETURN_NONE;
383}
384
Zackery Spytz9650fe02020-07-10 11:43:37 -0600385/*[clinic input]
386_overlapped.UnregisterWaitEx
387
388 WaitHandle: HANDLE
389 Event: HANDLE
390 /
391
392Unregister wait handle.
393[clinic start generated code]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100394
395static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600396_overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
397 HANDLE Event)
398/*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100399{
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100400 BOOL ret;
401
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100402 Py_BEGIN_ALLOW_THREADS
403 ret = UnregisterWaitEx(WaitHandle, Event);
404 Py_END_ALLOW_THREADS
405
406 if (!ret)
407 return SetFromWindowsErr(0);
408 Py_RETURN_NONE;
409}
410
Guido van Rossum90fb9142013-10-30 14:44:05 -0700411/*
412 * Event functions -- currently only used by tests
413 */
414
Zackery Spytz9650fe02020-07-10 11:43:37 -0600415/*[clinic input]
416_overlapped.CreateEvent
417
418 EventAttributes: object
419 ManualReset: BOOL
420 InitialState: BOOL
421 Name: Py_UNICODE(accept={str, NoneType})
422 /
423
424Create an event.
425
426EventAttributes must be None.
427[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700428
429static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600430_overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
431 BOOL ManualReset, BOOL InitialState,
432 const Py_UNICODE *Name)
433/*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700434{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700435 HANDLE Event;
436
Guido van Rossum90fb9142013-10-30 14:44:05 -0700437 if (EventAttributes != Py_None) {
438 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
439 return NULL;
440 }
441
442 Py_BEGIN_ALLOW_THREADS
443 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
444 Py_END_ALLOW_THREADS
445
446 if (Event == NULL)
447 return SetFromWindowsErr(0);
448 return Py_BuildValue(F_HANDLE, Event);
449}
450
Zackery Spytz9650fe02020-07-10 11:43:37 -0600451/*[clinic input]
452_overlapped.SetEvent
453
454 Handle: HANDLE
455 /
456
457Set event.
458[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700459
460static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600461_overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
462/*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700463{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700464 BOOL ret;
465
Guido van Rossum90fb9142013-10-30 14:44:05 -0700466 Py_BEGIN_ALLOW_THREADS
467 ret = SetEvent(Handle);
468 Py_END_ALLOW_THREADS
469
470 if (!ret)
471 return SetFromWindowsErr(0);
472 Py_RETURN_NONE;
473}
474
Zackery Spytz9650fe02020-07-10 11:43:37 -0600475/*[clinic input]
476_overlapped.ResetEvent
477
478 Handle: HANDLE
479 /
480
481Reset event.
482[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700483
484static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600485_overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
486/*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700487{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700488 BOOL ret;
489
Guido van Rossum90fb9142013-10-30 14:44:05 -0700490 Py_BEGIN_ALLOW_THREADS
491 ret = ResetEvent(Handle);
492 Py_END_ALLOW_THREADS
493
494 if (!ret)
495 return SetFromWindowsErr(0);
496 Py_RETURN_NONE;
497}
498
499/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700500 * Bind socket handle to local port without doing slow getaddrinfo()
501 */
502
Zackery Spytz9650fe02020-07-10 11:43:37 -0600503/*[clinic input]
504_overlapped.BindLocal
505
506 handle as Socket: HANDLE
507 family as Family: int
508 /
509
510Bind a socket handle to an arbitrary local port.
511
512family should be AF_INET or AF_INET6.
513[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700514
515static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600516_overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
517/*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700518{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700519 BOOL ret;
520
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700521 if (Family == AF_INET) {
522 struct sockaddr_in addr;
523 memset(&addr, 0, sizeof(addr));
524 addr.sin_family = AF_INET;
525 addr.sin_port = 0;
526 addr.sin_addr.S_un.S_addr = INADDR_ANY;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600527 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
528 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700529 } else if (Family == AF_INET6) {
530 struct sockaddr_in6 addr;
531 memset(&addr, 0, sizeof(addr));
532 addr.sin6_family = AF_INET6;
533 addr.sin6_port = 0;
534 addr.sin6_addr = in6addr_any;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600535 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
536 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700537 } else {
538 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
539 return NULL;
540 }
541
542 if (!ret)
543 return SetFromWindowsErr(WSAGetLastError());
544 Py_RETURN_NONE;
545}
546
547/*
548 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
549 */
550
Zackery Spytz9650fe02020-07-10 11:43:37 -0600551/*[clinic input]
552_overlapped.FormatMessage
553
554 error_code as code: DWORD
555 /
556
557Return error message for an error code.
558[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700559
560static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600561_overlapped_FormatMessage_impl(PyObject *module, DWORD code)
562/*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700563{
Zackery Spytz9650fe02020-07-10 11:43:37 -0600564 DWORD n;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700565 WCHAR *lpMsgBuf;
566 PyObject *res;
567
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700568 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600569 FORMAT_MESSAGE_FROM_SYSTEM |
570 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700571 NULL,
572 code,
573 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
574 (LPWSTR) &lpMsgBuf,
575 0,
576 NULL);
577 if (n) {
578 while (iswspace(lpMsgBuf[n-1]))
579 --n;
580 lpMsgBuf[n] = L'\0';
581 res = Py_BuildValue("u", lpMsgBuf);
582 } else {
583 res = PyUnicode_FromFormat("unknown error code %u", code);
584 }
585 LocalFree(lpMsgBuf);
586 return res;
587}
588
589
590/*
591 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
592 */
593
594static void
595mark_as_completed(OVERLAPPED *ov)
596{
597 ov->Internal = 0;
598 if (ov->hEvent != NULL)
599 SetEvent(ov->hEvent);
600}
601
602/*
603 * A Python object wrapping an OVERLAPPED structure and other useful data
604 * for overlapped I/O
605 */
606
Zackery Spytz9650fe02020-07-10 11:43:37 -0600607/*[clinic input]
608@classmethod
609_overlapped.Overlapped.__new__
610
611 event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
612
613OVERLAPPED structure wrapper.
614[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700615
616static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600617_overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
618/*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700619{
620 OverlappedObject *self;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700621
622 if (event == INVALID_HANDLE_VALUE) {
623 event = CreateEvent(NULL, TRUE, FALSE, NULL);
624 if (event == NULL)
625 return SetFromWindowsErr(0);
626 }
627
628 self = PyObject_New(OverlappedObject, type);
629 if (self == NULL) {
630 if (event != NULL)
631 CloseHandle(event);
632 return NULL;
633 }
634
635 self->handle = NULL;
636 self->error = 0;
637 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200638 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700639 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200640 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700641 if (event)
642 self->overlapped.hEvent = event;
643 return (PyObject *)self;
644}
645
Victor Stinner54850852019-01-11 14:35:14 +0100646
647/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
648 buffers while overlapped are still running, to prevent a crash. */
649static int
650Overlapped_clear(OverlappedObject *self)
651{
652 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300653 case TYPE_READ:
654 case TYPE_ACCEPT: {
655 Py_CLEAR(self->allocated_buffer);
656 break;
Victor Stinner54850852019-01-11 14:35:14 +0100657 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300658 case TYPE_READ_FROM: {
659 // An initial call to WSARecvFrom will only allocate the buffer.
660 // The result tuple of (message, address) is only
661 // allocated _after_ a message has been received.
662 if(self->read_from.result) {
663 // We've received a message, free the result tuple.
664 Py_CLEAR(self->read_from.result);
665 }
666 if(self->read_from.allocated_buffer) {
667 Py_CLEAR(self->read_from.allocated_buffer);
668 }
669 break;
670 }
671 case TYPE_WRITE:
672 case TYPE_WRITE_TO:
673 case TYPE_READINTO: {
674 if (self->user_buffer.obj) {
675 PyBuffer_Release(&self->user_buffer);
676 }
677 break;
678 }
Victor Stinner54850852019-01-11 14:35:14 +0100679 }
680 self->type = TYPE_NOT_STARTED;
681 return 0;
682}
683
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700684static void
685Overlapped_dealloc(OverlappedObject *self)
686{
687 DWORD bytes;
688 DWORD olderr = GetLastError();
689 BOOL wait = FALSE;
690 BOOL ret;
691
692 if (!HasOverlappedIoCompleted(&self->overlapped) &&
693 self->type != TYPE_NOT_STARTED)
694 {
695 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
696 wait = TRUE;
697
698 Py_BEGIN_ALLOW_THREADS
699 ret = GetOverlappedResult(self->handle, &self->overlapped,
700 &bytes, wait);
701 Py_END_ALLOW_THREADS
702
703 switch (ret ? ERROR_SUCCESS : GetLastError()) {
704 case ERROR_SUCCESS:
705 case ERROR_NOT_FOUND:
706 case ERROR_OPERATION_ABORTED:
707 break;
708 default:
709 PyErr_Format(
710 PyExc_RuntimeError,
711 "%R still has pending operation at "
712 "deallocation, the process may crash", self);
713 PyErr_WriteUnraisable(NULL);
714 }
715 }
716
Victor Stinner54850852019-01-11 14:35:14 +0100717 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700718 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700719 }
Victor Stinner54850852019-01-11 14:35:14 +0100720
721 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700722 SetLastError(olderr);
Mohamed Koubaa2aabc322020-09-07 08:12:40 -0500723
724 PyTypeObject *tp = Py_TYPE(self);
725 PyObject_Del(self);
726 Py_DECREF(tp);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700727}
728
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300729
730/* Convert IPv4 sockaddr to a Python str. */
731
732static PyObject *
733make_ipv4_addr(const struct sockaddr_in *addr)
734{
735 char buf[INET_ADDRSTRLEN];
736 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
737 PyErr_SetFromErrno(PyExc_OSError);
738 return NULL;
739 }
740 return PyUnicode_FromString(buf);
741}
742
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300743/* Convert IPv6 sockaddr to a Python str. */
744
745static PyObject *
746make_ipv6_addr(const struct sockaddr_in6 *addr)
747{
748 char buf[INET6_ADDRSTRLEN];
749 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
750 PyErr_SetFromErrno(PyExc_OSError);
751 return NULL;
752 }
753 return PyUnicode_FromString(buf);
754}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300755
756static PyObject*
757unparse_address(LPSOCKADDR Address, DWORD Length)
758{
759 /* The function is adopted from mocketmodule.c makesockaddr()*/
760
761 switch(Address->sa_family) {
762 case AF_INET: {
763 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
764 PyObject *addrobj = make_ipv4_addr(a);
765 PyObject *ret = NULL;
766 if (addrobj) {
767 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
768 Py_DECREF(addrobj);
769 }
770 return ret;
771 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300772 case AF_INET6: {
773 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
774 PyObject *addrobj = make_ipv6_addr(a);
775 PyObject *ret = NULL;
776 if (addrobj) {
777 ret = Py_BuildValue("OiII",
778 addrobj,
779 ntohs(a->sin6_port),
780 ntohl(a->sin6_flowinfo),
781 a->sin6_scope_id);
782 Py_DECREF(addrobj);
783 }
784 return ret;
785 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300786 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200787 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
788 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300789 }
790 }
791}
792
Zackery Spytz9650fe02020-07-10 11:43:37 -0600793/*[clinic input]
794_overlapped.Overlapped.cancel
795
796Cancel overlapped operation.
797[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700798
799static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600800_overlapped_Overlapped_cancel_impl(OverlappedObject *self)
801/*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700802{
803 BOOL ret = TRUE;
804
805 if (self->type == TYPE_NOT_STARTED
806 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
807 Py_RETURN_NONE;
808
809 if (!HasOverlappedIoCompleted(&self->overlapped)) {
810 Py_BEGIN_ALLOW_THREADS
811 if (Py_CancelIoEx)
812 ret = Py_CancelIoEx(self->handle, &self->overlapped);
813 else
814 ret = CancelIo(self->handle);
815 Py_END_ALLOW_THREADS
816 }
817
818 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
819 if (!ret && GetLastError() != ERROR_NOT_FOUND)
820 return SetFromWindowsErr(0);
821 Py_RETURN_NONE;
822}
823
Zackery Spytz9650fe02020-07-10 11:43:37 -0600824/*[clinic input]
825_overlapped.Overlapped.getresult
826
827 wait: BOOL(c_default='FALSE') = False
828 /
829
830Retrieve result of operation.
831
832If wait is true then it blocks until the operation is finished. If wait
833is false and the operation is still pending then an error is raised.
834[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700835
836static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600837_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
838/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700839{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700840 DWORD transferred = 0;
841 BOOL ret;
842 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300843 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700844
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700845 if (self->type == TYPE_NONE) {
846 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
847 return NULL;
848 }
849
850 if (self->type == TYPE_NOT_STARTED) {
851 PyErr_SetString(PyExc_ValueError, "operation failed to start");
852 return NULL;
853 }
854
855 Py_BEGIN_ALLOW_THREADS
856 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
857 wait);
858 Py_END_ALLOW_THREADS
859
860 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
861 switch (err) {
862 case ERROR_SUCCESS:
863 case ERROR_MORE_DATA:
864 break;
865 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300866 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700867 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300868 }
869 else if (self->type == TYPE_READ_FROM &&
870 (self->read_from.result != NULL ||
871 self->read_from.allocated_buffer != NULL))
872 {
873 break;
874 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700875 /* fall through */
876 default:
877 return SetFromWindowsErr(err);
878 }
879
880 switch (self->type) {
881 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200882 assert(PyBytes_CheckExact(self->allocated_buffer));
883 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
884 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700885 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300886
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200887 Py_INCREF(self->allocated_buffer);
888 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300889 case TYPE_READ_FROM:
890 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
891
892 if (transferred != PyBytes_GET_SIZE(
893 self->read_from.allocated_buffer) &&
894 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
895 {
896 return NULL;
897 }
898
899 // unparse the address
900 addr = unparse_address((SOCKADDR*)&self->read_from.address,
901 self->read_from.address_length);
902
903 if (addr == NULL) {
904 return NULL;
905 }
906
907 // The result is a two item tuple: (message, address)
908 self->read_from.result = PyTuple_New(2);
909 if (self->read_from.result == NULL) {
910 Py_CLEAR(addr);
911 return NULL;
912 }
913
914 // first item: message
915 Py_INCREF(self->read_from.allocated_buffer);
916 PyTuple_SET_ITEM(self->read_from.result, 0,
917 self->read_from.allocated_buffer);
918 // second item: address
919 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
920
921 Py_INCREF(self->read_from.result);
922 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700923 default:
924 return PyLong_FromUnsignedLong((unsigned long) transferred);
925 }
926}
927
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200928static PyObject *
929do_ReadFile(OverlappedObject *self, HANDLE handle,
930 char *bufstart, DWORD buflen)
931{
932 DWORD nread;
933 int ret;
934 DWORD err;
935
936 Py_BEGIN_ALLOW_THREADS
937 ret = ReadFile(handle, bufstart, buflen, &nread,
938 &self->overlapped);
939 Py_END_ALLOW_THREADS
940
941 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
942 switch (err) {
943 case ERROR_BROKEN_PIPE:
944 mark_as_completed(&self->overlapped);
945 return SetFromWindowsErr(err);
946 case ERROR_SUCCESS:
947 case ERROR_MORE_DATA:
948 case ERROR_IO_PENDING:
949 Py_RETURN_NONE;
950 default:
Victor Stinner54850852019-01-11 14:35:14 +0100951 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200952 return SetFromWindowsErr(err);
953 }
954}
955
Zackery Spytz9650fe02020-07-10 11:43:37 -0600956/*[clinic input]
957_overlapped.Overlapped.ReadFile
958
959 handle: HANDLE
960 size: DWORD
961 /
962
963Start overlapped read.
964[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700965
966static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600967_overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
968 DWORD size)
969/*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700970{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700971 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700972
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700973 if (self->type != TYPE_NONE) {
974 PyErr_SetString(PyExc_ValueError, "operation already attempted");
975 return NULL;
976 }
977
978#if SIZEOF_SIZE_T <= SIZEOF_LONG
979 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
980#endif
981 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
982 if (buf == NULL)
983 return NULL;
984
985 self->type = TYPE_READ;
986 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200987 self->allocated_buffer = buf;
988
989 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
990}
991
Zackery Spytz9650fe02020-07-10 11:43:37 -0600992/*[clinic input]
993_overlapped.Overlapped.ReadFileInto
994
995 handle: HANDLE
996 buf as bufobj: object
997 /
998
999Start overlapped receive.
1000[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001001
1002static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001003_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
1004 HANDLE handle, PyObject *bufobj)
1005/*[clinic end generated code: output=1e9e712e742e5b2a input=16f6cc268d1d0387]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001006{
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001007 if (self->type != TYPE_NONE) {
1008 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1009 return NULL;
1010 }
1011
1012 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1013 return NULL;
1014
1015#if SIZEOF_SIZE_T > SIZEOF_LONG
1016 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1017 PyBuffer_Release(&self->user_buffer);
1018 PyErr_SetString(PyExc_ValueError, "buffer too large");
1019 return NULL;
1020 }
1021#endif
1022
1023 self->type = TYPE_READINTO;
1024 self->handle = handle;
1025
1026 return do_ReadFile(self, handle, self->user_buffer.buf,
1027 (DWORD)self->user_buffer.len);
1028}
1029
1030static PyObject *
1031do_WSARecv(OverlappedObject *self, HANDLE handle,
1032 char *bufstart, DWORD buflen, DWORD flags)
1033{
1034 DWORD nread;
1035 WSABUF wsabuf;
1036 int ret;
1037 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +03001038
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001039 wsabuf.buf = bufstart;
1040 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001041
1042 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001043 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1044 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001045 Py_END_ALLOW_THREADS
1046
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001047 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001048 switch (err) {
1049 case ERROR_BROKEN_PIPE:
1050 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +01001051 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001052 case ERROR_SUCCESS:
1053 case ERROR_MORE_DATA:
1054 case ERROR_IO_PENDING:
1055 Py_RETURN_NONE;
1056 default:
Victor Stinner54850852019-01-11 14:35:14 +01001057 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001058 return SetFromWindowsErr(err);
1059 }
1060}
1061
Zackery Spytz9650fe02020-07-10 11:43:37 -06001062/*[clinic input]
1063_overlapped.Overlapped.WSARecv
1064
1065 handle: HANDLE
1066 size: DWORD
1067 flags: DWORD = 0
1068 /
1069
1070Start overlapped receive.
1071[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001072
1073static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001074_overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
1075 DWORD size, DWORD flags)
1076/*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001077{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001078 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001079
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001080 if (self->type != TYPE_NONE) {
1081 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1082 return NULL;
1083 }
1084
1085#if SIZEOF_SIZE_T <= SIZEOF_LONG
1086 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1087#endif
1088 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1089 if (buf == NULL)
1090 return NULL;
1091
1092 self->type = TYPE_READ;
1093 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001094 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001095
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001096 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1097}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001098
Zackery Spytz9650fe02020-07-10 11:43:37 -06001099/*[clinic input]
1100_overlapped.Overlapped.WSARecvInto
1101
1102 handle: HANDLE
1103 buf as bufobj: object
1104 flags: DWORD
1105 /
1106
1107Start overlapped receive.
1108[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001109
1110static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001111_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
1112 HANDLE handle, PyObject *bufobj,
1113 DWORD flags)
1114/*[clinic end generated code: output=9a438abc436fe87c input=4f87c38fc381d525]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001115{
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001116 if (self->type != TYPE_NONE) {
1117 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1118 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001119 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001120
1121 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1122 return NULL;
1123
1124#if SIZEOF_SIZE_T > SIZEOF_LONG
1125 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1126 PyBuffer_Release(&self->user_buffer);
1127 PyErr_SetString(PyExc_ValueError, "buffer too large");
1128 return NULL;
1129 }
1130#endif
1131
1132 self->type = TYPE_READINTO;
1133 self->handle = handle;
1134
1135 return do_WSARecv(self, handle, self->user_buffer.buf,
1136 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001137}
1138
Zackery Spytz9650fe02020-07-10 11:43:37 -06001139/*[clinic input]
1140_overlapped.Overlapped.WriteFile
1141
1142 handle: HANDLE
1143 buf as bufobj: object
1144 /
1145
1146Start overlapped write.
1147[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001148
1149static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001150_overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
1151 PyObject *bufobj)
1152/*[clinic end generated code: output=c376230b6120d877 input=b8d9a7608d8a1e72]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001153{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001154 DWORD written;
1155 BOOL ret;
1156 DWORD err;
1157
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001158 if (self->type != TYPE_NONE) {
1159 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1160 return NULL;
1161 }
1162
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001163 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001164 return NULL;
1165
1166#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001167 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1168 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001169 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001170 return NULL;
1171 }
1172#endif
1173
1174 self->type = TYPE_WRITE;
1175 self->handle = handle;
1176
1177 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001178 ret = WriteFile(handle, self->user_buffer.buf,
1179 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001180 &written, &self->overlapped);
1181 Py_END_ALLOW_THREADS
1182
1183 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1184 switch (err) {
1185 case ERROR_SUCCESS:
1186 case ERROR_IO_PENDING:
1187 Py_RETURN_NONE;
1188 default:
Victor Stinner54850852019-01-11 14:35:14 +01001189 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001190 return SetFromWindowsErr(err);
1191 }
1192}
1193
Zackery Spytz9650fe02020-07-10 11:43:37 -06001194/*[clinic input]
1195_overlapped.Overlapped.WSASend
1196
1197 handle: HANDLE
1198 buf as bufobj: object
1199 flags: DWORD
1200 /
1201
1202Start overlapped send.
1203[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001204
1205static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001206_overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
1207 PyObject *bufobj, DWORD flags)
1208/*[clinic end generated code: output=316031c7467040cc input=932e7cba6d18f708]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001209{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001210 DWORD written;
1211 WSABUF wsabuf;
1212 int ret;
1213 DWORD err;
1214
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001215 if (self->type != TYPE_NONE) {
1216 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1217 return NULL;
1218 }
1219
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001220 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001221 return NULL;
1222
1223#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001224 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1225 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001226 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001227 return NULL;
1228 }
1229#endif
1230
1231 self->type = TYPE_WRITE;
1232 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001233 wsabuf.len = (DWORD)self->user_buffer.len;
1234 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001235
1236 Py_BEGIN_ALLOW_THREADS
1237 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1238 &self->overlapped, NULL);
1239 Py_END_ALLOW_THREADS
1240
1241 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1242 switch (err) {
1243 case ERROR_SUCCESS:
1244 case ERROR_IO_PENDING:
1245 Py_RETURN_NONE;
1246 default:
Victor Stinner54850852019-01-11 14:35:14 +01001247 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001248 return SetFromWindowsErr(err);
1249 }
1250}
1251
Zackery Spytz9650fe02020-07-10 11:43:37 -06001252/*[clinic input]
1253_overlapped.Overlapped.AcceptEx
1254
1255 listen_handle as ListenSocket: HANDLE
1256 accept_handle as AcceptSocket: HANDLE
1257 /
1258
1259Start overlapped wait for client to connect.
1260[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001261
1262static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001263_overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
1264 HANDLE ListenSocket,
1265 HANDLE AcceptSocket)
1266/*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001267{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001268 DWORD BytesReceived;
1269 DWORD size;
1270 PyObject *buf;
1271 BOOL ret;
1272 DWORD err;
1273
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001274 if (self->type != TYPE_NONE) {
1275 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1276 return NULL;
1277 }
1278
1279 size = sizeof(struct sockaddr_in6) + 16;
1280 buf = PyBytes_FromStringAndSize(NULL, size*2);
1281 if (!buf)
1282 return NULL;
1283
1284 self->type = TYPE_ACCEPT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001285 self->handle = ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001286 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001287
1288 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001289 ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
1290 PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
1291 &self->overlapped);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001292 Py_END_ALLOW_THREADS
1293
1294 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1295 switch (err) {
1296 case ERROR_SUCCESS:
1297 case ERROR_IO_PENDING:
1298 Py_RETURN_NONE;
1299 default:
Victor Stinner54850852019-01-11 14:35:14 +01001300 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001301 return SetFromWindowsErr(err);
1302 }
1303}
1304
1305
1306static int
1307parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1308{
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001309 PyObject *Host_obj;
Steve Dowercc16be82016-09-08 10:35:16 -07001310 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001311 unsigned short Port;
1312 unsigned long FlowInfo;
1313 unsigned long ScopeId;
1314
1315 memset(Address, 0, Length);
1316
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001317 switch (PyTuple_GET_SIZE(obj)) {
1318 case 2: {
1319 if (!PyArg_ParseTuple(obj, "UH", &Host_obj, &Port)) {
1320 return -1;
1321 }
1322#if USE_UNICODE_WCHAR_CACHE
1323 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1324#else /* USE_UNICODE_WCHAR_CACHE */
1325 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1326#endif /* USE_UNICODE_WCHAR_CACHE */
1327 if (Host == NULL) {
1328 return -1;
1329 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001330 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001331 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001332 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001333 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001334 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001335 else {
1336 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1337 }
1338#if !USE_UNICODE_WCHAR_CACHE
1339 PyMem_Free(Host);
1340#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001341 return Length;
1342 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001343 case 4: {
1344 if (!PyArg_ParseTuple(obj,
1345 "UHkk;ConnectEx(): illegal address_as_bytes argument",
1346 &Host_obj, &Port, &FlowInfo, &ScopeId))
1347 {
1348 return -1;
1349 }
1350#if USE_UNICODE_WCHAR_CACHE
1351 Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1352#else /* USE_UNICODE_WCHAR_CACHE */
1353 Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1354#endif /* USE_UNICODE_WCHAR_CACHE */
1355 if (Host == NULL) {
1356 return -1;
1357 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001358 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001359 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001360 SetFromWindowsErr(WSAGetLastError());
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001361 Length = -1;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001362 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001363 else {
1364 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1365 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1366 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1367 }
1368#if !USE_UNICODE_WCHAR_CACHE
1369 PyMem_Free(Host);
1370#endif /* USE_UNICODE_WCHAR_CACHE */
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001371 return Length;
1372 }
Serhiy Storchaka4c8f09d2020-07-10 23:26:06 +03001373 default:
1374 PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument");
1375 return -1;
1376 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001377}
1378
Zackery Spytz9650fe02020-07-10 11:43:37 -06001379/*[clinic input]
1380_overlapped.Overlapped.ConnectEx
1381
1382 client_handle as ConnectSocket: HANDLE
1383 address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1384 /
1385
1386Start overlapped connect.
1387
1388client_handle should be unbound.
1389[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001390
1391static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001392_overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
1393 HANDLE ConnectSocket,
1394 PyObject *AddressObj)
1395/*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001396{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001397 char AddressBuf[sizeof(struct sockaddr_in6)];
1398 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1399 int Length;
1400 BOOL ret;
1401 DWORD err;
1402
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001403 if (self->type != TYPE_NONE) {
1404 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1405 return NULL;
1406 }
1407
1408 Length = sizeof(AddressBuf);
1409 Length = parse_address(AddressObj, Address, Length);
1410 if (Length < 0)
1411 return NULL;
1412
1413 self->type = TYPE_CONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001414 self->handle = ConnectSocket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001415
1416 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001417 ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001418 NULL, 0, NULL, &self->overlapped);
1419 Py_END_ALLOW_THREADS
1420
1421 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1422 switch (err) {
1423 case ERROR_SUCCESS:
1424 case ERROR_IO_PENDING:
1425 Py_RETURN_NONE;
1426 default:
Victor Stinner54850852019-01-11 14:35:14 +01001427 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001428 return SetFromWindowsErr(err);
1429 }
1430}
1431
Zackery Spytz9650fe02020-07-10 11:43:37 -06001432/*[clinic input]
1433_overlapped.Overlapped.DisconnectEx
1434
1435 handle as Socket: HANDLE
1436 flags: DWORD
1437 /
1438
1439[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001440
1441static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001442_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
1443 HANDLE Socket, DWORD flags)
1444/*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001445{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001446 BOOL ret;
1447 DWORD err;
1448
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001449 if (self->type != TYPE_NONE) {
1450 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1451 return NULL;
1452 }
1453
1454 self->type = TYPE_DISCONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001455 self->handle = Socket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001456
1457 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001458 ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001459 Py_END_ALLOW_THREADS
1460
1461 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1462 switch (err) {
1463 case ERROR_SUCCESS:
1464 case ERROR_IO_PENDING:
1465 Py_RETURN_NONE;
1466 default:
Victor Stinner54850852019-01-11 14:35:14 +01001467 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001468 return SetFromWindowsErr(err);
1469 }
1470}
1471
Zackery Spytz9650fe02020-07-10 11:43:37 -06001472/*[clinic input]
1473_overlapped.Overlapped.TransmitFile
1474
1475 socket as Socket: HANDLE
1476 file as File: HANDLE
1477 offset: DWORD
1478 offset_high: DWORD
1479 count_to_write: DWORD
1480 count_per_send: DWORD
1481 flags: DWORD
1482 /
1483
1484Transmit file data over a connected socket.
1485[clinic start generated code]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001486
1487static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001488_overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
1489 HANDLE Socket, HANDLE File,
1490 DWORD offset, DWORD offset_high,
1491 DWORD count_to_write,
1492 DWORD count_per_send, DWORD flags)
1493/*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001494{
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001495 BOOL ret;
1496 DWORD err;
1497
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001498 if (self->type != TYPE_NONE) {
1499 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1500 return NULL;
1501 }
1502
1503 self->type = TYPE_TRANSMIT_FILE;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001504 self->handle = Socket;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001505 self->overlapped.Offset = offset;
1506 self->overlapped.OffsetHigh = offset_high;
1507
1508 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001509 ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
1510 count_per_send, &self->overlapped, NULL, flags);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001511 Py_END_ALLOW_THREADS
1512
1513 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1514 switch (err) {
1515 case ERROR_SUCCESS:
1516 case ERROR_IO_PENDING:
1517 Py_RETURN_NONE;
1518 default:
Victor Stinner54850852019-01-11 14:35:14 +01001519 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001520 return SetFromWindowsErr(err);
1521 }
1522}
1523
Zackery Spytz9650fe02020-07-10 11:43:37 -06001524/*[clinic input]
1525_overlapped.Overlapped.ConnectNamedPipe
1526
1527 handle as Pipe: HANDLE
1528 /
1529
1530Start overlapped wait for a client to connect.
1531[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001532
1533static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001534_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
1535 HANDLE Pipe)
1536/*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001537{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001538 BOOL ret;
1539 DWORD err;
1540
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001541 if (self->type != TYPE_NONE) {
1542 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1543 return NULL;
1544 }
1545
1546 self->type = TYPE_CONNECT_NAMED_PIPE;
1547 self->handle = Pipe;
1548
1549 Py_BEGIN_ALLOW_THREADS
1550 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1551 Py_END_ALLOW_THREADS
1552
1553 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1554 switch (err) {
1555 case ERROR_PIPE_CONNECTED:
1556 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001557 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001558 case ERROR_SUCCESS:
1559 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001560 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001561 default:
Victor Stinner54850852019-01-11 14:35:14 +01001562 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001563 return SetFromWindowsErr(err);
1564 }
1565}
1566
Zackery Spytz9650fe02020-07-10 11:43:37 -06001567/*[clinic input]
1568_overlapped.Overlapped.ConnectPipe
1569
1570 addr as Address: Py_UNICODE
1571 /
1572
1573Connect to the pipe for asynchronous I/O (overlapped).
1574[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001575
1576static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001577_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
1578 const Py_UNICODE *Address)
1579/*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001580{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001581 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001582
Victor Stinner498b1f62015-01-26 22:43:39 +01001583 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001584 PipeHandle = CreateFileW(Address,
1585 GENERIC_READ | GENERIC_WRITE,
1586 0, NULL, OPEN_EXISTING,
1587 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001588 Py_END_ALLOW_THREADS
1589
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001590 if (PipeHandle == INVALID_HANDLE_VALUE)
1591 return SetFromWindowsErr(0);
1592 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001593}
1594
1595static PyObject*
1596Overlapped_getaddress(OverlappedObject *self)
1597{
1598 return PyLong_FromVoidPtr(&self->overlapped);
1599}
1600
1601static PyObject*
1602Overlapped_getpending(OverlappedObject *self)
1603{
1604 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1605 self->type != TYPE_NOT_STARTED);
1606}
1607
Victor Stinner54850852019-01-11 14:35:14 +01001608static int
1609Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1610{
1611 switch (self->type) {
1612 case TYPE_READ:
1613 case TYPE_ACCEPT:
1614 Py_VISIT(self->allocated_buffer);
1615 break;
1616 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001617 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001618 case TYPE_READINTO:
1619 if (self->user_buffer.obj) {
1620 Py_VISIT(&self->user_buffer.obj);
1621 }
1622 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001623 case TYPE_READ_FROM:
Hai Shi47a23fc2020-06-07 20:05:36 +08001624 Py_VISIT(self->read_from.result);
1625 Py_VISIT(self->read_from.allocated_buffer);
Victor Stinner54850852019-01-11 14:35:14 +01001626 }
1627 return 0;
1628}
1629
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001630// UDP functions
1631
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001632/*
1633 * Note: WSAConnect does not support Overlapped I/O so this function should
1634 * _only_ be used for connectionless sockets (UDP).
1635 */
Zackery Spytz9650fe02020-07-10 11:43:37 -06001636
1637/*[clinic input]
1638_overlapped.WSAConnect
1639
1640 client_handle as ConnectSocket: HANDLE
1641 address_as_bytes as AddressObj: object
1642 /
1643
1644Bind a remote address to a connectionless (UDP) socket.
1645[clinic start generated code]*/
1646
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001647static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001648_overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
1649 PyObject *AddressObj)
1650/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001651{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001652 char AddressBuf[sizeof(struct sockaddr_in6)];
1653 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1654 int Length;
1655 int err;
1656
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001657 Length = sizeof(AddressBuf);
1658 Length = parse_address(AddressObj, Address, Length);
1659 if (Length < 0) {
1660 return NULL;
1661 }
1662
1663 Py_BEGIN_ALLOW_THREADS
1664 // WSAConnect does not support overlapped I/O so this call will
1665 // successfully complete immediately.
Zackery Spytz9650fe02020-07-10 11:43:37 -06001666 err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001667 NULL, NULL, NULL, NULL);
1668 Py_END_ALLOW_THREADS
1669
1670 if (err == 0) {
1671 Py_RETURN_NONE;
1672 }
1673 else {
1674 return SetFromWindowsErr(WSAGetLastError());
1675 }
1676}
1677
Zackery Spytz9650fe02020-07-10 11:43:37 -06001678/*[clinic input]
1679_overlapped.Overlapped.WSASendTo
1680
1681 handle: HANDLE
1682 buf as bufobj: object
1683 flags: DWORD
1684 address_as_bytes as AddressObj: object
1685 /
1686
1687Start overlapped sendto over a connectionless (UDP) socket.
1688[clinic start generated code]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001689
1690static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001691_overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
1692 PyObject *bufobj, DWORD flags,
1693 PyObject *AddressObj)
1694/*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001695{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001696 char AddressBuf[sizeof(struct sockaddr_in6)];
1697 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1698 int AddressLength;
1699 DWORD written;
1700 WSABUF wsabuf;
1701 int ret;
1702 DWORD err;
1703
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001704 // Parse the "to" address
1705 AddressLength = sizeof(AddressBuf);
1706 AddressLength = parse_address(AddressObj, Address, AddressLength);
1707 if (AddressLength < 0) {
1708 return NULL;
1709 }
1710
1711 if (self->type != TYPE_NONE) {
1712 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1713 return NULL;
1714 }
1715
1716 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1717 return NULL;
1718 }
1719
1720#if SIZEOF_SIZE_T > SIZEOF_LONG
1721 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1722 PyBuffer_Release(&self->user_buffer);
1723 PyErr_SetString(PyExc_ValueError, "buffer too large");
1724 return NULL;
1725 }
1726#endif
1727
1728 self->type = TYPE_WRITE_TO;
1729 self->handle = handle;
1730 wsabuf.len = (DWORD)self->user_buffer.len;
1731 wsabuf.buf = self->user_buffer.buf;
1732
1733 Py_BEGIN_ALLOW_THREADS
1734 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1735 Address, AddressLength, &self->overlapped, NULL);
1736 Py_END_ALLOW_THREADS
1737
1738 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1739 ERROR_SUCCESS);
1740
1741 switch(err) {
1742 case ERROR_SUCCESS:
1743 case ERROR_IO_PENDING:
1744 Py_RETURN_NONE;
1745 default:
1746 self->type = TYPE_NOT_STARTED;
1747 return SetFromWindowsErr(err);
1748 }
1749}
1750
1751
1752
1753PyDoc_STRVAR(
1754 Overlapped_WSARecvFrom_doc,
1755 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1756 "Start overlapped receive");
1757
Zackery Spytz9650fe02020-07-10 11:43:37 -06001758/*[clinic input]
1759_overlapped.Overlapped.WSARecvFrom
1760
1761 handle: HANDLE
1762 size: DWORD
1763 flags: DWORD = 0
1764 /
1765
1766Start overlapped receive.
1767[clinic start generated code]*/
1768
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001769static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001770_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
1771 HANDLE handle, DWORD size,
1772 DWORD flags)
1773/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001774{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001775 DWORD nread;
1776 PyObject *buf;
1777 WSABUF wsabuf;
1778 int ret;
1779 DWORD err;
1780
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001781 if (self->type != TYPE_NONE) {
1782 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1783 return NULL;
1784 }
1785
1786#if SIZEOF_SIZE_T <= SIZEOF_LONG
1787 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1788#endif
1789 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1790 if (buf == NULL) {
1791 return NULL;
1792 }
1793
1794 wsabuf.len = size;
1795 wsabuf.buf = PyBytes_AS_STRING(buf);
1796
1797 self->type = TYPE_READ_FROM;
1798 self->handle = handle;
1799 self->read_from.allocated_buffer = buf;
1800 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1801 self->read_from.address_length = sizeof(self->read_from.address);
1802
1803 Py_BEGIN_ALLOW_THREADS
1804 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1805 (SOCKADDR*)&self->read_from.address,
1806 &self->read_from.address_length,
1807 &self->overlapped, NULL);
1808 Py_END_ALLOW_THREADS
1809
1810 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1811
1812 switch(err) {
1813 case ERROR_BROKEN_PIPE:
1814 mark_as_completed(&self->overlapped);
1815 return SetFromWindowsErr(err);
1816 case ERROR_SUCCESS:
1817 case ERROR_MORE_DATA:
1818 case ERROR_IO_PENDING:
1819 Py_RETURN_NONE;
1820 default:
1821 self->type = TYPE_NOT_STARTED;
1822 return SetFromWindowsErr(err);
1823 }
1824}
1825
Zackery Spytz9650fe02020-07-10 11:43:37 -06001826#include "clinic/overlapped.c.h"
Victor Stinner54850852019-01-11 14:35:14 +01001827
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001828static PyMethodDef Overlapped_methods[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001829 _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
1830 _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
1831 _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
1832 _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
1833 _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
1834 _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
1835 _OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
1836 _OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
1837 _OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
1838 _OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
1839 _OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
1840 _OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
1841 _OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
1842 _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1843 _OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001844 {NULL}
1845};
1846
1847static PyMemberDef Overlapped_members[] = {
1848 {"error", T_ULONG,
1849 offsetof(OverlappedObject, error),
1850 READONLY, "Error from last operation"},
1851 {"event", T_HANDLE,
1852 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1853 READONLY, "Overlapped event handle"},
1854 {NULL}
1855};
1856
1857static PyGetSetDef Overlapped_getsets[] = {
1858 {"address", (getter)Overlapped_getaddress, NULL,
1859 "Address of overlapped structure"},
1860 {"pending", (getter)Overlapped_getpending, NULL,
1861 "Whether the operation is pending"},
1862 {NULL},
1863};
1864
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001865static PyType_Slot overlapped_type_slots[] = {
1866 {Py_tp_dealloc, Overlapped_dealloc},
1867 {Py_tp_doc, (char *)_overlapped_Overlapped__doc__},
1868 {Py_tp_traverse, Overlapped_traverse},
1869 {Py_tp_methods, Overlapped_methods},
1870 {Py_tp_members, Overlapped_members},
1871 {Py_tp_getset, Overlapped_getsets},
1872 {Py_tp_new, _overlapped_Overlapped},
1873 {0,0}
1874};
1875
1876static PyType_Spec overlapped_type_spec = {
1877 .name = "_overlapped.Overlapped",
1878 .basicsize = sizeof(OverlappedObject),
1879 .flags = Py_TPFLAGS_DEFAULT,
1880 .slots = overlapped_type_slots
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001881};
1882
1883static PyMethodDef overlapped_functions[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001884 _OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
1885 _OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
1886 _OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
1887 _OVERLAPPED_FORMATMESSAGE_METHODDEF
1888 _OVERLAPPED_BINDLOCAL_METHODDEF
1889 _OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
1890 _OVERLAPPED_UNREGISTERWAIT_METHODDEF
1891 _OVERLAPPED_UNREGISTERWAITEX_METHODDEF
1892 _OVERLAPPED_CREATEEVENT_METHODDEF
1893 _OVERLAPPED_SETEVENT_METHODDEF
1894 _OVERLAPPED_RESETEVENT_METHODDEF
1895 _OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
1896 _OVERLAPPED_WSACONNECT_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001897 {NULL}
1898};
1899
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001900static int
1901overlapped_traverse(PyObject *module, visitproc visit, void *arg)
1902{
1903 OverlappedState *state = overlapped_get_state(module);
1904 Py_VISIT(state->overlapped_type);
1905 return 0;
1906}
1907
1908static int
1909overlapped_clear(PyObject *module)
1910{
1911 OverlappedState *state = overlapped_get_state(module);
1912 Py_CLEAR(state->overlapped_type);
1913 return 0;
1914}
1915
1916static void
1917overlapped_free(void *module)
1918{
1919 overlapped_clear((PyObject *)module);
1920}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001921
1922#define WINAPI_CONSTANT(fmt, con) \
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001923 do { \
1924 PyObject *value = Py_BuildValue(fmt, con); \
1925 if (value == NULL) { \
1926 return -1; \
1927 } \
1928 if (PyModule_AddObject(module, #con, value) < 0 ) { \
1929 Py_DECREF(value); \
1930 return -1; \
1931 } \
1932 } while (0)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001933
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001934static int
1935overlapped_exec(PyObject *module)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001936{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001937 /* Ensure WSAStartup() called before initializing function pointers */
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001938 PyObject *socket_module = PyImport_ImportModule("_socket");
1939 if (!socket_module) {
1940 return -1;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001941 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001942
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001943 Py_DECREF(socket_module);
1944
1945 if (initialize_function_pointers() < 0) {
1946 return -1;
1947 }
1948
1949 OverlappedState *st = overlapped_get_state(module);
1950 st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(
1951 module, &overlapped_type_spec, NULL);
1952 if (st->overlapped_type == NULL) {
1953 return -1;
1954 }
1955
1956 if (PyModule_AddType(module, st->overlapped_type) < 0) {
1957 return -1;
1958 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001959
1960 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1961 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001962 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001963 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001964 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001965 WINAPI_CONSTANT(F_DWORD, INFINITE);
1966 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1967 WINAPI_CONSTANT(F_HANDLE, NULL);
1968 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1969 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1970 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1971
Mohamed Koubaa2aabc322020-09-07 08:12:40 -05001972 return 0;
1973}
1974
1975static PyModuleDef_Slot overlapped_slots[] = {
1976 {Py_mod_exec, overlapped_exec},
1977 {0, NULL}
1978};
1979
1980static struct PyModuleDef overlapped_module = {
1981 PyModuleDef_HEAD_INIT,
1982 .m_name = "_overlapped",
1983 .m_size = sizeof(OverlappedState),
1984 .m_methods = overlapped_functions,
1985 .m_slots = overlapped_slots,
1986 .m_traverse = overlapped_traverse,
1987 .m_clear = overlapped_clear,
1988 .m_free = overlapped_free
1989};
1990
1991PyMODINIT_FUNC
1992PyInit__overlapped(void)
1993{
1994 return PyModuleDef_Init(&overlapped_module);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001995}