blob: e5a209bf75829770486408cddb6e3c20d5fc5a53 [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"
11#include "structmember.h"
12
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 Svetlova19fb3c2018-02-25 19:32:14 +030042 TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE};
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070043
44typedef struct {
45 PyObject_HEAD
46 OVERLAPPED overlapped;
47 /* For convenience, we store the file handle too */
48 HANDLE handle;
49 /* Error returned by last method call */
50 DWORD error;
51 /* Type of operation */
52 DWORD type;
53 union {
Antoine Pitrou525f40d2017-10-19 21:46:40 +020054 /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
55 PyObject *allocated_buffer;
56 /* Buffer passed by the user: TYPE_WRITE and TYPE_READINTO */
57 Py_buffer user_buffer;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070058 };
59} OverlappedObject;
60
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070061/*
62 * Map Windows error codes to subclasses of OSError
63 */
64
65static PyObject *
66SetFromWindowsErr(DWORD err)
67{
68 PyObject *exception_type;
69
70 if (err == 0)
71 err = GetLastError();
72 switch (err) {
73 case ERROR_CONNECTION_REFUSED:
74 exception_type = PyExc_ConnectionRefusedError;
75 break;
76 case ERROR_CONNECTION_ABORTED:
77 exception_type = PyExc_ConnectionAbortedError;
78 break;
79 default:
80 exception_type = PyExc_OSError;
81 }
82 return PyErr_SetExcFromWindowsErr(exception_type, err);
83}
84
85/*
86 * Some functions should be loaded at runtime
87 */
88
89static LPFN_ACCEPTEX Py_AcceptEx = NULL;
90static LPFN_CONNECTEX Py_ConnectEx = NULL;
91static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +030092static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070093static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
94
95#define GET_WSA_POINTER(s, x) \
96 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
97 &Guid##x, sizeof(Guid##x), &Py_##x, \
98 sizeof(Py_##x), &dwBytes, NULL, NULL))
99
100static int
101initialize_function_pointers(void)
102{
103 GUID GuidAcceptEx = WSAID_ACCEPTEX;
104 GUID GuidConnectEx = WSAID_CONNECTEX;
105 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300106 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700107 HINSTANCE hKernel32;
108 SOCKET s;
109 DWORD dwBytes;
110
111 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
112 if (s == INVALID_SOCKET) {
113 SetFromWindowsErr(WSAGetLastError());
114 return -1;
115 }
116
117 if (!GET_WSA_POINTER(s, AcceptEx) ||
118 !GET_WSA_POINTER(s, ConnectEx) ||
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300119 !GET_WSA_POINTER(s, DisconnectEx) ||
120 !GET_WSA_POINTER(s, TransmitFile))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700121 {
122 closesocket(s);
123 SetFromWindowsErr(WSAGetLastError());
124 return -1;
125 }
126
127 closesocket(s);
128
129 /* On WinXP we will have Py_CancelIoEx == NULL */
Tony Roberts4860f012019-02-02 18:16:42 +0100130 Py_BEGIN_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700131 hKernel32 = GetModuleHandle("KERNEL32");
132 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Tony Roberts4860f012019-02-02 18:16:42 +0100133 Py_END_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700134 return 0;
135}
136
137/*
138 * Completion port stuff
139 */
140
141PyDoc_STRVAR(
142 CreateIoCompletionPort_doc,
143 "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
144 "Create a completion port or register a handle with a port.");
145
146static PyObject *
147overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
148{
149 HANDLE FileHandle;
150 HANDLE ExistingCompletionPort;
151 ULONG_PTR CompletionKey;
152 DWORD NumberOfConcurrentThreads;
153 HANDLE ret;
154
155 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
156 &FileHandle, &ExistingCompletionPort, &CompletionKey,
157 &NumberOfConcurrentThreads))
158 return NULL;
159
160 Py_BEGIN_ALLOW_THREADS
161 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
162 CompletionKey, NumberOfConcurrentThreads);
163 Py_END_ALLOW_THREADS
164
165 if (ret == NULL)
166 return SetFromWindowsErr(0);
167 return Py_BuildValue(F_HANDLE, ret);
168}
169
170PyDoc_STRVAR(
171 GetQueuedCompletionStatus_doc,
172 "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
173 "Get a message from completion port. Wait for up to msecs milliseconds.");
174
175static PyObject *
176overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
177{
178 HANDLE CompletionPort = NULL;
179 DWORD NumberOfBytes = 0;
180 ULONG_PTR CompletionKey = 0;
181 OVERLAPPED *Overlapped = NULL;
182 DWORD Milliseconds;
183 DWORD err;
184 BOOL ret;
185
186 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
187 &CompletionPort, &Milliseconds))
188 return NULL;
189
190 Py_BEGIN_ALLOW_THREADS
191 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
192 &CompletionKey, &Overlapped, Milliseconds);
193 Py_END_ALLOW_THREADS
194
195 err = ret ? ERROR_SUCCESS : GetLastError();
196 if (Overlapped == NULL) {
197 if (err == WAIT_TIMEOUT)
198 Py_RETURN_NONE;
199 else
200 return SetFromWindowsErr(err);
201 }
202 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
203 err, NumberOfBytes, CompletionKey, Overlapped);
204}
205
206PyDoc_STRVAR(
207 PostQueuedCompletionStatus_doc,
208 "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
209 "Post a message to completion port.");
210
211static PyObject *
212overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
213{
214 HANDLE CompletionPort;
215 DWORD NumberOfBytes;
216 ULONG_PTR CompletionKey;
217 OVERLAPPED *Overlapped;
218 BOOL ret;
219
220 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
221 &CompletionPort, &NumberOfBytes, &CompletionKey,
222 &Overlapped))
223 return NULL;
224
225 Py_BEGIN_ALLOW_THREADS
226 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
227 CompletionKey, Overlapped);
228 Py_END_ALLOW_THREADS
229
230 if (!ret)
231 return SetFromWindowsErr(0);
232 Py_RETURN_NONE;
233}
234
235/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700236 * Wait for a handle
237 */
238
239struct PostCallbackData {
240 HANDLE CompletionPort;
241 LPOVERLAPPED Overlapped;
242};
243
244static VOID CALLBACK
245PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
246{
247 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
248
249 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
250 0, p->Overlapped);
251 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100252 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700253}
254
255PyDoc_STRVAR(
256 RegisterWaitWithQueue_doc,
257 "RegisterWaitWithQueue(Object, CompletionPort, Overlapped, Timeout)\n"
258 " -> WaitHandle\n\n"
259 "Register wait for Object; when complete CompletionPort is notified.\n");
260
261static PyObject *
262overlapped_RegisterWaitWithQueue(PyObject *self, PyObject *args)
263{
264 HANDLE NewWaitObject;
265 HANDLE Object;
266 ULONG Milliseconds;
267 struct PostCallbackData data, *pdata;
268
269 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_POINTER F_DWORD,
270 &Object,
271 &data.CompletionPort,
272 &data.Overlapped,
273 &Milliseconds))
274 return NULL;
275
Victor Stinner6150f312016-03-16 23:25:02 +0100276 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
277 PostToQueueCallback() will call PyMem_Free() from a new C thread
278 which doesn't hold the GIL. */
279 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700280 if (pdata == NULL)
281 return SetFromWindowsErr(0);
282
283 *pdata = data;
284
285 if (!RegisterWaitForSingleObject(
286 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
287 pdata, Milliseconds,
288 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
289 {
Victor Stinner6150f312016-03-16 23:25:02 +0100290 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700291 return SetFromWindowsErr(0);
292 }
293
294 return Py_BuildValue(F_HANDLE, NewWaitObject);
295}
296
297PyDoc_STRVAR(
298 UnregisterWait_doc,
299 "UnregisterWait(WaitHandle) -> None\n\n"
300 "Unregister wait handle.\n");
301
302static PyObject *
303overlapped_UnregisterWait(PyObject *self, PyObject *args)
304{
305 HANDLE WaitHandle;
306 BOOL ret;
307
308 if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
309 return NULL;
310
311 Py_BEGIN_ALLOW_THREADS
312 ret = UnregisterWait(WaitHandle);
313 Py_END_ALLOW_THREADS
314
315 if (!ret)
316 return SetFromWindowsErr(0);
317 Py_RETURN_NONE;
318}
319
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100320PyDoc_STRVAR(
321 UnregisterWaitEx_doc,
322 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
323 "Unregister wait handle.\n");
324
325static PyObject *
326overlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
327{
328 HANDLE WaitHandle, Event;
329 BOOL ret;
330
331 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
332 return NULL;
333
334 Py_BEGIN_ALLOW_THREADS
335 ret = UnregisterWaitEx(WaitHandle, Event);
336 Py_END_ALLOW_THREADS
337
338 if (!ret)
339 return SetFromWindowsErr(0);
340 Py_RETURN_NONE;
341}
342
Guido van Rossum90fb9142013-10-30 14:44:05 -0700343/*
344 * Event functions -- currently only used by tests
345 */
346
347PyDoc_STRVAR(
348 CreateEvent_doc,
349 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
350 " -> Handle\n\n"
351 "Create an event. EventAttributes must be None.\n");
352
353static PyObject *
354overlapped_CreateEvent(PyObject *self, PyObject *args)
355{
356 PyObject *EventAttributes;
357 BOOL ManualReset;
358 BOOL InitialState;
359 Py_UNICODE *Name;
360 HANDLE Event;
361
362 if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
363 &EventAttributes, &ManualReset,
364 &InitialState, &Name))
365 return NULL;
366
367 if (EventAttributes != Py_None) {
368 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
369 return NULL;
370 }
371
372 Py_BEGIN_ALLOW_THREADS
373 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
374 Py_END_ALLOW_THREADS
375
376 if (Event == NULL)
377 return SetFromWindowsErr(0);
378 return Py_BuildValue(F_HANDLE, Event);
379}
380
381PyDoc_STRVAR(
382 SetEvent_doc,
383 "SetEvent(Handle) -> None\n\n"
384 "Set event.\n");
385
386static PyObject *
387overlapped_SetEvent(PyObject *self, PyObject *args)
388{
389 HANDLE Handle;
390 BOOL ret;
391
392 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
393 return NULL;
394
395 Py_BEGIN_ALLOW_THREADS
396 ret = SetEvent(Handle);
397 Py_END_ALLOW_THREADS
398
399 if (!ret)
400 return SetFromWindowsErr(0);
401 Py_RETURN_NONE;
402}
403
404PyDoc_STRVAR(
405 ResetEvent_doc,
406 "ResetEvent(Handle) -> None\n\n"
407 "Reset event.\n");
408
409static PyObject *
410overlapped_ResetEvent(PyObject *self, PyObject *args)
411{
412 HANDLE Handle;
413 BOOL ret;
414
415 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
416 return NULL;
417
418 Py_BEGIN_ALLOW_THREADS
419 ret = ResetEvent(Handle);
420 Py_END_ALLOW_THREADS
421
422 if (!ret)
423 return SetFromWindowsErr(0);
424 Py_RETURN_NONE;
425}
426
427/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700428 * Bind socket handle to local port without doing slow getaddrinfo()
429 */
430
431PyDoc_STRVAR(
432 BindLocal_doc,
433 "BindLocal(handle, family) -> None\n\n"
434 "Bind a socket handle to an arbitrary local port.\n"
435 "family should AF_INET or AF_INET6.\n");
436
437static PyObject *
438overlapped_BindLocal(PyObject *self, PyObject *args)
439{
440 SOCKET Socket;
441 int Family;
442 BOOL ret;
443
444 if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
445 return NULL;
446
447 if (Family == AF_INET) {
448 struct sockaddr_in addr;
449 memset(&addr, 0, sizeof(addr));
450 addr.sin_family = AF_INET;
451 addr.sin_port = 0;
452 addr.sin_addr.S_un.S_addr = INADDR_ANY;
453 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
454 } else if (Family == AF_INET6) {
455 struct sockaddr_in6 addr;
456 memset(&addr, 0, sizeof(addr));
457 addr.sin6_family = AF_INET6;
458 addr.sin6_port = 0;
459 addr.sin6_addr = in6addr_any;
460 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
461 } else {
462 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
463 return NULL;
464 }
465
466 if (!ret)
467 return SetFromWindowsErr(WSAGetLastError());
468 Py_RETURN_NONE;
469}
470
471/*
472 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
473 */
474
475PyDoc_STRVAR(
476 FormatMessage_doc,
477 "FormatMessage(error_code) -> error_message\n\n"
478 "Return error message for an error code.");
479
480static PyObject *
481overlapped_FormatMessage(PyObject *ignore, PyObject *args)
482{
483 DWORD code, n;
484 WCHAR *lpMsgBuf;
485 PyObject *res;
486
487 if (!PyArg_ParseTuple(args, F_DWORD, &code))
488 return NULL;
489
490 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
491 FORMAT_MESSAGE_FROM_SYSTEM,
492 NULL,
493 code,
494 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
495 (LPWSTR) &lpMsgBuf,
496 0,
497 NULL);
498 if (n) {
499 while (iswspace(lpMsgBuf[n-1]))
500 --n;
501 lpMsgBuf[n] = L'\0';
502 res = Py_BuildValue("u", lpMsgBuf);
503 } else {
504 res = PyUnicode_FromFormat("unknown error code %u", code);
505 }
506 LocalFree(lpMsgBuf);
507 return res;
508}
509
510
511/*
512 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
513 */
514
515static void
516mark_as_completed(OVERLAPPED *ov)
517{
518 ov->Internal = 0;
519 if (ov->hEvent != NULL)
520 SetEvent(ov->hEvent);
521}
522
523/*
524 * A Python object wrapping an OVERLAPPED structure and other useful data
525 * for overlapped I/O
526 */
527
528PyDoc_STRVAR(
529 Overlapped_doc,
530 "Overlapped object");
531
532static PyObject *
533Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
534{
535 OverlappedObject *self;
536 HANDLE event = INVALID_HANDLE_VALUE;
537 static char *kwlist[] = {"event", NULL};
538
539 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
540 return NULL;
541
542 if (event == INVALID_HANDLE_VALUE) {
543 event = CreateEvent(NULL, TRUE, FALSE, NULL);
544 if (event == NULL)
545 return SetFromWindowsErr(0);
546 }
547
548 self = PyObject_New(OverlappedObject, type);
549 if (self == NULL) {
550 if (event != NULL)
551 CloseHandle(event);
552 return NULL;
553 }
554
555 self->handle = NULL;
556 self->error = 0;
557 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200558 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700559 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200560 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700561 if (event)
562 self->overlapped.hEvent = event;
563 return (PyObject *)self;
564}
565
Victor Stinner54850852019-01-11 14:35:14 +0100566
567/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
568 buffers while overlapped are still running, to prevent a crash. */
569static int
570Overlapped_clear(OverlappedObject *self)
571{
572 switch (self->type) {
573 case TYPE_READ:
574 case TYPE_ACCEPT:
575 Py_CLEAR(self->allocated_buffer);
576 break;
577 case TYPE_WRITE:
578 case TYPE_READINTO:
579 if (self->user_buffer.obj) {
580 PyBuffer_Release(&self->user_buffer);
581 }
582 break;
583 }
584 self->type = TYPE_NOT_STARTED;
585 return 0;
586}
587
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700588static void
589Overlapped_dealloc(OverlappedObject *self)
590{
591 DWORD bytes;
592 DWORD olderr = GetLastError();
593 BOOL wait = FALSE;
594 BOOL ret;
595
596 if (!HasOverlappedIoCompleted(&self->overlapped) &&
597 self->type != TYPE_NOT_STARTED)
598 {
599 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
600 wait = TRUE;
601
602 Py_BEGIN_ALLOW_THREADS
603 ret = GetOverlappedResult(self->handle, &self->overlapped,
604 &bytes, wait);
605 Py_END_ALLOW_THREADS
606
607 switch (ret ? ERROR_SUCCESS : GetLastError()) {
608 case ERROR_SUCCESS:
609 case ERROR_NOT_FOUND:
610 case ERROR_OPERATION_ABORTED:
611 break;
612 default:
613 PyErr_Format(
614 PyExc_RuntimeError,
615 "%R still has pending operation at "
616 "deallocation, the process may crash", self);
617 PyErr_WriteUnraisable(NULL);
618 }
619 }
620
Victor Stinner54850852019-01-11 14:35:14 +0100621 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700622 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700623 }
Victor Stinner54850852019-01-11 14:35:14 +0100624
625 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700626 PyObject_Del(self);
627 SetLastError(olderr);
628}
629
630PyDoc_STRVAR(
631 Overlapped_cancel_doc,
632 "cancel() -> None\n\n"
633 "Cancel overlapped operation");
634
635static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530636Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700637{
638 BOOL ret = TRUE;
639
640 if (self->type == TYPE_NOT_STARTED
641 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
642 Py_RETURN_NONE;
643
644 if (!HasOverlappedIoCompleted(&self->overlapped)) {
645 Py_BEGIN_ALLOW_THREADS
646 if (Py_CancelIoEx)
647 ret = Py_CancelIoEx(self->handle, &self->overlapped);
648 else
649 ret = CancelIo(self->handle);
650 Py_END_ALLOW_THREADS
651 }
652
653 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
654 if (!ret && GetLastError() != ERROR_NOT_FOUND)
655 return SetFromWindowsErr(0);
656 Py_RETURN_NONE;
657}
658
659PyDoc_STRVAR(
660 Overlapped_getresult_doc,
661 "getresult(wait=False) -> result\n\n"
662 "Retrieve result of operation. If wait is true then it blocks\n"
663 "until the operation is finished. If wait is false and the\n"
664 "operation is still pending then an error is raised.");
665
666static PyObject *
667Overlapped_getresult(OverlappedObject *self, PyObject *args)
668{
669 BOOL wait = FALSE;
670 DWORD transferred = 0;
671 BOOL ret;
672 DWORD err;
673
674 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
675 return NULL;
676
677 if (self->type == TYPE_NONE) {
678 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
679 return NULL;
680 }
681
682 if (self->type == TYPE_NOT_STARTED) {
683 PyErr_SetString(PyExc_ValueError, "operation failed to start");
684 return NULL;
685 }
686
687 Py_BEGIN_ALLOW_THREADS
688 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
689 wait);
690 Py_END_ALLOW_THREADS
691
692 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
693 switch (err) {
694 case ERROR_SUCCESS:
695 case ERROR_MORE_DATA:
696 break;
697 case ERROR_BROKEN_PIPE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200698 if (self->type == TYPE_READ || self->type == TYPE_READINTO)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700699 break;
700 /* fall through */
701 default:
702 return SetFromWindowsErr(err);
703 }
704
705 switch (self->type) {
706 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200707 assert(PyBytes_CheckExact(self->allocated_buffer));
708 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
709 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700710 return NULL;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200711 Py_INCREF(self->allocated_buffer);
712 return self->allocated_buffer;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700713 default:
714 return PyLong_FromUnsignedLong((unsigned long) transferred);
715 }
716}
717
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200718static PyObject *
719do_ReadFile(OverlappedObject *self, HANDLE handle,
720 char *bufstart, DWORD buflen)
721{
722 DWORD nread;
723 int ret;
724 DWORD err;
725
726 Py_BEGIN_ALLOW_THREADS
727 ret = ReadFile(handle, bufstart, buflen, &nread,
728 &self->overlapped);
729 Py_END_ALLOW_THREADS
730
731 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
732 switch (err) {
733 case ERROR_BROKEN_PIPE:
734 mark_as_completed(&self->overlapped);
735 return SetFromWindowsErr(err);
736 case ERROR_SUCCESS:
737 case ERROR_MORE_DATA:
738 case ERROR_IO_PENDING:
739 Py_RETURN_NONE;
740 default:
Victor Stinner54850852019-01-11 14:35:14 +0100741 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200742 return SetFromWindowsErr(err);
743 }
744}
745
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700746PyDoc_STRVAR(
747 Overlapped_ReadFile_doc,
748 "ReadFile(handle, size) -> Overlapped[message]\n\n"
749 "Start overlapped read");
750
751static PyObject *
752Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
753{
754 HANDLE handle;
755 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700756 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700757
758 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
759 return NULL;
760
761 if (self->type != TYPE_NONE) {
762 PyErr_SetString(PyExc_ValueError, "operation already attempted");
763 return NULL;
764 }
765
766#if SIZEOF_SIZE_T <= SIZEOF_LONG
767 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
768#endif
769 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
770 if (buf == NULL)
771 return NULL;
772
773 self->type = TYPE_READ;
774 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200775 self->allocated_buffer = buf;
776
777 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
778}
779
780PyDoc_STRVAR(
781 Overlapped_ReadFileInto_doc,
782 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
783 "Start overlapped receive");
784
785static PyObject *
786Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
787{
788 HANDLE handle;
789 PyObject *bufobj;
790
791 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
792 return NULL;
793
794 if (self->type != TYPE_NONE) {
795 PyErr_SetString(PyExc_ValueError, "operation already attempted");
796 return NULL;
797 }
798
799 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
800 return NULL;
801
802#if SIZEOF_SIZE_T > SIZEOF_LONG
803 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
804 PyBuffer_Release(&self->user_buffer);
805 PyErr_SetString(PyExc_ValueError, "buffer too large");
806 return NULL;
807 }
808#endif
809
810 self->type = TYPE_READINTO;
811 self->handle = handle;
812
813 return do_ReadFile(self, handle, self->user_buffer.buf,
814 (DWORD)self->user_buffer.len);
815}
816
817static PyObject *
818do_WSARecv(OverlappedObject *self, HANDLE handle,
819 char *bufstart, DWORD buflen, DWORD flags)
820{
821 DWORD nread;
822 WSABUF wsabuf;
823 int ret;
824 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300825
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200826 wsabuf.buf = bufstart;
827 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700828
829 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200830 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
831 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700832 Py_END_ALLOW_THREADS
833
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200834 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700835 switch (err) {
836 case ERROR_BROKEN_PIPE:
837 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100838 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700839 case ERROR_SUCCESS:
840 case ERROR_MORE_DATA:
841 case ERROR_IO_PENDING:
842 Py_RETURN_NONE;
843 default:
Victor Stinner54850852019-01-11 14:35:14 +0100844 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700845 return SetFromWindowsErr(err);
846 }
847}
848
849PyDoc_STRVAR(
850 Overlapped_WSARecv_doc,
851 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
852 "Start overlapped receive");
853
854static PyObject *
855Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
856{
857 HANDLE handle;
858 DWORD size;
859 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700860 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700861
862 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
863 &handle, &size, &flags))
864 return NULL;
865
866 if (self->type != TYPE_NONE) {
867 PyErr_SetString(PyExc_ValueError, "operation already attempted");
868 return NULL;
869 }
870
871#if SIZEOF_SIZE_T <= SIZEOF_LONG
872 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
873#endif
874 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
875 if (buf == NULL)
876 return NULL;
877
878 self->type = TYPE_READ;
879 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200880 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700881
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200882 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
883}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700884
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200885PyDoc_STRVAR(
886 Overlapped_WSARecvInto_doc,
887 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
888 "Start overlapped receive");
889
890static PyObject *
891Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
892{
893 HANDLE handle;
894 PyObject *bufobj;
895 DWORD flags;
896
897 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
898 &handle, &bufobj, &flags))
899 return NULL;
900
901 if (self->type != TYPE_NONE) {
902 PyErr_SetString(PyExc_ValueError, "operation already attempted");
903 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700904 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200905
906 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
907 return NULL;
908
909#if SIZEOF_SIZE_T > SIZEOF_LONG
910 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
911 PyBuffer_Release(&self->user_buffer);
912 PyErr_SetString(PyExc_ValueError, "buffer too large");
913 return NULL;
914 }
915#endif
916
917 self->type = TYPE_READINTO;
918 self->handle = handle;
919
920 return do_WSARecv(self, handle, self->user_buffer.buf,
921 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700922}
923
924PyDoc_STRVAR(
925 Overlapped_WriteFile_doc,
926 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
927 "Start overlapped write");
928
929static PyObject *
930Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
931{
932 HANDLE handle;
933 PyObject *bufobj;
934 DWORD written;
935 BOOL ret;
936 DWORD err;
937
938 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
939 return NULL;
940
941 if (self->type != TYPE_NONE) {
942 PyErr_SetString(PyExc_ValueError, "operation already attempted");
943 return NULL;
944 }
945
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200946 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700947 return NULL;
948
949#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200950 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
951 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300952 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700953 return NULL;
954 }
955#endif
956
957 self->type = TYPE_WRITE;
958 self->handle = handle;
959
960 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200961 ret = WriteFile(handle, self->user_buffer.buf,
962 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700963 &written, &self->overlapped);
964 Py_END_ALLOW_THREADS
965
966 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
967 switch (err) {
968 case ERROR_SUCCESS:
969 case ERROR_IO_PENDING:
970 Py_RETURN_NONE;
971 default:
Victor Stinner54850852019-01-11 14:35:14 +0100972 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700973 return SetFromWindowsErr(err);
974 }
975}
976
977PyDoc_STRVAR(
978 Overlapped_WSASend_doc,
979 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
980 "Start overlapped send");
981
982static PyObject *
983Overlapped_WSASend(OverlappedObject *self, PyObject *args)
984{
985 HANDLE handle;
986 PyObject *bufobj;
987 DWORD flags;
988 DWORD written;
989 WSABUF wsabuf;
990 int ret;
991 DWORD err;
992
993 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
994 &handle, &bufobj, &flags))
995 return NULL;
996
997 if (self->type != TYPE_NONE) {
998 PyErr_SetString(PyExc_ValueError, "operation already attempted");
999 return NULL;
1000 }
1001
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001002 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001003 return NULL;
1004
1005#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001006 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1007 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001008 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001009 return NULL;
1010 }
1011#endif
1012
1013 self->type = TYPE_WRITE;
1014 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001015 wsabuf.len = (DWORD)self->user_buffer.len;
1016 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001017
1018 Py_BEGIN_ALLOW_THREADS
1019 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1020 &self->overlapped, NULL);
1021 Py_END_ALLOW_THREADS
1022
1023 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1024 switch (err) {
1025 case ERROR_SUCCESS:
1026 case ERROR_IO_PENDING:
1027 Py_RETURN_NONE;
1028 default:
Victor Stinner54850852019-01-11 14:35:14 +01001029 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001030 return SetFromWindowsErr(err);
1031 }
1032}
1033
1034PyDoc_STRVAR(
1035 Overlapped_AcceptEx_doc,
1036 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1037 "Start overlapped wait for client to connect");
1038
1039static PyObject *
1040Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1041{
1042 SOCKET ListenSocket;
1043 SOCKET AcceptSocket;
1044 DWORD BytesReceived;
1045 DWORD size;
1046 PyObject *buf;
1047 BOOL ret;
1048 DWORD err;
1049
1050 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1051 &ListenSocket, &AcceptSocket))
1052 return NULL;
1053
1054 if (self->type != TYPE_NONE) {
1055 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1056 return NULL;
1057 }
1058
1059 size = sizeof(struct sockaddr_in6) + 16;
1060 buf = PyBytes_FromStringAndSize(NULL, size*2);
1061 if (!buf)
1062 return NULL;
1063
1064 self->type = TYPE_ACCEPT;
1065 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001066 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001067
1068 Py_BEGIN_ALLOW_THREADS
1069 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1070 0, size, size, &BytesReceived, &self->overlapped);
1071 Py_END_ALLOW_THREADS
1072
1073 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1074 switch (err) {
1075 case ERROR_SUCCESS:
1076 case ERROR_IO_PENDING:
1077 Py_RETURN_NONE;
1078 default:
Victor Stinner54850852019-01-11 14:35:14 +01001079 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001080 return SetFromWindowsErr(err);
1081 }
1082}
1083
1084
1085static int
1086parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1087{
Steve Dowercc16be82016-09-08 10:35:16 -07001088 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001089 unsigned short Port;
1090 unsigned long FlowInfo;
1091 unsigned long ScopeId;
1092
1093 memset(Address, 0, Length);
1094
Steve Dowercc16be82016-09-08 10:35:16 -07001095 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001096 {
1097 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001098 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001099 SetFromWindowsErr(WSAGetLastError());
1100 return -1;
1101 }
1102 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1103 return Length;
1104 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001105 else if (PyArg_ParseTuple(obj,
1106 "uHkk;ConnectEx(): illegal address_as_bytes "
1107 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001108 {
1109 PyErr_Clear();
1110 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001111 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001112 SetFromWindowsErr(WSAGetLastError());
1113 return -1;
1114 }
1115 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1116 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1117 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1118 return Length;
1119 }
1120
1121 return -1;
1122}
1123
1124
1125PyDoc_STRVAR(
1126 Overlapped_ConnectEx_doc,
1127 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1128 "Start overlapped connect. client_handle should be unbound.");
1129
1130static PyObject *
1131Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1132{
1133 SOCKET ConnectSocket;
1134 PyObject *AddressObj;
1135 char AddressBuf[sizeof(struct sockaddr_in6)];
1136 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1137 int Length;
1138 BOOL ret;
1139 DWORD err;
1140
Oren Milman1d1d3e92017-08-20 18:35:36 +03001141 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1142 &ConnectSocket, &PyTuple_Type, &AddressObj))
1143 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001144 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001145 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001146
1147 if (self->type != TYPE_NONE) {
1148 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1149 return NULL;
1150 }
1151
1152 Length = sizeof(AddressBuf);
1153 Length = parse_address(AddressObj, Address, Length);
1154 if (Length < 0)
1155 return NULL;
1156
1157 self->type = TYPE_CONNECT;
1158 self->handle = (HANDLE)ConnectSocket;
1159
1160 Py_BEGIN_ALLOW_THREADS
1161 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1162 NULL, 0, NULL, &self->overlapped);
1163 Py_END_ALLOW_THREADS
1164
1165 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1166 switch (err) {
1167 case ERROR_SUCCESS:
1168 case ERROR_IO_PENDING:
1169 Py_RETURN_NONE;
1170 default:
Victor Stinner54850852019-01-11 14:35:14 +01001171 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001172 return SetFromWindowsErr(err);
1173 }
1174}
1175
1176PyDoc_STRVAR(
1177 Overlapped_DisconnectEx_doc,
1178 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1179 "Start overlapped connect. client_handle should be unbound.");
1180
1181static PyObject *
1182Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1183{
1184 SOCKET Socket;
1185 DWORD flags;
1186 BOOL ret;
1187 DWORD err;
1188
1189 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1190 return NULL;
1191
1192 if (self->type != TYPE_NONE) {
1193 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1194 return NULL;
1195 }
1196
1197 self->type = TYPE_DISCONNECT;
1198 self->handle = (HANDLE)Socket;
1199
1200 Py_BEGIN_ALLOW_THREADS
1201 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1202 Py_END_ALLOW_THREADS
1203
1204 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1205 switch (err) {
1206 case ERROR_SUCCESS:
1207 case ERROR_IO_PENDING:
1208 Py_RETURN_NONE;
1209 default:
Victor Stinner54850852019-01-11 14:35:14 +01001210 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001211 return SetFromWindowsErr(err);
1212 }
1213}
1214
1215PyDoc_STRVAR(
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001216 Overlapped_TransmitFile_doc,
1217 "TransmitFile(socket, file, offset, offset_high, "
1218 "count_to_write, count_per_send, flags) "
1219 "-> Overlapped[None]\n\n"
1220 "Transmit file data over a connected socket.");
1221
1222static PyObject *
1223Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
1224{
1225 SOCKET Socket;
1226 HANDLE File;
1227 DWORD offset;
1228 DWORD offset_high;
1229 DWORD count_to_write;
1230 DWORD count_per_send;
1231 DWORD flags;
1232 BOOL ret;
1233 DWORD err;
1234
1235 if (!PyArg_ParseTuple(args,
1236 F_HANDLE F_HANDLE F_DWORD F_DWORD
1237 F_DWORD F_DWORD F_DWORD,
1238 &Socket, &File, &offset, &offset_high,
1239 &count_to_write, &count_per_send,
1240 &flags))
1241 return NULL;
1242
1243 if (self->type != TYPE_NONE) {
1244 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1245 return NULL;
1246 }
1247
1248 self->type = TYPE_TRANSMIT_FILE;
1249 self->handle = (HANDLE)Socket;
1250 self->overlapped.Offset = offset;
1251 self->overlapped.OffsetHigh = offset_high;
1252
1253 Py_BEGIN_ALLOW_THREADS
1254 ret = Py_TransmitFile(Socket, File, count_to_write, count_per_send,
1255 &self->overlapped,
1256 NULL, flags);
1257 Py_END_ALLOW_THREADS
1258
1259 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1260 switch (err) {
1261 case ERROR_SUCCESS:
1262 case ERROR_IO_PENDING:
1263 Py_RETURN_NONE;
1264 default:
Victor Stinner54850852019-01-11 14:35:14 +01001265 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001266 return SetFromWindowsErr(err);
1267 }
1268}
1269
1270PyDoc_STRVAR(
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001271 Overlapped_ConnectNamedPipe_doc,
1272 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1273 "Start overlapped wait for a client to connect.");
1274
1275static PyObject *
1276Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1277{
1278 HANDLE Pipe;
1279 BOOL ret;
1280 DWORD err;
1281
1282 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1283 return NULL;
1284
1285 if (self->type != TYPE_NONE) {
1286 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1287 return NULL;
1288 }
1289
1290 self->type = TYPE_CONNECT_NAMED_PIPE;
1291 self->handle = Pipe;
1292
1293 Py_BEGIN_ALLOW_THREADS
1294 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1295 Py_END_ALLOW_THREADS
1296
1297 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1298 switch (err) {
1299 case ERROR_PIPE_CONNECTED:
1300 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001301 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001302 case ERROR_SUCCESS:
1303 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001304 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001305 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
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001311PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001312 ConnectPipe_doc,
1313 "ConnectPipe(addr) -> pipe_handle\n\n"
1314 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001315
1316static PyObject *
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001317ConnectPipe(OverlappedObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001318{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001319 PyObject *AddressObj;
1320 wchar_t *Address;
1321 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001322
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001323 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001324 return NULL;
1325
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001326 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1327 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001328 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001329
Victor Stinner498b1f62015-01-26 22:43:39 +01001330 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001331 PipeHandle = CreateFileW(Address,
1332 GENERIC_READ | GENERIC_WRITE,
1333 0, NULL, OPEN_EXISTING,
1334 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001335 Py_END_ALLOW_THREADS
1336
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001337 PyMem_Free(Address);
1338 if (PipeHandle == INVALID_HANDLE_VALUE)
1339 return SetFromWindowsErr(0);
1340 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001341}
1342
1343static PyObject*
1344Overlapped_getaddress(OverlappedObject *self)
1345{
1346 return PyLong_FromVoidPtr(&self->overlapped);
1347}
1348
1349static PyObject*
1350Overlapped_getpending(OverlappedObject *self)
1351{
1352 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1353 self->type != TYPE_NOT_STARTED);
1354}
1355
Victor Stinner54850852019-01-11 14:35:14 +01001356static int
1357Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1358{
1359 switch (self->type) {
1360 case TYPE_READ:
1361 case TYPE_ACCEPT:
1362 Py_VISIT(self->allocated_buffer);
1363 break;
1364 case TYPE_WRITE:
1365 case TYPE_READINTO:
1366 if (self->user_buffer.obj) {
1367 Py_VISIT(&self->user_buffer.obj);
1368 }
1369 break;
1370 }
1371 return 0;
1372}
1373
1374
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001375static PyMethodDef Overlapped_methods[] = {
1376 {"getresult", (PyCFunction) Overlapped_getresult,
1377 METH_VARARGS, Overlapped_getresult_doc},
1378 {"cancel", (PyCFunction) Overlapped_cancel,
1379 METH_NOARGS, Overlapped_cancel_doc},
1380 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1381 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001382 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1383 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001384 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1385 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001386 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1387 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001388 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1389 METH_VARARGS, Overlapped_WriteFile_doc},
1390 {"WSASend", (PyCFunction) Overlapped_WSASend,
1391 METH_VARARGS, Overlapped_WSASend_doc},
1392 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1393 METH_VARARGS, Overlapped_AcceptEx_doc},
1394 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1395 METH_VARARGS, Overlapped_ConnectEx_doc},
1396 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1397 METH_VARARGS, Overlapped_DisconnectEx_doc},
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001398 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1399 METH_VARARGS, Overlapped_TransmitFile_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001400 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1401 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001402 {NULL}
1403};
1404
1405static PyMemberDef Overlapped_members[] = {
1406 {"error", T_ULONG,
1407 offsetof(OverlappedObject, error),
1408 READONLY, "Error from last operation"},
1409 {"event", T_HANDLE,
1410 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1411 READONLY, "Overlapped event handle"},
1412 {NULL}
1413};
1414
1415static PyGetSetDef Overlapped_getsets[] = {
1416 {"address", (getter)Overlapped_getaddress, NULL,
1417 "Address of overlapped structure"},
1418 {"pending", (getter)Overlapped_getpending, NULL,
1419 "Whether the operation is pending"},
1420 {NULL},
1421};
1422
1423PyTypeObject OverlappedType = {
1424 PyVarObject_HEAD_INIT(NULL, 0)
1425 /* tp_name */ "_overlapped.Overlapped",
1426 /* tp_basicsize */ sizeof(OverlappedObject),
1427 /* tp_itemsize */ 0,
1428 /* tp_dealloc */ (destructor) Overlapped_dealloc,
1429 /* tp_print */ 0,
1430 /* tp_getattr */ 0,
1431 /* tp_setattr */ 0,
1432 /* tp_reserved */ 0,
1433 /* tp_repr */ 0,
1434 /* tp_as_number */ 0,
1435 /* tp_as_sequence */ 0,
1436 /* tp_as_mapping */ 0,
1437 /* tp_hash */ 0,
1438 /* tp_call */ 0,
1439 /* tp_str */ 0,
1440 /* tp_getattro */ 0,
1441 /* tp_setattro */ 0,
1442 /* tp_as_buffer */ 0,
1443 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1444 /* tp_doc */ "OVERLAPPED structure wrapper",
Victor Stinner54850852019-01-11 14:35:14 +01001445 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001446 /* tp_clear */ 0,
1447 /* tp_richcompare */ 0,
1448 /* tp_weaklistoffset */ 0,
1449 /* tp_iter */ 0,
1450 /* tp_iternext */ 0,
1451 /* tp_methods */ Overlapped_methods,
1452 /* tp_members */ Overlapped_members,
1453 /* tp_getset */ Overlapped_getsets,
1454 /* tp_base */ 0,
1455 /* tp_dict */ 0,
1456 /* tp_descr_get */ 0,
1457 /* tp_descr_set */ 0,
1458 /* tp_dictoffset */ 0,
1459 /* tp_init */ 0,
1460 /* tp_alloc */ 0,
1461 /* tp_new */ Overlapped_new,
1462};
1463
1464static PyMethodDef overlapped_functions[] = {
1465 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1466 METH_VARARGS, CreateIoCompletionPort_doc},
1467 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1468 METH_VARARGS, GetQueuedCompletionStatus_doc},
1469 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1470 METH_VARARGS, PostQueuedCompletionStatus_doc},
1471 {"FormatMessage", overlapped_FormatMessage,
1472 METH_VARARGS, FormatMessage_doc},
1473 {"BindLocal", overlapped_BindLocal,
1474 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001475 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1476 METH_VARARGS, RegisterWaitWithQueue_doc},
1477 {"UnregisterWait", overlapped_UnregisterWait,
1478 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001479 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1480 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001481 {"CreateEvent", overlapped_CreateEvent,
1482 METH_VARARGS, CreateEvent_doc},
1483 {"SetEvent", overlapped_SetEvent,
1484 METH_VARARGS, SetEvent_doc},
1485 {"ResetEvent", overlapped_ResetEvent,
1486 METH_VARARGS, ResetEvent_doc},
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001487 {"ConnectPipe",
1488 (PyCFunction) ConnectPipe,
1489 METH_VARARGS, ConnectPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001490 {NULL}
1491};
1492
1493static struct PyModuleDef overlapped_module = {
1494 PyModuleDef_HEAD_INIT,
1495 "_overlapped",
1496 NULL,
1497 -1,
1498 overlapped_functions,
1499 NULL,
1500 NULL,
1501 NULL,
1502 NULL
1503};
1504
1505#define WINAPI_CONSTANT(fmt, con) \
1506 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1507
1508PyMODINIT_FUNC
1509PyInit__overlapped(void)
1510{
1511 PyObject *m, *d;
1512
1513 /* Ensure WSAStartup() called before initializing function pointers */
1514 m = PyImport_ImportModule("_socket");
1515 if (!m)
1516 return NULL;
1517 Py_DECREF(m);
1518
1519 if (initialize_function_pointers() < 0)
1520 return NULL;
1521
1522 if (PyType_Ready(&OverlappedType) < 0)
1523 return NULL;
1524
1525 m = PyModule_Create(&overlapped_module);
1526 if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
1527 return NULL;
1528
1529 d = PyModule_GetDict(m);
1530
1531 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1532 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001533 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001534 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001535 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001536 WINAPI_CONSTANT(F_DWORD, INFINITE);
1537 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1538 WINAPI_CONSTANT(F_HANDLE, NULL);
1539 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1540 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1541 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1542
1543 return m;
1544}