blob: eed8fbf0393002af3a1cd26ba5117073d66eac44 [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
Antoine Pitrou525f40d2017-10-19 21:46:40 +020040enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
41 TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030042 TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
43 TYPE_WRITE_TO};
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070044
45typedef struct {
46 PyObject_HEAD
47 OVERLAPPED overlapped;
48 /* For convenience, we store the file handle too */
49 HANDLE handle;
50 /* Error returned by last method call */
51 DWORD error;
52 /* Type of operation */
53 DWORD type;
54 union {
Antoine Pitrou525f40d2017-10-19 21:46:40 +020055 /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
56 PyObject *allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030057 /* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */
Antoine Pitrou525f40d2017-10-19 21:46:40 +020058 Py_buffer user_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030059
60 /* Data used for reading from a connectionless socket:
61 TYPE_READ_FROM */
62 struct {
63 // A (buffer, (host, port)) tuple
64 PyObject *result;
65 // The actual read buffer
66 PyObject *allocated_buffer;
67 struct sockaddr_in6 address;
68 int address_length;
69 } read_from;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070070 };
71} OverlappedObject;
72
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070073/*
74 * Map Windows error codes to subclasses of OSError
75 */
76
77static PyObject *
78SetFromWindowsErr(DWORD err)
79{
80 PyObject *exception_type;
81
82 if (err == 0)
83 err = GetLastError();
84 switch (err) {
85 case ERROR_CONNECTION_REFUSED:
86 exception_type = PyExc_ConnectionRefusedError;
87 break;
88 case ERROR_CONNECTION_ABORTED:
89 exception_type = PyExc_ConnectionAbortedError;
90 break;
91 default:
92 exception_type = PyExc_OSError;
93 }
94 return PyErr_SetExcFromWindowsErr(exception_type, err);
95}
96
97/*
98 * Some functions should be loaded at runtime
99 */
100
101static LPFN_ACCEPTEX Py_AcceptEx = NULL;
102static LPFN_CONNECTEX Py_ConnectEx = NULL;
103static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300104static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700105static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
106
107#define GET_WSA_POINTER(s, x) \
108 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
109 &Guid##x, sizeof(Guid##x), &Py_##x, \
110 sizeof(Py_##x), &dwBytes, NULL, NULL))
111
112static int
113initialize_function_pointers(void)
114{
115 GUID GuidAcceptEx = WSAID_ACCEPTEX;
116 GUID GuidConnectEx = WSAID_CONNECTEX;
117 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300118 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700119 HINSTANCE hKernel32;
120 SOCKET s;
121 DWORD dwBytes;
122
123 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
124 if (s == INVALID_SOCKET) {
125 SetFromWindowsErr(WSAGetLastError());
126 return -1;
127 }
128
129 if (!GET_WSA_POINTER(s, AcceptEx) ||
130 !GET_WSA_POINTER(s, ConnectEx) ||
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300131 !GET_WSA_POINTER(s, DisconnectEx) ||
132 !GET_WSA_POINTER(s, TransmitFile))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700133 {
134 closesocket(s);
135 SetFromWindowsErr(WSAGetLastError());
136 return -1;
137 }
138
139 closesocket(s);
140
141 /* On WinXP we will have Py_CancelIoEx == NULL */
Tony Roberts4860f012019-02-02 18:16:42 +0100142 Py_BEGIN_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700143 hKernel32 = GetModuleHandle("KERNEL32");
144 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Tony Roberts4860f012019-02-02 18:16:42 +0100145 Py_END_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700146 return 0;
147}
148
149/*
150 * Completion port stuff
151 */
152
153PyDoc_STRVAR(
154 CreateIoCompletionPort_doc,
155 "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
156 "Create a completion port or register a handle with a port.");
157
158static PyObject *
159overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
160{
161 HANDLE FileHandle;
162 HANDLE ExistingCompletionPort;
163 ULONG_PTR CompletionKey;
164 DWORD NumberOfConcurrentThreads;
165 HANDLE ret;
166
167 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
168 &FileHandle, &ExistingCompletionPort, &CompletionKey,
169 &NumberOfConcurrentThreads))
170 return NULL;
171
172 Py_BEGIN_ALLOW_THREADS
173 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
174 CompletionKey, NumberOfConcurrentThreads);
175 Py_END_ALLOW_THREADS
176
177 if (ret == NULL)
178 return SetFromWindowsErr(0);
179 return Py_BuildValue(F_HANDLE, ret);
180}
181
182PyDoc_STRVAR(
183 GetQueuedCompletionStatus_doc,
184 "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
185 "Get a message from completion port. Wait for up to msecs milliseconds.");
186
187static PyObject *
188overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
189{
190 HANDLE CompletionPort = NULL;
191 DWORD NumberOfBytes = 0;
192 ULONG_PTR CompletionKey = 0;
193 OVERLAPPED *Overlapped = NULL;
194 DWORD Milliseconds;
195 DWORD err;
196 BOOL ret;
197
198 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
199 &CompletionPort, &Milliseconds))
200 return NULL;
201
202 Py_BEGIN_ALLOW_THREADS
203 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
204 &CompletionKey, &Overlapped, Milliseconds);
205 Py_END_ALLOW_THREADS
206
207 err = ret ? ERROR_SUCCESS : GetLastError();
208 if (Overlapped == NULL) {
209 if (err == WAIT_TIMEOUT)
210 Py_RETURN_NONE;
211 else
212 return SetFromWindowsErr(err);
213 }
214 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
215 err, NumberOfBytes, CompletionKey, Overlapped);
216}
217
218PyDoc_STRVAR(
219 PostQueuedCompletionStatus_doc,
220 "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
221 "Post a message to completion port.");
222
223static PyObject *
224overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
225{
226 HANDLE CompletionPort;
227 DWORD NumberOfBytes;
228 ULONG_PTR CompletionKey;
229 OVERLAPPED *Overlapped;
230 BOOL ret;
231
232 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
233 &CompletionPort, &NumberOfBytes, &CompletionKey,
234 &Overlapped))
235 return NULL;
236
237 Py_BEGIN_ALLOW_THREADS
238 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
239 CompletionKey, Overlapped);
240 Py_END_ALLOW_THREADS
241
242 if (!ret)
243 return SetFromWindowsErr(0);
244 Py_RETURN_NONE;
245}
246
247/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700248 * Wait for a handle
249 */
250
251struct PostCallbackData {
252 HANDLE CompletionPort;
253 LPOVERLAPPED Overlapped;
254};
255
256static VOID CALLBACK
257PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
258{
259 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
260
261 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
262 0, p->Overlapped);
263 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100264 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700265}
266
267PyDoc_STRVAR(
268 RegisterWaitWithQueue_doc,
269 "RegisterWaitWithQueue(Object, CompletionPort, Overlapped, Timeout)\n"
270 " -> WaitHandle\n\n"
271 "Register wait for Object; when complete CompletionPort is notified.\n");
272
273static PyObject *
274overlapped_RegisterWaitWithQueue(PyObject *self, PyObject *args)
275{
276 HANDLE NewWaitObject;
277 HANDLE Object;
278 ULONG Milliseconds;
279 struct PostCallbackData data, *pdata;
280
281 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_POINTER F_DWORD,
282 &Object,
283 &data.CompletionPort,
284 &data.Overlapped,
285 &Milliseconds))
286 return NULL;
287
Victor Stinner6150f312016-03-16 23:25:02 +0100288 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
289 PostToQueueCallback() will call PyMem_Free() from a new C thread
290 which doesn't hold the GIL. */
291 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700292 if (pdata == NULL)
293 return SetFromWindowsErr(0);
294
295 *pdata = data;
296
297 if (!RegisterWaitForSingleObject(
298 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
299 pdata, Milliseconds,
300 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
301 {
Victor Stinner6150f312016-03-16 23:25:02 +0100302 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700303 return SetFromWindowsErr(0);
304 }
305
306 return Py_BuildValue(F_HANDLE, NewWaitObject);
307}
308
309PyDoc_STRVAR(
310 UnregisterWait_doc,
311 "UnregisterWait(WaitHandle) -> None\n\n"
312 "Unregister wait handle.\n");
313
314static PyObject *
315overlapped_UnregisterWait(PyObject *self, PyObject *args)
316{
317 HANDLE WaitHandle;
318 BOOL ret;
319
320 if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
321 return NULL;
322
323 Py_BEGIN_ALLOW_THREADS
324 ret = UnregisterWait(WaitHandle);
325 Py_END_ALLOW_THREADS
326
327 if (!ret)
328 return SetFromWindowsErr(0);
329 Py_RETURN_NONE;
330}
331
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100332PyDoc_STRVAR(
333 UnregisterWaitEx_doc,
334 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
335 "Unregister wait handle.\n");
336
337static PyObject *
338overlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
339{
340 HANDLE WaitHandle, Event;
341 BOOL ret;
342
343 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
344 return NULL;
345
346 Py_BEGIN_ALLOW_THREADS
347 ret = UnregisterWaitEx(WaitHandle, Event);
348 Py_END_ALLOW_THREADS
349
350 if (!ret)
351 return SetFromWindowsErr(0);
352 Py_RETURN_NONE;
353}
354
Guido van Rossum90fb9142013-10-30 14:44:05 -0700355/*
356 * Event functions -- currently only used by tests
357 */
358
359PyDoc_STRVAR(
360 CreateEvent_doc,
361 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
362 " -> Handle\n\n"
363 "Create an event. EventAttributes must be None.\n");
364
365static PyObject *
366overlapped_CreateEvent(PyObject *self, PyObject *args)
367{
368 PyObject *EventAttributes;
369 BOOL ManualReset;
370 BOOL InitialState;
371 Py_UNICODE *Name;
372 HANDLE Event;
373
374 if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
375 &EventAttributes, &ManualReset,
376 &InitialState, &Name))
377 return NULL;
378
379 if (EventAttributes != Py_None) {
380 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
381 return NULL;
382 }
383
384 Py_BEGIN_ALLOW_THREADS
385 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
386 Py_END_ALLOW_THREADS
387
388 if (Event == NULL)
389 return SetFromWindowsErr(0);
390 return Py_BuildValue(F_HANDLE, Event);
391}
392
393PyDoc_STRVAR(
394 SetEvent_doc,
395 "SetEvent(Handle) -> None\n\n"
396 "Set event.\n");
397
398static PyObject *
399overlapped_SetEvent(PyObject *self, PyObject *args)
400{
401 HANDLE Handle;
402 BOOL ret;
403
404 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
405 return NULL;
406
407 Py_BEGIN_ALLOW_THREADS
408 ret = SetEvent(Handle);
409 Py_END_ALLOW_THREADS
410
411 if (!ret)
412 return SetFromWindowsErr(0);
413 Py_RETURN_NONE;
414}
415
416PyDoc_STRVAR(
417 ResetEvent_doc,
418 "ResetEvent(Handle) -> None\n\n"
419 "Reset event.\n");
420
421static PyObject *
422overlapped_ResetEvent(PyObject *self, PyObject *args)
423{
424 HANDLE Handle;
425 BOOL ret;
426
427 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
428 return NULL;
429
430 Py_BEGIN_ALLOW_THREADS
431 ret = ResetEvent(Handle);
432 Py_END_ALLOW_THREADS
433
434 if (!ret)
435 return SetFromWindowsErr(0);
436 Py_RETURN_NONE;
437}
438
439/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700440 * Bind socket handle to local port without doing slow getaddrinfo()
441 */
442
443PyDoc_STRVAR(
444 BindLocal_doc,
445 "BindLocal(handle, family) -> None\n\n"
446 "Bind a socket handle to an arbitrary local port.\n"
447 "family should AF_INET or AF_INET6.\n");
448
449static PyObject *
450overlapped_BindLocal(PyObject *self, PyObject *args)
451{
452 SOCKET Socket;
453 int Family;
454 BOOL ret;
455
456 if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
457 return NULL;
458
459 if (Family == AF_INET) {
460 struct sockaddr_in addr;
461 memset(&addr, 0, sizeof(addr));
462 addr.sin_family = AF_INET;
463 addr.sin_port = 0;
464 addr.sin_addr.S_un.S_addr = INADDR_ANY;
465 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
466 } else if (Family == AF_INET6) {
467 struct sockaddr_in6 addr;
468 memset(&addr, 0, sizeof(addr));
469 addr.sin6_family = AF_INET6;
470 addr.sin6_port = 0;
471 addr.sin6_addr = in6addr_any;
472 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
473 } else {
474 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
475 return NULL;
476 }
477
478 if (!ret)
479 return SetFromWindowsErr(WSAGetLastError());
480 Py_RETURN_NONE;
481}
482
483/*
484 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
485 */
486
487PyDoc_STRVAR(
488 FormatMessage_doc,
489 "FormatMessage(error_code) -> error_message\n\n"
490 "Return error message for an error code.");
491
492static PyObject *
493overlapped_FormatMessage(PyObject *ignore, PyObject *args)
494{
495 DWORD code, n;
496 WCHAR *lpMsgBuf;
497 PyObject *res;
498
499 if (!PyArg_ParseTuple(args, F_DWORD, &code))
500 return NULL;
501
502 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600503 FORMAT_MESSAGE_FROM_SYSTEM |
504 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700505 NULL,
506 code,
507 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
508 (LPWSTR) &lpMsgBuf,
509 0,
510 NULL);
511 if (n) {
512 while (iswspace(lpMsgBuf[n-1]))
513 --n;
514 lpMsgBuf[n] = L'\0';
515 res = Py_BuildValue("u", lpMsgBuf);
516 } else {
517 res = PyUnicode_FromFormat("unknown error code %u", code);
518 }
519 LocalFree(lpMsgBuf);
520 return res;
521}
522
523
524/*
525 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
526 */
527
528static void
529mark_as_completed(OVERLAPPED *ov)
530{
531 ov->Internal = 0;
532 if (ov->hEvent != NULL)
533 SetEvent(ov->hEvent);
534}
535
536/*
537 * A Python object wrapping an OVERLAPPED structure and other useful data
538 * for overlapped I/O
539 */
540
541PyDoc_STRVAR(
542 Overlapped_doc,
543 "Overlapped object");
544
545static PyObject *
546Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
547{
548 OverlappedObject *self;
549 HANDLE event = INVALID_HANDLE_VALUE;
550 static char *kwlist[] = {"event", NULL};
551
552 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
553 return NULL;
554
555 if (event == INVALID_HANDLE_VALUE) {
556 event = CreateEvent(NULL, TRUE, FALSE, NULL);
557 if (event == NULL)
558 return SetFromWindowsErr(0);
559 }
560
561 self = PyObject_New(OverlappedObject, type);
562 if (self == NULL) {
563 if (event != NULL)
564 CloseHandle(event);
565 return NULL;
566 }
567
568 self->handle = NULL;
569 self->error = 0;
570 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200571 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700572 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200573 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700574 if (event)
575 self->overlapped.hEvent = event;
576 return (PyObject *)self;
577}
578
Victor Stinner54850852019-01-11 14:35:14 +0100579
580/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
581 buffers while overlapped are still running, to prevent a crash. */
582static int
583Overlapped_clear(OverlappedObject *self)
584{
585 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300586 case TYPE_READ:
587 case TYPE_ACCEPT: {
588 Py_CLEAR(self->allocated_buffer);
589 break;
Victor Stinner54850852019-01-11 14:35:14 +0100590 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300591 case TYPE_READ_FROM: {
592 // An initial call to WSARecvFrom will only allocate the buffer.
593 // The result tuple of (message, address) is only
594 // allocated _after_ a message has been received.
595 if(self->read_from.result) {
596 // We've received a message, free the result tuple.
597 Py_CLEAR(self->read_from.result);
598 }
599 if(self->read_from.allocated_buffer) {
600 Py_CLEAR(self->read_from.allocated_buffer);
601 }
602 break;
603 }
604 case TYPE_WRITE:
605 case TYPE_WRITE_TO:
606 case TYPE_READINTO: {
607 if (self->user_buffer.obj) {
608 PyBuffer_Release(&self->user_buffer);
609 }
610 break;
611 }
Victor Stinner54850852019-01-11 14:35:14 +0100612 }
613 self->type = TYPE_NOT_STARTED;
614 return 0;
615}
616
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700617static void
618Overlapped_dealloc(OverlappedObject *self)
619{
620 DWORD bytes;
621 DWORD olderr = GetLastError();
622 BOOL wait = FALSE;
623 BOOL ret;
624
625 if (!HasOverlappedIoCompleted(&self->overlapped) &&
626 self->type != TYPE_NOT_STARTED)
627 {
628 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
629 wait = TRUE;
630
631 Py_BEGIN_ALLOW_THREADS
632 ret = GetOverlappedResult(self->handle, &self->overlapped,
633 &bytes, wait);
634 Py_END_ALLOW_THREADS
635
636 switch (ret ? ERROR_SUCCESS : GetLastError()) {
637 case ERROR_SUCCESS:
638 case ERROR_NOT_FOUND:
639 case ERROR_OPERATION_ABORTED:
640 break;
641 default:
642 PyErr_Format(
643 PyExc_RuntimeError,
644 "%R still has pending operation at "
645 "deallocation, the process may crash", self);
646 PyErr_WriteUnraisable(NULL);
647 }
648 }
649
Victor Stinner54850852019-01-11 14:35:14 +0100650 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700651 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700652 }
Victor Stinner54850852019-01-11 14:35:14 +0100653
654 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700655 PyObject_Del(self);
656 SetLastError(olderr);
657}
658
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300659
660/* Convert IPv4 sockaddr to a Python str. */
661
662static PyObject *
663make_ipv4_addr(const struct sockaddr_in *addr)
664{
665 char buf[INET_ADDRSTRLEN];
666 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
667 PyErr_SetFromErrno(PyExc_OSError);
668 return NULL;
669 }
670 return PyUnicode_FromString(buf);
671}
672
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300673/* Convert IPv6 sockaddr to a Python str. */
674
675static PyObject *
676make_ipv6_addr(const struct sockaddr_in6 *addr)
677{
678 char buf[INET6_ADDRSTRLEN];
679 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
680 PyErr_SetFromErrno(PyExc_OSError);
681 return NULL;
682 }
683 return PyUnicode_FromString(buf);
684}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300685
686static PyObject*
687unparse_address(LPSOCKADDR Address, DWORD Length)
688{
689 /* The function is adopted from mocketmodule.c makesockaddr()*/
690
691 switch(Address->sa_family) {
692 case AF_INET: {
693 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
694 PyObject *addrobj = make_ipv4_addr(a);
695 PyObject *ret = NULL;
696 if (addrobj) {
697 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
698 Py_DECREF(addrobj);
699 }
700 return ret;
701 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300702 case AF_INET6: {
703 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
704 PyObject *addrobj = make_ipv6_addr(a);
705 PyObject *ret = NULL;
706 if (addrobj) {
707 ret = Py_BuildValue("OiII",
708 addrobj,
709 ntohs(a->sin6_port),
710 ntohl(a->sin6_flowinfo),
711 a->sin6_scope_id);
712 Py_DECREF(addrobj);
713 }
714 return ret;
715 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300716 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200717 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
718 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300719 }
720 }
721}
722
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700723PyDoc_STRVAR(
724 Overlapped_cancel_doc,
725 "cancel() -> None\n\n"
726 "Cancel overlapped operation");
727
728static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530729Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700730{
731 BOOL ret = TRUE;
732
733 if (self->type == TYPE_NOT_STARTED
734 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
735 Py_RETURN_NONE;
736
737 if (!HasOverlappedIoCompleted(&self->overlapped)) {
738 Py_BEGIN_ALLOW_THREADS
739 if (Py_CancelIoEx)
740 ret = Py_CancelIoEx(self->handle, &self->overlapped);
741 else
742 ret = CancelIo(self->handle);
743 Py_END_ALLOW_THREADS
744 }
745
746 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
747 if (!ret && GetLastError() != ERROR_NOT_FOUND)
748 return SetFromWindowsErr(0);
749 Py_RETURN_NONE;
750}
751
752PyDoc_STRVAR(
753 Overlapped_getresult_doc,
754 "getresult(wait=False) -> result\n\n"
755 "Retrieve result of operation. If wait is true then it blocks\n"
756 "until the operation is finished. If wait is false and the\n"
757 "operation is still pending then an error is raised.");
758
759static PyObject *
760Overlapped_getresult(OverlappedObject *self, PyObject *args)
761{
762 BOOL wait = FALSE;
763 DWORD transferred = 0;
764 BOOL ret;
765 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300766 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700767
768 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
769 return NULL;
770
771 if (self->type == TYPE_NONE) {
772 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
773 return NULL;
774 }
775
776 if (self->type == TYPE_NOT_STARTED) {
777 PyErr_SetString(PyExc_ValueError, "operation failed to start");
778 return NULL;
779 }
780
781 Py_BEGIN_ALLOW_THREADS
782 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
783 wait);
784 Py_END_ALLOW_THREADS
785
786 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
787 switch (err) {
788 case ERROR_SUCCESS:
789 case ERROR_MORE_DATA:
790 break;
791 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300792 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700793 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300794 }
795 else if (self->type == TYPE_READ_FROM &&
796 (self->read_from.result != NULL ||
797 self->read_from.allocated_buffer != NULL))
798 {
799 break;
800 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700801 /* fall through */
802 default:
803 return SetFromWindowsErr(err);
804 }
805
806 switch (self->type) {
807 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200808 assert(PyBytes_CheckExact(self->allocated_buffer));
809 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
810 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700811 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300812
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200813 Py_INCREF(self->allocated_buffer);
814 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300815 case TYPE_READ_FROM:
816 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
817
818 if (transferred != PyBytes_GET_SIZE(
819 self->read_from.allocated_buffer) &&
820 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
821 {
822 return NULL;
823 }
824
825 // unparse the address
826 addr = unparse_address((SOCKADDR*)&self->read_from.address,
827 self->read_from.address_length);
828
829 if (addr == NULL) {
830 return NULL;
831 }
832
833 // The result is a two item tuple: (message, address)
834 self->read_from.result = PyTuple_New(2);
835 if (self->read_from.result == NULL) {
836 Py_CLEAR(addr);
837 return NULL;
838 }
839
840 // first item: message
841 Py_INCREF(self->read_from.allocated_buffer);
842 PyTuple_SET_ITEM(self->read_from.result, 0,
843 self->read_from.allocated_buffer);
844 // second item: address
845 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
846
847 Py_INCREF(self->read_from.result);
848 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700849 default:
850 return PyLong_FromUnsignedLong((unsigned long) transferred);
851 }
852}
853
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200854static PyObject *
855do_ReadFile(OverlappedObject *self, HANDLE handle,
856 char *bufstart, DWORD buflen)
857{
858 DWORD nread;
859 int ret;
860 DWORD err;
861
862 Py_BEGIN_ALLOW_THREADS
863 ret = ReadFile(handle, bufstart, buflen, &nread,
864 &self->overlapped);
865 Py_END_ALLOW_THREADS
866
867 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
868 switch (err) {
869 case ERROR_BROKEN_PIPE:
870 mark_as_completed(&self->overlapped);
871 return SetFromWindowsErr(err);
872 case ERROR_SUCCESS:
873 case ERROR_MORE_DATA:
874 case ERROR_IO_PENDING:
875 Py_RETURN_NONE;
876 default:
Victor Stinner54850852019-01-11 14:35:14 +0100877 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200878 return SetFromWindowsErr(err);
879 }
880}
881
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700882PyDoc_STRVAR(
883 Overlapped_ReadFile_doc,
884 "ReadFile(handle, size) -> Overlapped[message]\n\n"
885 "Start overlapped read");
886
887static PyObject *
888Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
889{
890 HANDLE handle;
891 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700892 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700893
894 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
895 return NULL;
896
897 if (self->type != TYPE_NONE) {
898 PyErr_SetString(PyExc_ValueError, "operation already attempted");
899 return NULL;
900 }
901
902#if SIZEOF_SIZE_T <= SIZEOF_LONG
903 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
904#endif
905 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
906 if (buf == NULL)
907 return NULL;
908
909 self->type = TYPE_READ;
910 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200911 self->allocated_buffer = buf;
912
913 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
914}
915
916PyDoc_STRVAR(
917 Overlapped_ReadFileInto_doc,
918 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
919 "Start overlapped receive");
920
921static PyObject *
922Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
923{
924 HANDLE handle;
925 PyObject *bufobj;
926
927 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
928 return NULL;
929
930 if (self->type != TYPE_NONE) {
931 PyErr_SetString(PyExc_ValueError, "operation already attempted");
932 return NULL;
933 }
934
935 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
936 return NULL;
937
938#if SIZEOF_SIZE_T > SIZEOF_LONG
939 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
940 PyBuffer_Release(&self->user_buffer);
941 PyErr_SetString(PyExc_ValueError, "buffer too large");
942 return NULL;
943 }
944#endif
945
946 self->type = TYPE_READINTO;
947 self->handle = handle;
948
949 return do_ReadFile(self, handle, self->user_buffer.buf,
950 (DWORD)self->user_buffer.len);
951}
952
953static PyObject *
954do_WSARecv(OverlappedObject *self, HANDLE handle,
955 char *bufstart, DWORD buflen, DWORD flags)
956{
957 DWORD nread;
958 WSABUF wsabuf;
959 int ret;
960 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300961
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200962 wsabuf.buf = bufstart;
963 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700964
965 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200966 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
967 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700968 Py_END_ALLOW_THREADS
969
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200970 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700971 switch (err) {
972 case ERROR_BROKEN_PIPE:
973 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100974 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700975 case ERROR_SUCCESS:
976 case ERROR_MORE_DATA:
977 case ERROR_IO_PENDING:
978 Py_RETURN_NONE;
979 default:
Victor Stinner54850852019-01-11 14:35:14 +0100980 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700981 return SetFromWindowsErr(err);
982 }
983}
984
985PyDoc_STRVAR(
986 Overlapped_WSARecv_doc,
987 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
988 "Start overlapped receive");
989
990static PyObject *
991Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
992{
993 HANDLE handle;
994 DWORD size;
995 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700996 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700997
998 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
999 &handle, &size, &flags))
1000 return NULL;
1001
1002 if (self->type != TYPE_NONE) {
1003 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1004 return NULL;
1005 }
1006
1007#if SIZEOF_SIZE_T <= SIZEOF_LONG
1008 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1009#endif
1010 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1011 if (buf == NULL)
1012 return NULL;
1013
1014 self->type = TYPE_READ;
1015 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001016 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001017
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001018 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1019}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001020
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001021PyDoc_STRVAR(
1022 Overlapped_WSARecvInto_doc,
1023 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
1024 "Start overlapped receive");
1025
1026static PyObject *
1027Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
1028{
1029 HANDLE handle;
1030 PyObject *bufobj;
1031 DWORD flags;
1032
1033 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
1034 &handle, &bufobj, &flags))
1035 return NULL;
1036
1037 if (self->type != TYPE_NONE) {
1038 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1039 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001040 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001041
1042 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1043 return NULL;
1044
1045#if SIZEOF_SIZE_T > SIZEOF_LONG
1046 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1047 PyBuffer_Release(&self->user_buffer);
1048 PyErr_SetString(PyExc_ValueError, "buffer too large");
1049 return NULL;
1050 }
1051#endif
1052
1053 self->type = TYPE_READINTO;
1054 self->handle = handle;
1055
1056 return do_WSARecv(self, handle, self->user_buffer.buf,
1057 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001058}
1059
1060PyDoc_STRVAR(
1061 Overlapped_WriteFile_doc,
1062 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
1063 "Start overlapped write");
1064
1065static PyObject *
1066Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
1067{
1068 HANDLE handle;
1069 PyObject *bufobj;
1070 DWORD written;
1071 BOOL ret;
1072 DWORD err;
1073
1074 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
1075 return NULL;
1076
1077 if (self->type != TYPE_NONE) {
1078 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1079 return NULL;
1080 }
1081
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001082 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001083 return NULL;
1084
1085#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001086 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1087 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001088 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001089 return NULL;
1090 }
1091#endif
1092
1093 self->type = TYPE_WRITE;
1094 self->handle = handle;
1095
1096 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001097 ret = WriteFile(handle, self->user_buffer.buf,
1098 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001099 &written, &self->overlapped);
1100 Py_END_ALLOW_THREADS
1101
1102 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1103 switch (err) {
1104 case ERROR_SUCCESS:
1105 case ERROR_IO_PENDING:
1106 Py_RETURN_NONE;
1107 default:
Victor Stinner54850852019-01-11 14:35:14 +01001108 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001109 return SetFromWindowsErr(err);
1110 }
1111}
1112
1113PyDoc_STRVAR(
1114 Overlapped_WSASend_doc,
1115 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
1116 "Start overlapped send");
1117
1118static PyObject *
1119Overlapped_WSASend(OverlappedObject *self, PyObject *args)
1120{
1121 HANDLE handle;
1122 PyObject *bufobj;
1123 DWORD flags;
1124 DWORD written;
1125 WSABUF wsabuf;
1126 int ret;
1127 DWORD err;
1128
1129 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
1130 &handle, &bufobj, &flags))
1131 return NULL;
1132
1133 if (self->type != TYPE_NONE) {
1134 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1135 return NULL;
1136 }
1137
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001138 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001139 return NULL;
1140
1141#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001142 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1143 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001144 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001145 return NULL;
1146 }
1147#endif
1148
1149 self->type = TYPE_WRITE;
1150 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001151 wsabuf.len = (DWORD)self->user_buffer.len;
1152 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001153
1154 Py_BEGIN_ALLOW_THREADS
1155 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1156 &self->overlapped, NULL);
1157 Py_END_ALLOW_THREADS
1158
1159 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1160 switch (err) {
1161 case ERROR_SUCCESS:
1162 case ERROR_IO_PENDING:
1163 Py_RETURN_NONE;
1164 default:
Victor Stinner54850852019-01-11 14:35:14 +01001165 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001166 return SetFromWindowsErr(err);
1167 }
1168}
1169
1170PyDoc_STRVAR(
1171 Overlapped_AcceptEx_doc,
1172 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1173 "Start overlapped wait for client to connect");
1174
1175static PyObject *
1176Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1177{
1178 SOCKET ListenSocket;
1179 SOCKET AcceptSocket;
1180 DWORD BytesReceived;
1181 DWORD size;
1182 PyObject *buf;
1183 BOOL ret;
1184 DWORD err;
1185
1186 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1187 &ListenSocket, &AcceptSocket))
1188 return NULL;
1189
1190 if (self->type != TYPE_NONE) {
1191 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1192 return NULL;
1193 }
1194
1195 size = sizeof(struct sockaddr_in6) + 16;
1196 buf = PyBytes_FromStringAndSize(NULL, size*2);
1197 if (!buf)
1198 return NULL;
1199
1200 self->type = TYPE_ACCEPT;
1201 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001202 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001203
1204 Py_BEGIN_ALLOW_THREADS
1205 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1206 0, size, size, &BytesReceived, &self->overlapped);
1207 Py_END_ALLOW_THREADS
1208
1209 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1210 switch (err) {
1211 case ERROR_SUCCESS:
1212 case ERROR_IO_PENDING:
1213 Py_RETURN_NONE;
1214 default:
Victor Stinner54850852019-01-11 14:35:14 +01001215 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001216 return SetFromWindowsErr(err);
1217 }
1218}
1219
1220
1221static int
1222parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1223{
Steve Dowercc16be82016-09-08 10:35:16 -07001224 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001225 unsigned short Port;
1226 unsigned long FlowInfo;
1227 unsigned long ScopeId;
1228
1229 memset(Address, 0, Length);
1230
Steve Dowercc16be82016-09-08 10:35:16 -07001231 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001232 {
1233 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001234 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001235 SetFromWindowsErr(WSAGetLastError());
1236 return -1;
1237 }
1238 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1239 return Length;
1240 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001241 else if (PyArg_ParseTuple(obj,
1242 "uHkk;ConnectEx(): illegal address_as_bytes "
1243 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001244 {
1245 PyErr_Clear();
1246 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001247 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001248 SetFromWindowsErr(WSAGetLastError());
1249 return -1;
1250 }
1251 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1252 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1253 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1254 return Length;
1255 }
1256
1257 return -1;
1258}
1259
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001260PyDoc_STRVAR(
1261 Overlapped_ConnectEx_doc,
1262 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1263 "Start overlapped connect. client_handle should be unbound.");
1264
1265static PyObject *
1266Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1267{
1268 SOCKET ConnectSocket;
1269 PyObject *AddressObj;
1270 char AddressBuf[sizeof(struct sockaddr_in6)];
1271 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1272 int Length;
1273 BOOL ret;
1274 DWORD err;
1275
Oren Milman1d1d3e92017-08-20 18:35:36 +03001276 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1277 &ConnectSocket, &PyTuple_Type, &AddressObj))
1278 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001279 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001280 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001281
1282 if (self->type != TYPE_NONE) {
1283 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1284 return NULL;
1285 }
1286
1287 Length = sizeof(AddressBuf);
1288 Length = parse_address(AddressObj, Address, Length);
1289 if (Length < 0)
1290 return NULL;
1291
1292 self->type = TYPE_CONNECT;
1293 self->handle = (HANDLE)ConnectSocket;
1294
1295 Py_BEGIN_ALLOW_THREADS
1296 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1297 NULL, 0, NULL, &self->overlapped);
1298 Py_END_ALLOW_THREADS
1299
1300 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1301 switch (err) {
1302 case ERROR_SUCCESS:
1303 case ERROR_IO_PENDING:
1304 Py_RETURN_NONE;
1305 default:
Victor Stinner54850852019-01-11 14:35:14 +01001306 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001307 return SetFromWindowsErr(err);
1308 }
1309}
1310
1311PyDoc_STRVAR(
1312 Overlapped_DisconnectEx_doc,
1313 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1314 "Start overlapped connect. client_handle should be unbound.");
1315
1316static PyObject *
1317Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1318{
1319 SOCKET Socket;
1320 DWORD flags;
1321 BOOL ret;
1322 DWORD err;
1323
1324 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1325 return NULL;
1326
1327 if (self->type != TYPE_NONE) {
1328 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1329 return NULL;
1330 }
1331
1332 self->type = TYPE_DISCONNECT;
1333 self->handle = (HANDLE)Socket;
1334
1335 Py_BEGIN_ALLOW_THREADS
1336 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1337 Py_END_ALLOW_THREADS
1338
1339 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1340 switch (err) {
1341 case ERROR_SUCCESS:
1342 case ERROR_IO_PENDING:
1343 Py_RETURN_NONE;
1344 default:
Victor Stinner54850852019-01-11 14:35:14 +01001345 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001346 return SetFromWindowsErr(err);
1347 }
1348}
1349
1350PyDoc_STRVAR(
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001351 Overlapped_TransmitFile_doc,
1352 "TransmitFile(socket, file, offset, offset_high, "
1353 "count_to_write, count_per_send, flags) "
1354 "-> Overlapped[None]\n\n"
1355 "Transmit file data over a connected socket.");
1356
1357static PyObject *
1358Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
1359{
1360 SOCKET Socket;
1361 HANDLE File;
1362 DWORD offset;
1363 DWORD offset_high;
1364 DWORD count_to_write;
1365 DWORD count_per_send;
1366 DWORD flags;
1367 BOOL ret;
1368 DWORD err;
1369
1370 if (!PyArg_ParseTuple(args,
1371 F_HANDLE F_HANDLE F_DWORD F_DWORD
1372 F_DWORD F_DWORD F_DWORD,
1373 &Socket, &File, &offset, &offset_high,
1374 &count_to_write, &count_per_send,
1375 &flags))
1376 return NULL;
1377
1378 if (self->type != TYPE_NONE) {
1379 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1380 return NULL;
1381 }
1382
1383 self->type = TYPE_TRANSMIT_FILE;
1384 self->handle = (HANDLE)Socket;
1385 self->overlapped.Offset = offset;
1386 self->overlapped.OffsetHigh = offset_high;
1387
1388 Py_BEGIN_ALLOW_THREADS
1389 ret = Py_TransmitFile(Socket, File, count_to_write, count_per_send,
1390 &self->overlapped,
1391 NULL, flags);
1392 Py_END_ALLOW_THREADS
1393
1394 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1395 switch (err) {
1396 case ERROR_SUCCESS:
1397 case ERROR_IO_PENDING:
1398 Py_RETURN_NONE;
1399 default:
Victor Stinner54850852019-01-11 14:35:14 +01001400 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001401 return SetFromWindowsErr(err);
1402 }
1403}
1404
1405PyDoc_STRVAR(
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001406 Overlapped_ConnectNamedPipe_doc,
1407 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1408 "Start overlapped wait for a client to connect.");
1409
1410static PyObject *
1411Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1412{
1413 HANDLE Pipe;
1414 BOOL ret;
1415 DWORD err;
1416
1417 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1418 return NULL;
1419
1420 if (self->type != TYPE_NONE) {
1421 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1422 return NULL;
1423 }
1424
1425 self->type = TYPE_CONNECT_NAMED_PIPE;
1426 self->handle = Pipe;
1427
1428 Py_BEGIN_ALLOW_THREADS
1429 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1430 Py_END_ALLOW_THREADS
1431
1432 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1433 switch (err) {
1434 case ERROR_PIPE_CONNECTED:
1435 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001436 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001437 case ERROR_SUCCESS:
1438 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001439 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001440 default:
Victor Stinner54850852019-01-11 14:35:14 +01001441 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001442 return SetFromWindowsErr(err);
1443 }
1444}
1445
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001446PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001447 ConnectPipe_doc,
1448 "ConnectPipe(addr) -> pipe_handle\n\n"
1449 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001450
1451static PyObject *
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001452overlapped_ConnectPipe(PyObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001453{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001454 PyObject *AddressObj;
1455 wchar_t *Address;
1456 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001457
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001458 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001459 return NULL;
1460
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001461 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1462 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001463 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001464
Victor Stinner498b1f62015-01-26 22:43:39 +01001465 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001466 PipeHandle = CreateFileW(Address,
1467 GENERIC_READ | GENERIC_WRITE,
1468 0, NULL, OPEN_EXISTING,
1469 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001470 Py_END_ALLOW_THREADS
1471
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001472 PyMem_Free(Address);
1473 if (PipeHandle == INVALID_HANDLE_VALUE)
1474 return SetFromWindowsErr(0);
1475 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001476}
1477
1478static PyObject*
1479Overlapped_getaddress(OverlappedObject *self)
1480{
1481 return PyLong_FromVoidPtr(&self->overlapped);
1482}
1483
1484static PyObject*
1485Overlapped_getpending(OverlappedObject *self)
1486{
1487 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1488 self->type != TYPE_NOT_STARTED);
1489}
1490
Victor Stinner54850852019-01-11 14:35:14 +01001491static int
1492Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1493{
1494 switch (self->type) {
1495 case TYPE_READ:
1496 case TYPE_ACCEPT:
1497 Py_VISIT(self->allocated_buffer);
1498 break;
1499 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001500 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001501 case TYPE_READINTO:
1502 if (self->user_buffer.obj) {
1503 Py_VISIT(&self->user_buffer.obj);
1504 }
1505 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001506 case TYPE_READ_FROM:
Hai Shi47a23fc2020-06-07 20:05:36 +08001507 Py_VISIT(self->read_from.result);
1508 Py_VISIT(self->read_from.allocated_buffer);
Victor Stinner54850852019-01-11 14:35:14 +01001509 }
1510 return 0;
1511}
1512
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001513// UDP functions
1514
1515PyDoc_STRVAR(
1516 WSAConnect_doc,
1517 "WSAConnect(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1518 "Bind a remote address to a connectionless (UDP) socket");
1519
1520/*
1521 * Note: WSAConnect does not support Overlapped I/O so this function should
1522 * _only_ be used for connectionless sockets (UDP).
1523 */
1524static PyObject *
1525overlapped_WSAConnect(PyObject *self, PyObject *args)
1526{
1527 SOCKET ConnectSocket;
1528 PyObject *AddressObj;
1529 char AddressBuf[sizeof(struct sockaddr_in6)];
1530 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1531 int Length;
1532 int err;
1533
1534 if (!PyArg_ParseTuple(args, F_HANDLE "O", &ConnectSocket, &AddressObj)) {
1535 return NULL;
1536 }
1537
1538 Length = sizeof(AddressBuf);
1539 Length = parse_address(AddressObj, Address, Length);
1540 if (Length < 0) {
1541 return NULL;
1542 }
1543
1544 Py_BEGIN_ALLOW_THREADS
1545 // WSAConnect does not support overlapped I/O so this call will
1546 // successfully complete immediately.
1547 err = WSAConnect(ConnectSocket, Address, Length,
1548 NULL, NULL, NULL, NULL);
1549 Py_END_ALLOW_THREADS
1550
1551 if (err == 0) {
1552 Py_RETURN_NONE;
1553 }
1554 else {
1555 return SetFromWindowsErr(WSAGetLastError());
1556 }
1557}
1558
1559PyDoc_STRVAR(
1560 Overlapped_WSASendTo_doc,
1561 "WSASendTo(handle, buf, flags, address_as_bytes) -> "
1562 "Overlapped[bytes_transferred]\n\n"
1563 "Start overlapped sendto over a connectionless (UDP) socket");
1564
1565static PyObject *
1566Overlapped_WSASendTo(OverlappedObject *self, PyObject *args)
1567{
1568 HANDLE handle;
1569 PyObject *bufobj;
1570 DWORD flags;
1571 PyObject *AddressObj;
1572 char AddressBuf[sizeof(struct sockaddr_in6)];
1573 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1574 int AddressLength;
1575 DWORD written;
1576 WSABUF wsabuf;
1577 int ret;
1578 DWORD err;
1579
1580 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD "O",
1581 &handle, &bufobj, &flags, &AddressObj))
1582 {
1583 return NULL;
1584 }
1585
1586 // Parse the "to" address
1587 AddressLength = sizeof(AddressBuf);
1588 AddressLength = parse_address(AddressObj, Address, AddressLength);
1589 if (AddressLength < 0) {
1590 return NULL;
1591 }
1592
1593 if (self->type != TYPE_NONE) {
1594 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1595 return NULL;
1596 }
1597
1598 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1599 return NULL;
1600 }
1601
1602#if SIZEOF_SIZE_T > SIZEOF_LONG
1603 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1604 PyBuffer_Release(&self->user_buffer);
1605 PyErr_SetString(PyExc_ValueError, "buffer too large");
1606 return NULL;
1607 }
1608#endif
1609
1610 self->type = TYPE_WRITE_TO;
1611 self->handle = handle;
1612 wsabuf.len = (DWORD)self->user_buffer.len;
1613 wsabuf.buf = self->user_buffer.buf;
1614
1615 Py_BEGIN_ALLOW_THREADS
1616 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1617 Address, AddressLength, &self->overlapped, NULL);
1618 Py_END_ALLOW_THREADS
1619
1620 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1621 ERROR_SUCCESS);
1622
1623 switch(err) {
1624 case ERROR_SUCCESS:
1625 case ERROR_IO_PENDING:
1626 Py_RETURN_NONE;
1627 default:
1628 self->type = TYPE_NOT_STARTED;
1629 return SetFromWindowsErr(err);
1630 }
1631}
1632
1633
1634
1635PyDoc_STRVAR(
1636 Overlapped_WSARecvFrom_doc,
1637 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1638 "Start overlapped receive");
1639
1640static PyObject *
1641Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *args)
1642{
1643 HANDLE handle;
1644 DWORD size;
1645 DWORD flags = 0;
1646 DWORD nread;
1647 PyObject *buf;
1648 WSABUF wsabuf;
1649 int ret;
1650 DWORD err;
1651
1652 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
1653 &handle, &size, &flags))
1654 {
1655 return NULL;
1656 }
1657
1658 if (self->type != TYPE_NONE) {
1659 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1660 return NULL;
1661 }
1662
1663#if SIZEOF_SIZE_T <= SIZEOF_LONG
1664 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1665#endif
1666 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1667 if (buf == NULL) {
1668 return NULL;
1669 }
1670
1671 wsabuf.len = size;
1672 wsabuf.buf = PyBytes_AS_STRING(buf);
1673
1674 self->type = TYPE_READ_FROM;
1675 self->handle = handle;
1676 self->read_from.allocated_buffer = buf;
1677 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1678 self->read_from.address_length = sizeof(self->read_from.address);
1679
1680 Py_BEGIN_ALLOW_THREADS
1681 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1682 (SOCKADDR*)&self->read_from.address,
1683 &self->read_from.address_length,
1684 &self->overlapped, NULL);
1685 Py_END_ALLOW_THREADS
1686
1687 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1688
1689 switch(err) {
1690 case ERROR_BROKEN_PIPE:
1691 mark_as_completed(&self->overlapped);
1692 return SetFromWindowsErr(err);
1693 case ERROR_SUCCESS:
1694 case ERROR_MORE_DATA:
1695 case ERROR_IO_PENDING:
1696 Py_RETURN_NONE;
1697 default:
1698 self->type = TYPE_NOT_STARTED;
1699 return SetFromWindowsErr(err);
1700 }
1701}
1702
Victor Stinner54850852019-01-11 14:35:14 +01001703
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001704static PyMethodDef Overlapped_methods[] = {
1705 {"getresult", (PyCFunction) Overlapped_getresult,
1706 METH_VARARGS, Overlapped_getresult_doc},
1707 {"cancel", (PyCFunction) Overlapped_cancel,
1708 METH_NOARGS, Overlapped_cancel_doc},
1709 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1710 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001711 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1712 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001713 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1714 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001715 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1716 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001717 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1718 METH_VARARGS, Overlapped_WriteFile_doc},
1719 {"WSASend", (PyCFunction) Overlapped_WSASend,
1720 METH_VARARGS, Overlapped_WSASend_doc},
1721 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1722 METH_VARARGS, Overlapped_AcceptEx_doc},
1723 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1724 METH_VARARGS, Overlapped_ConnectEx_doc},
1725 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1726 METH_VARARGS, Overlapped_DisconnectEx_doc},
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001727 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1728 METH_VARARGS, Overlapped_TransmitFile_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001729 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1730 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001731 {"WSARecvFrom", (PyCFunction) Overlapped_WSARecvFrom,
1732 METH_VARARGS, Overlapped_WSARecvFrom_doc },
1733 {"WSASendTo", (PyCFunction) Overlapped_WSASendTo,
1734 METH_VARARGS, Overlapped_WSASendTo_doc },
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001735 {NULL}
1736};
1737
1738static PyMemberDef Overlapped_members[] = {
1739 {"error", T_ULONG,
1740 offsetof(OverlappedObject, error),
1741 READONLY, "Error from last operation"},
1742 {"event", T_HANDLE,
1743 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1744 READONLY, "Overlapped event handle"},
1745 {NULL}
1746};
1747
1748static PyGetSetDef Overlapped_getsets[] = {
1749 {"address", (getter)Overlapped_getaddress, NULL,
1750 "Address of overlapped structure"},
1751 {"pending", (getter)Overlapped_getpending, NULL,
1752 "Whether the operation is pending"},
1753 {NULL},
1754};
1755
1756PyTypeObject OverlappedType = {
1757 PyVarObject_HEAD_INIT(NULL, 0)
1758 /* tp_name */ "_overlapped.Overlapped",
1759 /* tp_basicsize */ sizeof(OverlappedObject),
1760 /* tp_itemsize */ 0,
1761 /* tp_dealloc */ (destructor) Overlapped_dealloc,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001762 /* tp_vectorcall_offset */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001763 /* tp_getattr */ 0,
1764 /* tp_setattr */ 0,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001765 /* tp_as_async */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001766 /* tp_repr */ 0,
1767 /* tp_as_number */ 0,
1768 /* tp_as_sequence */ 0,
1769 /* tp_as_mapping */ 0,
1770 /* tp_hash */ 0,
1771 /* tp_call */ 0,
1772 /* tp_str */ 0,
1773 /* tp_getattro */ 0,
1774 /* tp_setattro */ 0,
1775 /* tp_as_buffer */ 0,
1776 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1777 /* tp_doc */ "OVERLAPPED structure wrapper",
Victor Stinner54850852019-01-11 14:35:14 +01001778 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001779 /* tp_clear */ 0,
1780 /* tp_richcompare */ 0,
1781 /* tp_weaklistoffset */ 0,
1782 /* tp_iter */ 0,
1783 /* tp_iternext */ 0,
1784 /* tp_methods */ Overlapped_methods,
1785 /* tp_members */ Overlapped_members,
1786 /* tp_getset */ Overlapped_getsets,
1787 /* tp_base */ 0,
1788 /* tp_dict */ 0,
1789 /* tp_descr_get */ 0,
1790 /* tp_descr_set */ 0,
1791 /* tp_dictoffset */ 0,
1792 /* tp_init */ 0,
1793 /* tp_alloc */ 0,
1794 /* tp_new */ Overlapped_new,
1795};
1796
1797static PyMethodDef overlapped_functions[] = {
1798 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1799 METH_VARARGS, CreateIoCompletionPort_doc},
1800 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1801 METH_VARARGS, GetQueuedCompletionStatus_doc},
1802 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1803 METH_VARARGS, PostQueuedCompletionStatus_doc},
1804 {"FormatMessage", overlapped_FormatMessage,
1805 METH_VARARGS, FormatMessage_doc},
1806 {"BindLocal", overlapped_BindLocal,
1807 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001808 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1809 METH_VARARGS, RegisterWaitWithQueue_doc},
1810 {"UnregisterWait", overlapped_UnregisterWait,
1811 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001812 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1813 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001814 {"CreateEvent", overlapped_CreateEvent,
1815 METH_VARARGS, CreateEvent_doc},
1816 {"SetEvent", overlapped_SetEvent,
1817 METH_VARARGS, SetEvent_doc},
1818 {"ResetEvent", overlapped_ResetEvent,
1819 METH_VARARGS, ResetEvent_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001820 {"ConnectPipe", overlapped_ConnectPipe,
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001821 METH_VARARGS, ConnectPipe_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001822 {"WSAConnect", overlapped_WSAConnect,
1823 METH_VARARGS, WSAConnect_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001824 {NULL}
1825};
1826
1827static struct PyModuleDef overlapped_module = {
1828 PyModuleDef_HEAD_INIT,
1829 "_overlapped",
1830 NULL,
1831 -1,
1832 overlapped_functions,
1833 NULL,
1834 NULL,
1835 NULL,
1836 NULL
1837};
1838
1839#define WINAPI_CONSTANT(fmt, con) \
1840 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1841
1842PyMODINIT_FUNC
1843PyInit__overlapped(void)
1844{
1845 PyObject *m, *d;
1846
1847 /* Ensure WSAStartup() called before initializing function pointers */
1848 m = PyImport_ImportModule("_socket");
1849 if (!m)
1850 return NULL;
1851 Py_DECREF(m);
1852
1853 if (initialize_function_pointers() < 0)
1854 return NULL;
1855
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001856 m = PyModule_Create(&overlapped_module);
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001857 if (PyModule_AddType(m, &OverlappedType) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001858 return NULL;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001859 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001860
1861 d = PyModule_GetDict(m);
1862
1863 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1864 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001865 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001866 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001867 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001868 WINAPI_CONSTANT(F_DWORD, INFINITE);
1869 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1870 WINAPI_CONSTANT(F_HANDLE, NULL);
1871 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1872 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1873 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1874
1875 return m;
1876}