blob: cd7869fa8aab0ab370cf379ae18767b9ec521954 [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
Miss Islington (bot)4a02da42020-07-15 12:25:59 -0700257PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
Guido van Rossum90fb9142013-10-30 14:44:05 -0700258{
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(
Miss Islington (bot)4a02da42020-07-15 12:25:59 -0700298 &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
Guido van Rossum90fb9142013-10-30 14:44:05 -0700299 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
300 {
Victor Stinner6150f312016-03-16 23:25:02 +0100301 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700302 return SetFromWindowsErr(0);
303 }
304
305 return Py_BuildValue(F_HANDLE, NewWaitObject);
306}
307
308PyDoc_STRVAR(
309 UnregisterWait_doc,
310 "UnregisterWait(WaitHandle) -> None\n\n"
311 "Unregister wait handle.\n");
312
313static PyObject *
314overlapped_UnregisterWait(PyObject *self, PyObject *args)
315{
316 HANDLE WaitHandle;
317 BOOL ret;
318
319 if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
320 return NULL;
321
322 Py_BEGIN_ALLOW_THREADS
323 ret = UnregisterWait(WaitHandle);
324 Py_END_ALLOW_THREADS
325
326 if (!ret)
327 return SetFromWindowsErr(0);
328 Py_RETURN_NONE;
329}
330
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100331PyDoc_STRVAR(
332 UnregisterWaitEx_doc,
333 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
334 "Unregister wait handle.\n");
335
336static PyObject *
337overlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
338{
339 HANDLE WaitHandle, Event;
340 BOOL ret;
341
342 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
343 return NULL;
344
345 Py_BEGIN_ALLOW_THREADS
346 ret = UnregisterWaitEx(WaitHandle, Event);
347 Py_END_ALLOW_THREADS
348
349 if (!ret)
350 return SetFromWindowsErr(0);
351 Py_RETURN_NONE;
352}
353
Guido van Rossum90fb9142013-10-30 14:44:05 -0700354/*
355 * Event functions -- currently only used by tests
356 */
357
358PyDoc_STRVAR(
359 CreateEvent_doc,
360 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
361 " -> Handle\n\n"
362 "Create an event. EventAttributes must be None.\n");
363
364static PyObject *
365overlapped_CreateEvent(PyObject *self, PyObject *args)
366{
367 PyObject *EventAttributes;
368 BOOL ManualReset;
369 BOOL InitialState;
370 Py_UNICODE *Name;
371 HANDLE Event;
372
373 if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
374 &EventAttributes, &ManualReset,
375 &InitialState, &Name))
376 return NULL;
377
378 if (EventAttributes != Py_None) {
379 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
380 return NULL;
381 }
382
383 Py_BEGIN_ALLOW_THREADS
384 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
385 Py_END_ALLOW_THREADS
386
387 if (Event == NULL)
388 return SetFromWindowsErr(0);
389 return Py_BuildValue(F_HANDLE, Event);
390}
391
392PyDoc_STRVAR(
393 SetEvent_doc,
394 "SetEvent(Handle) -> None\n\n"
395 "Set event.\n");
396
397static PyObject *
398overlapped_SetEvent(PyObject *self, PyObject *args)
399{
400 HANDLE Handle;
401 BOOL ret;
402
403 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
404 return NULL;
405
406 Py_BEGIN_ALLOW_THREADS
407 ret = SetEvent(Handle);
408 Py_END_ALLOW_THREADS
409
410 if (!ret)
411 return SetFromWindowsErr(0);
412 Py_RETURN_NONE;
413}
414
415PyDoc_STRVAR(
416 ResetEvent_doc,
417 "ResetEvent(Handle) -> None\n\n"
418 "Reset event.\n");
419
420static PyObject *
421overlapped_ResetEvent(PyObject *self, PyObject *args)
422{
423 HANDLE Handle;
424 BOOL ret;
425
426 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
427 return NULL;
428
429 Py_BEGIN_ALLOW_THREADS
430 ret = ResetEvent(Handle);
431 Py_END_ALLOW_THREADS
432
433 if (!ret)
434 return SetFromWindowsErr(0);
435 Py_RETURN_NONE;
436}
437
438/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700439 * Bind socket handle to local port without doing slow getaddrinfo()
440 */
441
442PyDoc_STRVAR(
443 BindLocal_doc,
444 "BindLocal(handle, family) -> None\n\n"
445 "Bind a socket handle to an arbitrary local port.\n"
446 "family should AF_INET or AF_INET6.\n");
447
448static PyObject *
449overlapped_BindLocal(PyObject *self, PyObject *args)
450{
451 SOCKET Socket;
452 int Family;
453 BOOL ret;
454
455 if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
456 return NULL;
457
458 if (Family == AF_INET) {
459 struct sockaddr_in addr;
460 memset(&addr, 0, sizeof(addr));
461 addr.sin_family = AF_INET;
462 addr.sin_port = 0;
463 addr.sin_addr.S_un.S_addr = INADDR_ANY;
464 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
465 } else if (Family == AF_INET6) {
466 struct sockaddr_in6 addr;
467 memset(&addr, 0, sizeof(addr));
468 addr.sin6_family = AF_INET6;
469 addr.sin6_port = 0;
470 addr.sin6_addr = in6addr_any;
471 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
472 } else {
473 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
474 return NULL;
475 }
476
477 if (!ret)
478 return SetFromWindowsErr(WSAGetLastError());
479 Py_RETURN_NONE;
480}
481
482/*
483 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
484 */
485
486PyDoc_STRVAR(
487 FormatMessage_doc,
488 "FormatMessage(error_code) -> error_message\n\n"
489 "Return error message for an error code.");
490
491static PyObject *
492overlapped_FormatMessage(PyObject *ignore, PyObject *args)
493{
494 DWORD code, n;
495 WCHAR *lpMsgBuf;
496 PyObject *res;
497
498 if (!PyArg_ParseTuple(args, F_DWORD, &code))
499 return NULL;
500
501 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600502 FORMAT_MESSAGE_FROM_SYSTEM |
503 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700504 NULL,
505 code,
506 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
507 (LPWSTR) &lpMsgBuf,
508 0,
509 NULL);
510 if (n) {
511 while (iswspace(lpMsgBuf[n-1]))
512 --n;
513 lpMsgBuf[n] = L'\0';
514 res = Py_BuildValue("u", lpMsgBuf);
515 } else {
516 res = PyUnicode_FromFormat("unknown error code %u", code);
517 }
518 LocalFree(lpMsgBuf);
519 return res;
520}
521
522
523/*
524 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
525 */
526
527static void
528mark_as_completed(OVERLAPPED *ov)
529{
530 ov->Internal = 0;
531 if (ov->hEvent != NULL)
532 SetEvent(ov->hEvent);
533}
534
535/*
536 * A Python object wrapping an OVERLAPPED structure and other useful data
537 * for overlapped I/O
538 */
539
540PyDoc_STRVAR(
541 Overlapped_doc,
542 "Overlapped object");
543
544static PyObject *
545Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
546{
547 OverlappedObject *self;
548 HANDLE event = INVALID_HANDLE_VALUE;
549 static char *kwlist[] = {"event", NULL};
550
551 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
552 return NULL;
553
554 if (event == INVALID_HANDLE_VALUE) {
555 event = CreateEvent(NULL, TRUE, FALSE, NULL);
556 if (event == NULL)
557 return SetFromWindowsErr(0);
558 }
559
560 self = PyObject_New(OverlappedObject, type);
561 if (self == NULL) {
562 if (event != NULL)
563 CloseHandle(event);
564 return NULL;
565 }
566
567 self->handle = NULL;
568 self->error = 0;
569 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200570 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700571 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200572 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700573 if (event)
574 self->overlapped.hEvent = event;
575 return (PyObject *)self;
576}
577
Victor Stinner54850852019-01-11 14:35:14 +0100578
579/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
580 buffers while overlapped are still running, to prevent a crash. */
581static int
582Overlapped_clear(OverlappedObject *self)
583{
584 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300585 case TYPE_READ:
586 case TYPE_ACCEPT: {
587 Py_CLEAR(self->allocated_buffer);
588 break;
Victor Stinner54850852019-01-11 14:35:14 +0100589 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300590 case TYPE_READ_FROM: {
591 // An initial call to WSARecvFrom will only allocate the buffer.
592 // The result tuple of (message, address) is only
593 // allocated _after_ a message has been received.
594 if(self->read_from.result) {
595 // We've received a message, free the result tuple.
596 Py_CLEAR(self->read_from.result);
597 }
598 if(self->read_from.allocated_buffer) {
599 Py_CLEAR(self->read_from.allocated_buffer);
600 }
601 break;
602 }
603 case TYPE_WRITE:
604 case TYPE_WRITE_TO:
605 case TYPE_READINTO: {
606 if (self->user_buffer.obj) {
607 PyBuffer_Release(&self->user_buffer);
608 }
609 break;
610 }
Victor Stinner54850852019-01-11 14:35:14 +0100611 }
612 self->type = TYPE_NOT_STARTED;
613 return 0;
614}
615
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700616static void
617Overlapped_dealloc(OverlappedObject *self)
618{
619 DWORD bytes;
620 DWORD olderr = GetLastError();
621 BOOL wait = FALSE;
622 BOOL ret;
623
624 if (!HasOverlappedIoCompleted(&self->overlapped) &&
625 self->type != TYPE_NOT_STARTED)
626 {
627 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
628 wait = TRUE;
629
630 Py_BEGIN_ALLOW_THREADS
631 ret = GetOverlappedResult(self->handle, &self->overlapped,
632 &bytes, wait);
633 Py_END_ALLOW_THREADS
634
635 switch (ret ? ERROR_SUCCESS : GetLastError()) {
636 case ERROR_SUCCESS:
637 case ERROR_NOT_FOUND:
638 case ERROR_OPERATION_ABORTED:
639 break;
640 default:
641 PyErr_Format(
642 PyExc_RuntimeError,
643 "%R still has pending operation at "
644 "deallocation, the process may crash", self);
645 PyErr_WriteUnraisable(NULL);
646 }
647 }
648
Victor Stinner54850852019-01-11 14:35:14 +0100649 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700650 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700651 }
Victor Stinner54850852019-01-11 14:35:14 +0100652
653 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700654 PyObject_Del(self);
655 SetLastError(olderr);
656}
657
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300658
659/* Convert IPv4 sockaddr to a Python str. */
660
661static PyObject *
662make_ipv4_addr(const struct sockaddr_in *addr)
663{
664 char buf[INET_ADDRSTRLEN];
665 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
666 PyErr_SetFromErrno(PyExc_OSError);
667 return NULL;
668 }
669 return PyUnicode_FromString(buf);
670}
671
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300672/* Convert IPv6 sockaddr to a Python str. */
673
674static PyObject *
675make_ipv6_addr(const struct sockaddr_in6 *addr)
676{
677 char buf[INET6_ADDRSTRLEN];
678 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
679 PyErr_SetFromErrno(PyExc_OSError);
680 return NULL;
681 }
682 return PyUnicode_FromString(buf);
683}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300684
685static PyObject*
686unparse_address(LPSOCKADDR Address, DWORD Length)
687{
688 /* The function is adopted from mocketmodule.c makesockaddr()*/
689
690 switch(Address->sa_family) {
691 case AF_INET: {
692 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
693 PyObject *addrobj = make_ipv4_addr(a);
694 PyObject *ret = NULL;
695 if (addrobj) {
696 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
697 Py_DECREF(addrobj);
698 }
699 return ret;
700 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300701 case AF_INET6: {
702 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
703 PyObject *addrobj = make_ipv6_addr(a);
704 PyObject *ret = NULL;
705 if (addrobj) {
706 ret = Py_BuildValue("OiII",
707 addrobj,
708 ntohs(a->sin6_port),
709 ntohl(a->sin6_flowinfo),
710 a->sin6_scope_id);
711 Py_DECREF(addrobj);
712 }
713 return ret;
714 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300715 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200716 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
717 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300718 }
719 }
720}
721
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700722PyDoc_STRVAR(
723 Overlapped_cancel_doc,
724 "cancel() -> None\n\n"
725 "Cancel overlapped operation");
726
727static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530728Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700729{
730 BOOL ret = TRUE;
731
732 if (self->type == TYPE_NOT_STARTED
733 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
734 Py_RETURN_NONE;
735
736 if (!HasOverlappedIoCompleted(&self->overlapped)) {
737 Py_BEGIN_ALLOW_THREADS
738 if (Py_CancelIoEx)
739 ret = Py_CancelIoEx(self->handle, &self->overlapped);
740 else
741 ret = CancelIo(self->handle);
742 Py_END_ALLOW_THREADS
743 }
744
745 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
746 if (!ret && GetLastError() != ERROR_NOT_FOUND)
747 return SetFromWindowsErr(0);
748 Py_RETURN_NONE;
749}
750
751PyDoc_STRVAR(
752 Overlapped_getresult_doc,
753 "getresult(wait=False) -> result\n\n"
754 "Retrieve result of operation. If wait is true then it blocks\n"
755 "until the operation is finished. If wait is false and the\n"
756 "operation is still pending then an error is raised.");
757
758static PyObject *
759Overlapped_getresult(OverlappedObject *self, PyObject *args)
760{
761 BOOL wait = FALSE;
762 DWORD transferred = 0;
763 BOOL ret;
764 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300765 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700766
767 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
768 return NULL;
769
770 if (self->type == TYPE_NONE) {
771 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
772 return NULL;
773 }
774
775 if (self->type == TYPE_NOT_STARTED) {
776 PyErr_SetString(PyExc_ValueError, "operation failed to start");
777 return NULL;
778 }
779
780 Py_BEGIN_ALLOW_THREADS
781 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
782 wait);
783 Py_END_ALLOW_THREADS
784
785 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
786 switch (err) {
787 case ERROR_SUCCESS:
788 case ERROR_MORE_DATA:
789 break;
790 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300791 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700792 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300793 }
794 else if (self->type == TYPE_READ_FROM &&
795 (self->read_from.result != NULL ||
796 self->read_from.allocated_buffer != NULL))
797 {
798 break;
799 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700800 /* fall through */
801 default:
802 return SetFromWindowsErr(err);
803 }
804
805 switch (self->type) {
806 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200807 assert(PyBytes_CheckExact(self->allocated_buffer));
808 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
809 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700810 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300811
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200812 Py_INCREF(self->allocated_buffer);
813 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300814 case TYPE_READ_FROM:
815 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
816
817 if (transferred != PyBytes_GET_SIZE(
818 self->read_from.allocated_buffer) &&
819 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
820 {
821 return NULL;
822 }
823
824 // unparse the address
825 addr = unparse_address((SOCKADDR*)&self->read_from.address,
826 self->read_from.address_length);
827
828 if (addr == NULL) {
829 return NULL;
830 }
831
832 // The result is a two item tuple: (message, address)
833 self->read_from.result = PyTuple_New(2);
834 if (self->read_from.result == NULL) {
835 Py_CLEAR(addr);
836 return NULL;
837 }
838
839 // first item: message
840 Py_INCREF(self->read_from.allocated_buffer);
841 PyTuple_SET_ITEM(self->read_from.result, 0,
842 self->read_from.allocated_buffer);
843 // second item: address
844 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
845
846 Py_INCREF(self->read_from.result);
847 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700848 default:
849 return PyLong_FromUnsignedLong((unsigned long) transferred);
850 }
851}
852
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200853static PyObject *
854do_ReadFile(OverlappedObject *self, HANDLE handle,
855 char *bufstart, DWORD buflen)
856{
857 DWORD nread;
858 int ret;
859 DWORD err;
860
861 Py_BEGIN_ALLOW_THREADS
862 ret = ReadFile(handle, bufstart, buflen, &nread,
863 &self->overlapped);
864 Py_END_ALLOW_THREADS
865
866 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
867 switch (err) {
868 case ERROR_BROKEN_PIPE:
869 mark_as_completed(&self->overlapped);
870 return SetFromWindowsErr(err);
871 case ERROR_SUCCESS:
872 case ERROR_MORE_DATA:
873 case ERROR_IO_PENDING:
874 Py_RETURN_NONE;
875 default:
Victor Stinner54850852019-01-11 14:35:14 +0100876 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200877 return SetFromWindowsErr(err);
878 }
879}
880
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700881PyDoc_STRVAR(
882 Overlapped_ReadFile_doc,
883 "ReadFile(handle, size) -> Overlapped[message]\n\n"
884 "Start overlapped read");
885
886static PyObject *
887Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
888{
889 HANDLE handle;
890 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700891 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700892
893 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
894 return NULL;
895
896 if (self->type != TYPE_NONE) {
897 PyErr_SetString(PyExc_ValueError, "operation already attempted");
898 return NULL;
899 }
900
901#if SIZEOF_SIZE_T <= SIZEOF_LONG
902 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
903#endif
904 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
905 if (buf == NULL)
906 return NULL;
907
908 self->type = TYPE_READ;
909 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200910 self->allocated_buffer = buf;
911
912 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
913}
914
915PyDoc_STRVAR(
916 Overlapped_ReadFileInto_doc,
917 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
918 "Start overlapped receive");
919
920static PyObject *
921Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
922{
923 HANDLE handle;
924 PyObject *bufobj;
925
926 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
927 return NULL;
928
929 if (self->type != TYPE_NONE) {
930 PyErr_SetString(PyExc_ValueError, "operation already attempted");
931 return NULL;
932 }
933
934 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
935 return NULL;
936
937#if SIZEOF_SIZE_T > SIZEOF_LONG
938 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
939 PyBuffer_Release(&self->user_buffer);
940 PyErr_SetString(PyExc_ValueError, "buffer too large");
941 return NULL;
942 }
943#endif
944
945 self->type = TYPE_READINTO;
946 self->handle = handle;
947
948 return do_ReadFile(self, handle, self->user_buffer.buf,
949 (DWORD)self->user_buffer.len);
950}
951
952static PyObject *
953do_WSARecv(OverlappedObject *self, HANDLE handle,
954 char *bufstart, DWORD buflen, DWORD flags)
955{
956 DWORD nread;
957 WSABUF wsabuf;
958 int ret;
959 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300960
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200961 wsabuf.buf = bufstart;
962 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700963
964 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200965 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
966 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700967 Py_END_ALLOW_THREADS
968
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200969 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700970 switch (err) {
971 case ERROR_BROKEN_PIPE:
972 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100973 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700974 case ERROR_SUCCESS:
975 case ERROR_MORE_DATA:
976 case ERROR_IO_PENDING:
977 Py_RETURN_NONE;
978 default:
Victor Stinner54850852019-01-11 14:35:14 +0100979 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700980 return SetFromWindowsErr(err);
981 }
982}
983
984PyDoc_STRVAR(
985 Overlapped_WSARecv_doc,
986 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
987 "Start overlapped receive");
988
989static PyObject *
990Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
991{
992 HANDLE handle;
993 DWORD size;
994 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700995 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700996
997 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
998 &handle, &size, &flags))
999 return NULL;
1000
1001 if (self->type != TYPE_NONE) {
1002 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1003 return NULL;
1004 }
1005
1006#if SIZEOF_SIZE_T <= SIZEOF_LONG
1007 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1008#endif
1009 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1010 if (buf == NULL)
1011 return NULL;
1012
1013 self->type = TYPE_READ;
1014 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001015 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001016
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001017 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1018}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001019
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001020PyDoc_STRVAR(
1021 Overlapped_WSARecvInto_doc,
1022 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
1023 "Start overlapped receive");
1024
1025static PyObject *
1026Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
1027{
1028 HANDLE handle;
1029 PyObject *bufobj;
1030 DWORD flags;
1031
1032 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
1033 &handle, &bufobj, &flags))
1034 return NULL;
1035
1036 if (self->type != TYPE_NONE) {
1037 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1038 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001039 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001040
1041 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1042 return NULL;
1043
1044#if SIZEOF_SIZE_T > SIZEOF_LONG
1045 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1046 PyBuffer_Release(&self->user_buffer);
1047 PyErr_SetString(PyExc_ValueError, "buffer too large");
1048 return NULL;
1049 }
1050#endif
1051
1052 self->type = TYPE_READINTO;
1053 self->handle = handle;
1054
1055 return do_WSARecv(self, handle, self->user_buffer.buf,
1056 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001057}
1058
1059PyDoc_STRVAR(
1060 Overlapped_WriteFile_doc,
1061 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
1062 "Start overlapped write");
1063
1064static PyObject *
1065Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
1066{
1067 HANDLE handle;
1068 PyObject *bufobj;
1069 DWORD written;
1070 BOOL ret;
1071 DWORD err;
1072
1073 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
1074 return NULL;
1075
1076 if (self->type != TYPE_NONE) {
1077 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1078 return NULL;
1079 }
1080
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001081 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001082 return NULL;
1083
1084#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001085 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1086 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001087 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001088 return NULL;
1089 }
1090#endif
1091
1092 self->type = TYPE_WRITE;
1093 self->handle = handle;
1094
1095 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001096 ret = WriteFile(handle, self->user_buffer.buf,
1097 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001098 &written, &self->overlapped);
1099 Py_END_ALLOW_THREADS
1100
1101 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1102 switch (err) {
1103 case ERROR_SUCCESS:
1104 case ERROR_IO_PENDING:
1105 Py_RETURN_NONE;
1106 default:
Victor Stinner54850852019-01-11 14:35:14 +01001107 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001108 return SetFromWindowsErr(err);
1109 }
1110}
1111
1112PyDoc_STRVAR(
1113 Overlapped_WSASend_doc,
1114 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
1115 "Start overlapped send");
1116
1117static PyObject *
1118Overlapped_WSASend(OverlappedObject *self, PyObject *args)
1119{
1120 HANDLE handle;
1121 PyObject *bufobj;
1122 DWORD flags;
1123 DWORD written;
1124 WSABUF wsabuf;
1125 int ret;
1126 DWORD err;
1127
1128 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
1129 &handle, &bufobj, &flags))
1130 return NULL;
1131
1132 if (self->type != TYPE_NONE) {
1133 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1134 return NULL;
1135 }
1136
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001137 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001138 return NULL;
1139
1140#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001141 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1142 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001143 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001144 return NULL;
1145 }
1146#endif
1147
1148 self->type = TYPE_WRITE;
1149 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001150 wsabuf.len = (DWORD)self->user_buffer.len;
1151 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001152
1153 Py_BEGIN_ALLOW_THREADS
1154 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1155 &self->overlapped, NULL);
1156 Py_END_ALLOW_THREADS
1157
1158 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1159 switch (err) {
1160 case ERROR_SUCCESS:
1161 case ERROR_IO_PENDING:
1162 Py_RETURN_NONE;
1163 default:
Victor Stinner54850852019-01-11 14:35:14 +01001164 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001165 return SetFromWindowsErr(err);
1166 }
1167}
1168
1169PyDoc_STRVAR(
1170 Overlapped_AcceptEx_doc,
1171 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1172 "Start overlapped wait for client to connect");
1173
1174static PyObject *
1175Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1176{
1177 SOCKET ListenSocket;
1178 SOCKET AcceptSocket;
1179 DWORD BytesReceived;
1180 DWORD size;
1181 PyObject *buf;
1182 BOOL ret;
1183 DWORD err;
1184
1185 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1186 &ListenSocket, &AcceptSocket))
1187 return NULL;
1188
1189 if (self->type != TYPE_NONE) {
1190 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1191 return NULL;
1192 }
1193
1194 size = sizeof(struct sockaddr_in6) + 16;
1195 buf = PyBytes_FromStringAndSize(NULL, size*2);
1196 if (!buf)
1197 return NULL;
1198
1199 self->type = TYPE_ACCEPT;
1200 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001201 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001202
1203 Py_BEGIN_ALLOW_THREADS
1204 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1205 0, size, size, &BytesReceived, &self->overlapped);
1206 Py_END_ALLOW_THREADS
1207
1208 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1209 switch (err) {
1210 case ERROR_SUCCESS:
1211 case ERROR_IO_PENDING:
1212 Py_RETURN_NONE;
1213 default:
Victor Stinner54850852019-01-11 14:35:14 +01001214 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001215 return SetFromWindowsErr(err);
1216 }
1217}
1218
1219
1220static int
1221parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1222{
Steve Dowercc16be82016-09-08 10:35:16 -07001223 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001224 unsigned short Port;
1225 unsigned long FlowInfo;
1226 unsigned long ScopeId;
1227
1228 memset(Address, 0, Length);
1229
Steve Dowercc16be82016-09-08 10:35:16 -07001230 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001231 {
1232 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001233 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001234 SetFromWindowsErr(WSAGetLastError());
1235 return -1;
1236 }
1237 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1238 return Length;
1239 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001240 else if (PyArg_ParseTuple(obj,
1241 "uHkk;ConnectEx(): illegal address_as_bytes "
1242 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001243 {
1244 PyErr_Clear();
1245 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001246 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001247 SetFromWindowsErr(WSAGetLastError());
1248 return -1;
1249 }
1250 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1251 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1252 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1253 return Length;
1254 }
1255
1256 return -1;
1257}
1258
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001259PyDoc_STRVAR(
1260 Overlapped_ConnectEx_doc,
1261 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1262 "Start overlapped connect. client_handle should be unbound.");
1263
1264static PyObject *
1265Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1266{
1267 SOCKET ConnectSocket;
1268 PyObject *AddressObj;
1269 char AddressBuf[sizeof(struct sockaddr_in6)];
1270 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1271 int Length;
1272 BOOL ret;
1273 DWORD err;
1274
Oren Milman1d1d3e92017-08-20 18:35:36 +03001275 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1276 &ConnectSocket, &PyTuple_Type, &AddressObj))
1277 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001278 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001279 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001280
1281 if (self->type != TYPE_NONE) {
1282 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1283 return NULL;
1284 }
1285
1286 Length = sizeof(AddressBuf);
1287 Length = parse_address(AddressObj, Address, Length);
1288 if (Length < 0)
1289 return NULL;
1290
1291 self->type = TYPE_CONNECT;
1292 self->handle = (HANDLE)ConnectSocket;
1293
1294 Py_BEGIN_ALLOW_THREADS
1295 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1296 NULL, 0, NULL, &self->overlapped);
1297 Py_END_ALLOW_THREADS
1298
1299 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1300 switch (err) {
1301 case ERROR_SUCCESS:
1302 case ERROR_IO_PENDING:
1303 Py_RETURN_NONE;
1304 default:
Victor Stinner54850852019-01-11 14:35:14 +01001305 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001306 return SetFromWindowsErr(err);
1307 }
1308}
1309
1310PyDoc_STRVAR(
1311 Overlapped_DisconnectEx_doc,
1312 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1313 "Start overlapped connect. client_handle should be unbound.");
1314
1315static PyObject *
1316Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1317{
1318 SOCKET Socket;
1319 DWORD flags;
1320 BOOL ret;
1321 DWORD err;
1322
1323 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1324 return NULL;
1325
1326 if (self->type != TYPE_NONE) {
1327 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1328 return NULL;
1329 }
1330
1331 self->type = TYPE_DISCONNECT;
1332 self->handle = (HANDLE)Socket;
1333
1334 Py_BEGIN_ALLOW_THREADS
1335 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1336 Py_END_ALLOW_THREADS
1337
1338 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1339 switch (err) {
1340 case ERROR_SUCCESS:
1341 case ERROR_IO_PENDING:
1342 Py_RETURN_NONE;
1343 default:
Victor Stinner54850852019-01-11 14:35:14 +01001344 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001345 return SetFromWindowsErr(err);
1346 }
1347}
1348
1349PyDoc_STRVAR(
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001350 Overlapped_TransmitFile_doc,
1351 "TransmitFile(socket, file, offset, offset_high, "
1352 "count_to_write, count_per_send, flags) "
1353 "-> Overlapped[None]\n\n"
1354 "Transmit file data over a connected socket.");
1355
1356static PyObject *
1357Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
1358{
1359 SOCKET Socket;
1360 HANDLE File;
1361 DWORD offset;
1362 DWORD offset_high;
1363 DWORD count_to_write;
1364 DWORD count_per_send;
1365 DWORD flags;
1366 BOOL ret;
1367 DWORD err;
1368
1369 if (!PyArg_ParseTuple(args,
1370 F_HANDLE F_HANDLE F_DWORD F_DWORD
1371 F_DWORD F_DWORD F_DWORD,
1372 &Socket, &File, &offset, &offset_high,
1373 &count_to_write, &count_per_send,
1374 &flags))
1375 return NULL;
1376
1377 if (self->type != TYPE_NONE) {
1378 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1379 return NULL;
1380 }
1381
1382 self->type = TYPE_TRANSMIT_FILE;
1383 self->handle = (HANDLE)Socket;
1384 self->overlapped.Offset = offset;
1385 self->overlapped.OffsetHigh = offset_high;
1386
1387 Py_BEGIN_ALLOW_THREADS
1388 ret = Py_TransmitFile(Socket, File, count_to_write, count_per_send,
1389 &self->overlapped,
1390 NULL, flags);
1391 Py_END_ALLOW_THREADS
1392
1393 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1394 switch (err) {
1395 case ERROR_SUCCESS:
1396 case ERROR_IO_PENDING:
1397 Py_RETURN_NONE;
1398 default:
Victor Stinner54850852019-01-11 14:35:14 +01001399 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001400 return SetFromWindowsErr(err);
1401 }
1402}
1403
1404PyDoc_STRVAR(
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001405 Overlapped_ConnectNamedPipe_doc,
1406 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1407 "Start overlapped wait for a client to connect.");
1408
1409static PyObject *
1410Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1411{
1412 HANDLE Pipe;
1413 BOOL ret;
1414 DWORD err;
1415
1416 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1417 return NULL;
1418
1419 if (self->type != TYPE_NONE) {
1420 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1421 return NULL;
1422 }
1423
1424 self->type = TYPE_CONNECT_NAMED_PIPE;
1425 self->handle = Pipe;
1426
1427 Py_BEGIN_ALLOW_THREADS
1428 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1429 Py_END_ALLOW_THREADS
1430
1431 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1432 switch (err) {
1433 case ERROR_PIPE_CONNECTED:
1434 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001435 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001436 case ERROR_SUCCESS:
1437 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001438 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001439 default:
Victor Stinner54850852019-01-11 14:35:14 +01001440 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001441 return SetFromWindowsErr(err);
1442 }
1443}
1444
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001445PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001446 ConnectPipe_doc,
1447 "ConnectPipe(addr) -> pipe_handle\n\n"
1448 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001449
1450static PyObject *
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001451overlapped_ConnectPipe(PyObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001452{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001453 PyObject *AddressObj;
1454 wchar_t *Address;
1455 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001456
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001457 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001458 return NULL;
1459
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001460 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1461 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001462 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001463
Victor Stinner498b1f62015-01-26 22:43:39 +01001464 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001465 PipeHandle = CreateFileW(Address,
1466 GENERIC_READ | GENERIC_WRITE,
1467 0, NULL, OPEN_EXISTING,
1468 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001469 Py_END_ALLOW_THREADS
1470
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001471 PyMem_Free(Address);
1472 if (PipeHandle == INVALID_HANDLE_VALUE)
1473 return SetFromWindowsErr(0);
1474 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001475}
1476
1477static PyObject*
1478Overlapped_getaddress(OverlappedObject *self)
1479{
1480 return PyLong_FromVoidPtr(&self->overlapped);
1481}
1482
1483static PyObject*
1484Overlapped_getpending(OverlappedObject *self)
1485{
1486 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1487 self->type != TYPE_NOT_STARTED);
1488}
1489
Victor Stinner54850852019-01-11 14:35:14 +01001490static int
1491Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1492{
1493 switch (self->type) {
1494 case TYPE_READ:
1495 case TYPE_ACCEPT:
1496 Py_VISIT(self->allocated_buffer);
1497 break;
1498 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001499 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001500 case TYPE_READINTO:
1501 if (self->user_buffer.obj) {
1502 Py_VISIT(&self->user_buffer.obj);
1503 }
1504 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001505 case TYPE_READ_FROM:
1506 if(self->read_from.result) {
1507 Py_VISIT(self->read_from.result);
1508 }
1509 if(self->read_from.allocated_buffer) {
1510 Py_VISIT(self->read_from.allocated_buffer);
1511 }
Victor Stinner54850852019-01-11 14:35:14 +01001512 }
1513 return 0;
1514}
1515
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001516// UDP functions
1517
1518PyDoc_STRVAR(
1519 WSAConnect_doc,
1520 "WSAConnect(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1521 "Bind a remote address to a connectionless (UDP) socket");
1522
1523/*
1524 * Note: WSAConnect does not support Overlapped I/O so this function should
1525 * _only_ be used for connectionless sockets (UDP).
1526 */
1527static PyObject *
1528overlapped_WSAConnect(PyObject *self, PyObject *args)
1529{
1530 SOCKET ConnectSocket;
1531 PyObject *AddressObj;
1532 char AddressBuf[sizeof(struct sockaddr_in6)];
1533 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1534 int Length;
1535 int err;
1536
1537 if (!PyArg_ParseTuple(args, F_HANDLE "O", &ConnectSocket, &AddressObj)) {
1538 return NULL;
1539 }
1540
1541 Length = sizeof(AddressBuf);
1542 Length = parse_address(AddressObj, Address, Length);
1543 if (Length < 0) {
1544 return NULL;
1545 }
1546
1547 Py_BEGIN_ALLOW_THREADS
1548 // WSAConnect does not support overlapped I/O so this call will
1549 // successfully complete immediately.
1550 err = WSAConnect(ConnectSocket, Address, Length,
1551 NULL, NULL, NULL, NULL);
1552 Py_END_ALLOW_THREADS
1553
1554 if (err == 0) {
1555 Py_RETURN_NONE;
1556 }
1557 else {
1558 return SetFromWindowsErr(WSAGetLastError());
1559 }
1560}
1561
1562PyDoc_STRVAR(
1563 Overlapped_WSASendTo_doc,
1564 "WSASendTo(handle, buf, flags, address_as_bytes) -> "
1565 "Overlapped[bytes_transferred]\n\n"
1566 "Start overlapped sendto over a connectionless (UDP) socket");
1567
1568static PyObject *
1569Overlapped_WSASendTo(OverlappedObject *self, PyObject *args)
1570{
1571 HANDLE handle;
1572 PyObject *bufobj;
1573 DWORD flags;
1574 PyObject *AddressObj;
1575 char AddressBuf[sizeof(struct sockaddr_in6)];
1576 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1577 int AddressLength;
1578 DWORD written;
1579 WSABUF wsabuf;
1580 int ret;
1581 DWORD err;
1582
1583 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD "O",
1584 &handle, &bufobj, &flags, &AddressObj))
1585 {
1586 return NULL;
1587 }
1588
1589 // Parse the "to" address
1590 AddressLength = sizeof(AddressBuf);
1591 AddressLength = parse_address(AddressObj, Address, AddressLength);
1592 if (AddressLength < 0) {
1593 return NULL;
1594 }
1595
1596 if (self->type != TYPE_NONE) {
1597 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1598 return NULL;
1599 }
1600
1601 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1602 return NULL;
1603 }
1604
1605#if SIZEOF_SIZE_T > SIZEOF_LONG
1606 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1607 PyBuffer_Release(&self->user_buffer);
1608 PyErr_SetString(PyExc_ValueError, "buffer too large");
1609 return NULL;
1610 }
1611#endif
1612
1613 self->type = TYPE_WRITE_TO;
1614 self->handle = handle;
1615 wsabuf.len = (DWORD)self->user_buffer.len;
1616 wsabuf.buf = self->user_buffer.buf;
1617
1618 Py_BEGIN_ALLOW_THREADS
1619 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1620 Address, AddressLength, &self->overlapped, NULL);
1621 Py_END_ALLOW_THREADS
1622
1623 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1624 ERROR_SUCCESS);
1625
1626 switch(err) {
1627 case ERROR_SUCCESS:
1628 case ERROR_IO_PENDING:
1629 Py_RETURN_NONE;
1630 default:
1631 self->type = TYPE_NOT_STARTED;
1632 return SetFromWindowsErr(err);
1633 }
1634}
1635
1636
1637
1638PyDoc_STRVAR(
1639 Overlapped_WSARecvFrom_doc,
1640 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1641 "Start overlapped receive");
1642
1643static PyObject *
1644Overlapped_WSARecvFrom(OverlappedObject *self, PyObject *args)
1645{
1646 HANDLE handle;
1647 DWORD size;
1648 DWORD flags = 0;
1649 DWORD nread;
1650 PyObject *buf;
1651 WSABUF wsabuf;
1652 int ret;
1653 DWORD err;
1654
1655 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
1656 &handle, &size, &flags))
1657 {
1658 return NULL;
1659 }
1660
1661 if (self->type != TYPE_NONE) {
1662 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1663 return NULL;
1664 }
1665
1666#if SIZEOF_SIZE_T <= SIZEOF_LONG
1667 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1668#endif
1669 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1670 if (buf == NULL) {
1671 return NULL;
1672 }
1673
1674 wsabuf.len = size;
1675 wsabuf.buf = PyBytes_AS_STRING(buf);
1676
1677 self->type = TYPE_READ_FROM;
1678 self->handle = handle;
1679 self->read_from.allocated_buffer = buf;
1680 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1681 self->read_from.address_length = sizeof(self->read_from.address);
1682
1683 Py_BEGIN_ALLOW_THREADS
1684 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1685 (SOCKADDR*)&self->read_from.address,
1686 &self->read_from.address_length,
1687 &self->overlapped, NULL);
1688 Py_END_ALLOW_THREADS
1689
1690 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1691
1692 switch(err) {
1693 case ERROR_BROKEN_PIPE:
1694 mark_as_completed(&self->overlapped);
1695 return SetFromWindowsErr(err);
1696 case ERROR_SUCCESS:
1697 case ERROR_MORE_DATA:
1698 case ERROR_IO_PENDING:
1699 Py_RETURN_NONE;
1700 default:
1701 self->type = TYPE_NOT_STARTED;
1702 return SetFromWindowsErr(err);
1703 }
1704}
1705
Victor Stinner54850852019-01-11 14:35:14 +01001706
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001707static PyMethodDef Overlapped_methods[] = {
1708 {"getresult", (PyCFunction) Overlapped_getresult,
1709 METH_VARARGS, Overlapped_getresult_doc},
1710 {"cancel", (PyCFunction) Overlapped_cancel,
1711 METH_NOARGS, Overlapped_cancel_doc},
1712 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1713 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001714 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1715 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001716 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1717 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001718 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1719 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001720 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1721 METH_VARARGS, Overlapped_WriteFile_doc},
1722 {"WSASend", (PyCFunction) Overlapped_WSASend,
1723 METH_VARARGS, Overlapped_WSASend_doc},
1724 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1725 METH_VARARGS, Overlapped_AcceptEx_doc},
1726 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1727 METH_VARARGS, Overlapped_ConnectEx_doc},
1728 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1729 METH_VARARGS, Overlapped_DisconnectEx_doc},
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001730 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1731 METH_VARARGS, Overlapped_TransmitFile_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001732 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1733 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001734 {"WSARecvFrom", (PyCFunction) Overlapped_WSARecvFrom,
1735 METH_VARARGS, Overlapped_WSARecvFrom_doc },
1736 {"WSASendTo", (PyCFunction) Overlapped_WSASendTo,
1737 METH_VARARGS, Overlapped_WSASendTo_doc },
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001738 {NULL}
1739};
1740
1741static PyMemberDef Overlapped_members[] = {
1742 {"error", T_ULONG,
1743 offsetof(OverlappedObject, error),
1744 READONLY, "Error from last operation"},
1745 {"event", T_HANDLE,
1746 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1747 READONLY, "Overlapped event handle"},
1748 {NULL}
1749};
1750
1751static PyGetSetDef Overlapped_getsets[] = {
1752 {"address", (getter)Overlapped_getaddress, NULL,
1753 "Address of overlapped structure"},
1754 {"pending", (getter)Overlapped_getpending, NULL,
1755 "Whether the operation is pending"},
1756 {NULL},
1757};
1758
1759PyTypeObject OverlappedType = {
1760 PyVarObject_HEAD_INIT(NULL, 0)
1761 /* tp_name */ "_overlapped.Overlapped",
1762 /* tp_basicsize */ sizeof(OverlappedObject),
1763 /* tp_itemsize */ 0,
1764 /* tp_dealloc */ (destructor) Overlapped_dealloc,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001765 /* tp_vectorcall_offset */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001766 /* tp_getattr */ 0,
1767 /* tp_setattr */ 0,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001768 /* tp_as_async */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001769 /* tp_repr */ 0,
1770 /* tp_as_number */ 0,
1771 /* tp_as_sequence */ 0,
1772 /* tp_as_mapping */ 0,
1773 /* tp_hash */ 0,
1774 /* tp_call */ 0,
1775 /* tp_str */ 0,
1776 /* tp_getattro */ 0,
1777 /* tp_setattro */ 0,
1778 /* tp_as_buffer */ 0,
1779 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1780 /* tp_doc */ "OVERLAPPED structure wrapper",
Victor Stinner54850852019-01-11 14:35:14 +01001781 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001782 /* tp_clear */ 0,
1783 /* tp_richcompare */ 0,
1784 /* tp_weaklistoffset */ 0,
1785 /* tp_iter */ 0,
1786 /* tp_iternext */ 0,
1787 /* tp_methods */ Overlapped_methods,
1788 /* tp_members */ Overlapped_members,
1789 /* tp_getset */ Overlapped_getsets,
1790 /* tp_base */ 0,
1791 /* tp_dict */ 0,
1792 /* tp_descr_get */ 0,
1793 /* tp_descr_set */ 0,
1794 /* tp_dictoffset */ 0,
1795 /* tp_init */ 0,
1796 /* tp_alloc */ 0,
1797 /* tp_new */ Overlapped_new,
1798};
1799
1800static PyMethodDef overlapped_functions[] = {
1801 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1802 METH_VARARGS, CreateIoCompletionPort_doc},
1803 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1804 METH_VARARGS, GetQueuedCompletionStatus_doc},
1805 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1806 METH_VARARGS, PostQueuedCompletionStatus_doc},
1807 {"FormatMessage", overlapped_FormatMessage,
1808 METH_VARARGS, FormatMessage_doc},
1809 {"BindLocal", overlapped_BindLocal,
1810 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001811 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1812 METH_VARARGS, RegisterWaitWithQueue_doc},
1813 {"UnregisterWait", overlapped_UnregisterWait,
1814 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001815 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1816 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001817 {"CreateEvent", overlapped_CreateEvent,
1818 METH_VARARGS, CreateEvent_doc},
1819 {"SetEvent", overlapped_SetEvent,
1820 METH_VARARGS, SetEvent_doc},
1821 {"ResetEvent", overlapped_ResetEvent,
1822 METH_VARARGS, ResetEvent_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001823 {"ConnectPipe", overlapped_ConnectPipe,
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001824 METH_VARARGS, ConnectPipe_doc},
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001825 {"WSAConnect", overlapped_WSAConnect,
1826 METH_VARARGS, WSAConnect_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001827 {NULL}
1828};
1829
1830static struct PyModuleDef overlapped_module = {
1831 PyModuleDef_HEAD_INIT,
1832 "_overlapped",
1833 NULL,
1834 -1,
1835 overlapped_functions,
1836 NULL,
1837 NULL,
1838 NULL,
1839 NULL
1840};
1841
1842#define WINAPI_CONSTANT(fmt, con) \
1843 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1844
1845PyMODINIT_FUNC
1846PyInit__overlapped(void)
1847{
1848 PyObject *m, *d;
1849
1850 /* Ensure WSAStartup() called before initializing function pointers */
1851 m = PyImport_ImportModule("_socket");
1852 if (!m)
1853 return NULL;
1854 Py_DECREF(m);
1855
1856 if (initialize_function_pointers() < 0)
1857 return NULL;
1858
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001859 m = PyModule_Create(&overlapped_module);
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001860 if (PyModule_AddType(m, &OverlappedType) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001861 return NULL;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001862 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001863
1864 d = PyModule_GetDict(m);
1865
1866 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1867 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001868 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001869 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001870 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001871 WINAPI_CONSTANT(F_DWORD, INFINITE);
1872 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1873 WINAPI_CONSTANT(F_HANDLE, NULL);
1874 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1875 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1876 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1877
1878 return m;
1879}