blob: 7798856bee7304d12051b06b96a4aaa823bb8320 [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,
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -080042 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;
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -080092static 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;
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -0800106 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) ||
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -0800119 !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 */
130 hKernel32 = GetModuleHandle("KERNEL32");
131 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
132 return 0;
133}
134
135/*
136 * Completion port stuff
137 */
138
139PyDoc_STRVAR(
140 CreateIoCompletionPort_doc,
141 "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
142 "Create a completion port or register a handle with a port.");
143
144static PyObject *
145overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
146{
147 HANDLE FileHandle;
148 HANDLE ExistingCompletionPort;
149 ULONG_PTR CompletionKey;
150 DWORD NumberOfConcurrentThreads;
151 HANDLE ret;
152
153 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
154 &FileHandle, &ExistingCompletionPort, &CompletionKey,
155 &NumberOfConcurrentThreads))
156 return NULL;
157
158 Py_BEGIN_ALLOW_THREADS
159 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
160 CompletionKey, NumberOfConcurrentThreads);
161 Py_END_ALLOW_THREADS
162
163 if (ret == NULL)
164 return SetFromWindowsErr(0);
165 return Py_BuildValue(F_HANDLE, ret);
166}
167
168PyDoc_STRVAR(
169 GetQueuedCompletionStatus_doc,
170 "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
171 "Get a message from completion port. Wait for up to msecs milliseconds.");
172
173static PyObject *
174overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
175{
176 HANDLE CompletionPort = NULL;
177 DWORD NumberOfBytes = 0;
178 ULONG_PTR CompletionKey = 0;
179 OVERLAPPED *Overlapped = NULL;
180 DWORD Milliseconds;
181 DWORD err;
182 BOOL ret;
183
184 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
185 &CompletionPort, &Milliseconds))
186 return NULL;
187
188 Py_BEGIN_ALLOW_THREADS
189 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
190 &CompletionKey, &Overlapped, Milliseconds);
191 Py_END_ALLOW_THREADS
192
193 err = ret ? ERROR_SUCCESS : GetLastError();
194 if (Overlapped == NULL) {
195 if (err == WAIT_TIMEOUT)
196 Py_RETURN_NONE;
197 else
198 return SetFromWindowsErr(err);
199 }
200 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
201 err, NumberOfBytes, CompletionKey, Overlapped);
202}
203
204PyDoc_STRVAR(
205 PostQueuedCompletionStatus_doc,
206 "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
207 "Post a message to completion port.");
208
209static PyObject *
210overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
211{
212 HANDLE CompletionPort;
213 DWORD NumberOfBytes;
214 ULONG_PTR CompletionKey;
215 OVERLAPPED *Overlapped;
216 BOOL ret;
217
218 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
219 &CompletionPort, &NumberOfBytes, &CompletionKey,
220 &Overlapped))
221 return NULL;
222
223 Py_BEGIN_ALLOW_THREADS
224 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
225 CompletionKey, Overlapped);
226 Py_END_ALLOW_THREADS
227
228 if (!ret)
229 return SetFromWindowsErr(0);
230 Py_RETURN_NONE;
231}
232
233/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700234 * Wait for a handle
235 */
236
237struct PostCallbackData {
238 HANDLE CompletionPort;
239 LPOVERLAPPED Overlapped;
240};
241
242static VOID CALLBACK
243PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
244{
245 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
246
247 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
248 0, p->Overlapped);
249 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100250 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700251}
252
253PyDoc_STRVAR(
254 RegisterWaitWithQueue_doc,
255 "RegisterWaitWithQueue(Object, CompletionPort, Overlapped, Timeout)\n"
256 " -> WaitHandle\n\n"
257 "Register wait for Object; when complete CompletionPort is notified.\n");
258
259static PyObject *
260overlapped_RegisterWaitWithQueue(PyObject *self, PyObject *args)
261{
262 HANDLE NewWaitObject;
263 HANDLE Object;
264 ULONG Milliseconds;
265 struct PostCallbackData data, *pdata;
266
267 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_POINTER F_DWORD,
268 &Object,
269 &data.CompletionPort,
270 &data.Overlapped,
271 &Milliseconds))
272 return NULL;
273
Victor Stinner6150f312016-03-16 23:25:02 +0100274 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
275 PostToQueueCallback() will call PyMem_Free() from a new C thread
276 which doesn't hold the GIL. */
277 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700278 if (pdata == NULL)
279 return SetFromWindowsErr(0);
280
281 *pdata = data;
282
283 if (!RegisterWaitForSingleObject(
284 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
285 pdata, Milliseconds,
286 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
287 {
Victor Stinner6150f312016-03-16 23:25:02 +0100288 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700289 return SetFromWindowsErr(0);
290 }
291
292 return Py_BuildValue(F_HANDLE, NewWaitObject);
293}
294
295PyDoc_STRVAR(
296 UnregisterWait_doc,
297 "UnregisterWait(WaitHandle) -> None\n\n"
298 "Unregister wait handle.\n");
299
300static PyObject *
301overlapped_UnregisterWait(PyObject *self, PyObject *args)
302{
303 HANDLE WaitHandle;
304 BOOL ret;
305
306 if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
307 return NULL;
308
309 Py_BEGIN_ALLOW_THREADS
310 ret = UnregisterWait(WaitHandle);
311 Py_END_ALLOW_THREADS
312
313 if (!ret)
314 return SetFromWindowsErr(0);
315 Py_RETURN_NONE;
316}
317
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100318PyDoc_STRVAR(
319 UnregisterWaitEx_doc,
320 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
321 "Unregister wait handle.\n");
322
323static PyObject *
324overlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
325{
326 HANDLE WaitHandle, Event;
327 BOOL ret;
328
329 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
330 return NULL;
331
332 Py_BEGIN_ALLOW_THREADS
333 ret = UnregisterWaitEx(WaitHandle, Event);
334 Py_END_ALLOW_THREADS
335
336 if (!ret)
337 return SetFromWindowsErr(0);
338 Py_RETURN_NONE;
339}
340
Guido van Rossum90fb9142013-10-30 14:44:05 -0700341/*
342 * Event functions -- currently only used by tests
343 */
344
345PyDoc_STRVAR(
346 CreateEvent_doc,
347 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
348 " -> Handle\n\n"
349 "Create an event. EventAttributes must be None.\n");
350
351static PyObject *
352overlapped_CreateEvent(PyObject *self, PyObject *args)
353{
354 PyObject *EventAttributes;
355 BOOL ManualReset;
356 BOOL InitialState;
357 Py_UNICODE *Name;
358 HANDLE Event;
359
360 if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
361 &EventAttributes, &ManualReset,
362 &InitialState, &Name))
363 return NULL;
364
365 if (EventAttributes != Py_None) {
366 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
367 return NULL;
368 }
369
370 Py_BEGIN_ALLOW_THREADS
371 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
372 Py_END_ALLOW_THREADS
373
374 if (Event == NULL)
375 return SetFromWindowsErr(0);
376 return Py_BuildValue(F_HANDLE, Event);
377}
378
379PyDoc_STRVAR(
380 SetEvent_doc,
381 "SetEvent(Handle) -> None\n\n"
382 "Set event.\n");
383
384static PyObject *
385overlapped_SetEvent(PyObject *self, PyObject *args)
386{
387 HANDLE Handle;
388 BOOL ret;
389
390 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
391 return NULL;
392
393 Py_BEGIN_ALLOW_THREADS
394 ret = SetEvent(Handle);
395 Py_END_ALLOW_THREADS
396
397 if (!ret)
398 return SetFromWindowsErr(0);
399 Py_RETURN_NONE;
400}
401
402PyDoc_STRVAR(
403 ResetEvent_doc,
404 "ResetEvent(Handle) -> None\n\n"
405 "Reset event.\n");
406
407static PyObject *
408overlapped_ResetEvent(PyObject *self, PyObject *args)
409{
410 HANDLE Handle;
411 BOOL ret;
412
413 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
414 return NULL;
415
416 Py_BEGIN_ALLOW_THREADS
417 ret = ResetEvent(Handle);
418 Py_END_ALLOW_THREADS
419
420 if (!ret)
421 return SetFromWindowsErr(0);
422 Py_RETURN_NONE;
423}
424
425/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700426 * Bind socket handle to local port without doing slow getaddrinfo()
427 */
428
429PyDoc_STRVAR(
430 BindLocal_doc,
431 "BindLocal(handle, family) -> None\n\n"
432 "Bind a socket handle to an arbitrary local port.\n"
433 "family should AF_INET or AF_INET6.\n");
434
435static PyObject *
436overlapped_BindLocal(PyObject *self, PyObject *args)
437{
438 SOCKET Socket;
439 int Family;
440 BOOL ret;
441
442 if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
443 return NULL;
444
445 if (Family == AF_INET) {
446 struct sockaddr_in addr;
447 memset(&addr, 0, sizeof(addr));
448 addr.sin_family = AF_INET;
449 addr.sin_port = 0;
450 addr.sin_addr.S_un.S_addr = INADDR_ANY;
451 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
452 } else if (Family == AF_INET6) {
453 struct sockaddr_in6 addr;
454 memset(&addr, 0, sizeof(addr));
455 addr.sin6_family = AF_INET6;
456 addr.sin6_port = 0;
457 addr.sin6_addr = in6addr_any;
458 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
459 } else {
460 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
461 return NULL;
462 }
463
464 if (!ret)
465 return SetFromWindowsErr(WSAGetLastError());
466 Py_RETURN_NONE;
467}
468
469/*
470 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
471 */
472
473PyDoc_STRVAR(
474 FormatMessage_doc,
475 "FormatMessage(error_code) -> error_message\n\n"
476 "Return error message for an error code.");
477
478static PyObject *
479overlapped_FormatMessage(PyObject *ignore, PyObject *args)
480{
481 DWORD code, n;
482 WCHAR *lpMsgBuf;
483 PyObject *res;
484
485 if (!PyArg_ParseTuple(args, F_DWORD, &code))
486 return NULL;
487
488 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
489 FORMAT_MESSAGE_FROM_SYSTEM,
490 NULL,
491 code,
492 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
493 (LPWSTR) &lpMsgBuf,
494 0,
495 NULL);
496 if (n) {
497 while (iswspace(lpMsgBuf[n-1]))
498 --n;
499 lpMsgBuf[n] = L'\0';
500 res = Py_BuildValue("u", lpMsgBuf);
501 } else {
502 res = PyUnicode_FromFormat("unknown error code %u", code);
503 }
504 LocalFree(lpMsgBuf);
505 return res;
506}
507
508
509/*
510 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
511 */
512
513static void
514mark_as_completed(OVERLAPPED *ov)
515{
516 ov->Internal = 0;
517 if (ov->hEvent != NULL)
518 SetEvent(ov->hEvent);
519}
520
521/*
522 * A Python object wrapping an OVERLAPPED structure and other useful data
523 * for overlapped I/O
524 */
525
526PyDoc_STRVAR(
527 Overlapped_doc,
528 "Overlapped object");
529
530static PyObject *
531Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
532{
533 OverlappedObject *self;
534 HANDLE event = INVALID_HANDLE_VALUE;
535 static char *kwlist[] = {"event", NULL};
536
537 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
538 return NULL;
539
540 if (event == INVALID_HANDLE_VALUE) {
541 event = CreateEvent(NULL, TRUE, FALSE, NULL);
542 if (event == NULL)
543 return SetFromWindowsErr(0);
544 }
545
546 self = PyObject_New(OverlappedObject, type);
547 if (self == NULL) {
548 if (event != NULL)
549 CloseHandle(event);
550 return NULL;
551 }
552
553 self->handle = NULL;
554 self->error = 0;
555 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200556 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700557 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200558 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700559 if (event)
560 self->overlapped.hEvent = event;
561 return (PyObject *)self;
562}
563
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800564
565/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
566 buffers while overlapped are still running, to prevent a crash. */
567static int
568Overlapped_clear(OverlappedObject *self)
569{
570 switch (self->type) {
571 case TYPE_READ:
572 case TYPE_ACCEPT:
573 Py_CLEAR(self->allocated_buffer);
574 break;
575 case TYPE_WRITE:
576 case TYPE_READINTO:
577 if (self->user_buffer.obj) {
578 PyBuffer_Release(&self->user_buffer);
579 }
580 break;
581 }
582 self->type = TYPE_NOT_STARTED;
583 return 0;
584}
585
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700586static void
587Overlapped_dealloc(OverlappedObject *self)
588{
589 DWORD bytes;
590 DWORD olderr = GetLastError();
591 BOOL wait = FALSE;
592 BOOL ret;
593
594 if (!HasOverlappedIoCompleted(&self->overlapped) &&
595 self->type != TYPE_NOT_STARTED)
596 {
597 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
598 wait = TRUE;
599
600 Py_BEGIN_ALLOW_THREADS
601 ret = GetOverlappedResult(self->handle, &self->overlapped,
602 &bytes, wait);
603 Py_END_ALLOW_THREADS
604
605 switch (ret ? ERROR_SUCCESS : GetLastError()) {
606 case ERROR_SUCCESS:
607 case ERROR_NOT_FOUND:
608 case ERROR_OPERATION_ABORTED:
609 break;
610 default:
611 PyErr_Format(
612 PyExc_RuntimeError,
613 "%R still has pending operation at "
614 "deallocation, the process may crash", self);
615 PyErr_WriteUnraisable(NULL);
616 }
617 }
618
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800619 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700620 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700621 }
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800622
623 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700624 PyObject_Del(self);
625 SetLastError(olderr);
626}
627
628PyDoc_STRVAR(
629 Overlapped_cancel_doc,
630 "cancel() -> None\n\n"
631 "Cancel overlapped operation");
632
633static PyObject *
634Overlapped_cancel(OverlappedObject *self)
635{
636 BOOL ret = TRUE;
637
638 if (self->type == TYPE_NOT_STARTED
639 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
640 Py_RETURN_NONE;
641
642 if (!HasOverlappedIoCompleted(&self->overlapped)) {
643 Py_BEGIN_ALLOW_THREADS
644 if (Py_CancelIoEx)
645 ret = Py_CancelIoEx(self->handle, &self->overlapped);
646 else
647 ret = CancelIo(self->handle);
648 Py_END_ALLOW_THREADS
649 }
650
651 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
652 if (!ret && GetLastError() != ERROR_NOT_FOUND)
653 return SetFromWindowsErr(0);
654 Py_RETURN_NONE;
655}
656
657PyDoc_STRVAR(
658 Overlapped_getresult_doc,
659 "getresult(wait=False) -> result\n\n"
660 "Retrieve result of operation. If wait is true then it blocks\n"
661 "until the operation is finished. If wait is false and the\n"
662 "operation is still pending then an error is raised.");
663
664static PyObject *
665Overlapped_getresult(OverlappedObject *self, PyObject *args)
666{
667 BOOL wait = FALSE;
668 DWORD transferred = 0;
669 BOOL ret;
670 DWORD err;
671
672 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
673 return NULL;
674
675 if (self->type == TYPE_NONE) {
676 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
677 return NULL;
678 }
679
680 if (self->type == TYPE_NOT_STARTED) {
681 PyErr_SetString(PyExc_ValueError, "operation failed to start");
682 return NULL;
683 }
684
685 Py_BEGIN_ALLOW_THREADS
686 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
687 wait);
688 Py_END_ALLOW_THREADS
689
690 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
691 switch (err) {
692 case ERROR_SUCCESS:
693 case ERROR_MORE_DATA:
694 break;
695 case ERROR_BROKEN_PIPE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200696 if (self->type == TYPE_READ || self->type == TYPE_READINTO)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700697 break;
698 /* fall through */
699 default:
700 return SetFromWindowsErr(err);
701 }
702
703 switch (self->type) {
704 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200705 assert(PyBytes_CheckExact(self->allocated_buffer));
706 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
707 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700708 return NULL;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200709 Py_INCREF(self->allocated_buffer);
710 return self->allocated_buffer;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700711 default:
712 return PyLong_FromUnsignedLong((unsigned long) transferred);
713 }
714}
715
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200716static PyObject *
717do_ReadFile(OverlappedObject *self, HANDLE handle,
718 char *bufstart, DWORD buflen)
719{
720 DWORD nread;
721 int ret;
722 DWORD err;
723
724 Py_BEGIN_ALLOW_THREADS
725 ret = ReadFile(handle, bufstart, buflen, &nread,
726 &self->overlapped);
727 Py_END_ALLOW_THREADS
728
729 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
730 switch (err) {
731 case ERROR_BROKEN_PIPE:
732 mark_as_completed(&self->overlapped);
733 return SetFromWindowsErr(err);
734 case ERROR_SUCCESS:
735 case ERROR_MORE_DATA:
736 case ERROR_IO_PENDING:
737 Py_RETURN_NONE;
738 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800739 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200740 return SetFromWindowsErr(err);
741 }
742}
743
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700744PyDoc_STRVAR(
745 Overlapped_ReadFile_doc,
746 "ReadFile(handle, size) -> Overlapped[message]\n\n"
747 "Start overlapped read");
748
749static PyObject *
750Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
751{
752 HANDLE handle;
753 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700754 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700755
756 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
757 return NULL;
758
759 if (self->type != TYPE_NONE) {
760 PyErr_SetString(PyExc_ValueError, "operation already attempted");
761 return NULL;
762 }
763
764#if SIZEOF_SIZE_T <= SIZEOF_LONG
765 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
766#endif
767 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
768 if (buf == NULL)
769 return NULL;
770
771 self->type = TYPE_READ;
772 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200773 self->allocated_buffer = buf;
774
775 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
776}
777
778PyDoc_STRVAR(
779 Overlapped_ReadFileInto_doc,
780 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
781 "Start overlapped receive");
782
783static PyObject *
784Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
785{
786 HANDLE handle;
787 PyObject *bufobj;
788
789 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
790 return NULL;
791
792 if (self->type != TYPE_NONE) {
793 PyErr_SetString(PyExc_ValueError, "operation already attempted");
794 return NULL;
795 }
796
797 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
798 return NULL;
799
800#if SIZEOF_SIZE_T > SIZEOF_LONG
801 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
802 PyBuffer_Release(&self->user_buffer);
803 PyErr_SetString(PyExc_ValueError, "buffer too large");
804 return NULL;
805 }
806#endif
807
808 self->type = TYPE_READINTO;
809 self->handle = handle;
810
811 return do_ReadFile(self, handle, self->user_buffer.buf,
812 (DWORD)self->user_buffer.len);
813}
814
815static PyObject *
816do_WSARecv(OverlappedObject *self, HANDLE handle,
817 char *bufstart, DWORD buflen, DWORD flags)
818{
819 DWORD nread;
820 WSABUF wsabuf;
821 int ret;
822 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300823
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200824 wsabuf.buf = bufstart;
825 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700826
827 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200828 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
829 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700830 Py_END_ALLOW_THREADS
831
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200832 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700833 switch (err) {
834 case ERROR_BROKEN_PIPE:
835 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100836 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700837 case ERROR_SUCCESS:
838 case ERROR_MORE_DATA:
839 case ERROR_IO_PENDING:
840 Py_RETURN_NONE;
841 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800842 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700843 return SetFromWindowsErr(err);
844 }
845}
846
847PyDoc_STRVAR(
848 Overlapped_WSARecv_doc,
849 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
850 "Start overlapped receive");
851
852static PyObject *
853Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
854{
855 HANDLE handle;
856 DWORD size;
857 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700858 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700859
860 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
861 &handle, &size, &flags))
862 return NULL;
863
864 if (self->type != TYPE_NONE) {
865 PyErr_SetString(PyExc_ValueError, "operation already attempted");
866 return NULL;
867 }
868
869#if SIZEOF_SIZE_T <= SIZEOF_LONG
870 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
871#endif
872 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
873 if (buf == NULL)
874 return NULL;
875
876 self->type = TYPE_READ;
877 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200878 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700879
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200880 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
881}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700882
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200883PyDoc_STRVAR(
884 Overlapped_WSARecvInto_doc,
885 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
886 "Start overlapped receive");
887
888static PyObject *
889Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
890{
891 HANDLE handle;
892 PyObject *bufobj;
893 DWORD flags;
894
895 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
896 &handle, &bufobj, &flags))
897 return NULL;
898
899 if (self->type != TYPE_NONE) {
900 PyErr_SetString(PyExc_ValueError, "operation already attempted");
901 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700902 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200903
904 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
905 return NULL;
906
907#if SIZEOF_SIZE_T > SIZEOF_LONG
908 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
909 PyBuffer_Release(&self->user_buffer);
910 PyErr_SetString(PyExc_ValueError, "buffer too large");
911 return NULL;
912 }
913#endif
914
915 self->type = TYPE_READINTO;
916 self->handle = handle;
917
918 return do_WSARecv(self, handle, self->user_buffer.buf,
919 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700920}
921
922PyDoc_STRVAR(
923 Overlapped_WriteFile_doc,
924 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
925 "Start overlapped write");
926
927static PyObject *
928Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
929{
930 HANDLE handle;
931 PyObject *bufobj;
932 DWORD written;
933 BOOL ret;
934 DWORD err;
935
936 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
937 return NULL;
938
939 if (self->type != TYPE_NONE) {
940 PyErr_SetString(PyExc_ValueError, "operation already attempted");
941 return NULL;
942 }
943
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200944 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700945 return NULL;
946
947#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200948 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
949 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300950 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700951 return NULL;
952 }
953#endif
954
955 self->type = TYPE_WRITE;
956 self->handle = handle;
957
958 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200959 ret = WriteFile(handle, self->user_buffer.buf,
960 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700961 &written, &self->overlapped);
962 Py_END_ALLOW_THREADS
963
964 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
965 switch (err) {
966 case ERROR_SUCCESS:
967 case ERROR_IO_PENDING:
968 Py_RETURN_NONE;
969 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -0800970 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700971 return SetFromWindowsErr(err);
972 }
973}
974
975PyDoc_STRVAR(
976 Overlapped_WSASend_doc,
977 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
978 "Start overlapped send");
979
980static PyObject *
981Overlapped_WSASend(OverlappedObject *self, PyObject *args)
982{
983 HANDLE handle;
984 PyObject *bufobj;
985 DWORD flags;
986 DWORD written;
987 WSABUF wsabuf;
988 int ret;
989 DWORD err;
990
991 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
992 &handle, &bufobj, &flags))
993 return NULL;
994
995 if (self->type != TYPE_NONE) {
996 PyErr_SetString(PyExc_ValueError, "operation already attempted");
997 return NULL;
998 }
999
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001000 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001001 return NULL;
1002
1003#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001004 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1005 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001006 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001007 return NULL;
1008 }
1009#endif
1010
1011 self->type = TYPE_WRITE;
1012 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001013 wsabuf.len = (DWORD)self->user_buffer.len;
1014 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001015
1016 Py_BEGIN_ALLOW_THREADS
1017 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1018 &self->overlapped, NULL);
1019 Py_END_ALLOW_THREADS
1020
1021 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1022 switch (err) {
1023 case ERROR_SUCCESS:
1024 case ERROR_IO_PENDING:
1025 Py_RETURN_NONE;
1026 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001027 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001028 return SetFromWindowsErr(err);
1029 }
1030}
1031
1032PyDoc_STRVAR(
1033 Overlapped_AcceptEx_doc,
1034 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1035 "Start overlapped wait for client to connect");
1036
1037static PyObject *
1038Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1039{
1040 SOCKET ListenSocket;
1041 SOCKET AcceptSocket;
1042 DWORD BytesReceived;
1043 DWORD size;
1044 PyObject *buf;
1045 BOOL ret;
1046 DWORD err;
1047
1048 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1049 &ListenSocket, &AcceptSocket))
1050 return NULL;
1051
1052 if (self->type != TYPE_NONE) {
1053 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1054 return NULL;
1055 }
1056
1057 size = sizeof(struct sockaddr_in6) + 16;
1058 buf = PyBytes_FromStringAndSize(NULL, size*2);
1059 if (!buf)
1060 return NULL;
1061
1062 self->type = TYPE_ACCEPT;
1063 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001064 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001065
1066 Py_BEGIN_ALLOW_THREADS
1067 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1068 0, size, size, &BytesReceived, &self->overlapped);
1069 Py_END_ALLOW_THREADS
1070
1071 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1072 switch (err) {
1073 case ERROR_SUCCESS:
1074 case ERROR_IO_PENDING:
1075 Py_RETURN_NONE;
1076 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001077 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001078 return SetFromWindowsErr(err);
1079 }
1080}
1081
1082
1083static int
1084parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1085{
Steve Dowercc16be82016-09-08 10:35:16 -07001086 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001087 unsigned short Port;
1088 unsigned long FlowInfo;
1089 unsigned long ScopeId;
1090
1091 memset(Address, 0, Length);
1092
Steve Dowercc16be82016-09-08 10:35:16 -07001093 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001094 {
1095 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001096 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001097 SetFromWindowsErr(WSAGetLastError());
1098 return -1;
1099 }
1100 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1101 return Length;
1102 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001103 else if (PyArg_ParseTuple(obj,
1104 "uHkk;ConnectEx(): illegal address_as_bytes "
1105 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001106 {
1107 PyErr_Clear();
1108 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001109 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001110 SetFromWindowsErr(WSAGetLastError());
1111 return -1;
1112 }
1113 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1114 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1115 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1116 return Length;
1117 }
1118
1119 return -1;
1120}
1121
1122
1123PyDoc_STRVAR(
1124 Overlapped_ConnectEx_doc,
1125 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1126 "Start overlapped connect. client_handle should be unbound.");
1127
1128static PyObject *
1129Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1130{
1131 SOCKET ConnectSocket;
1132 PyObject *AddressObj;
1133 char AddressBuf[sizeof(struct sockaddr_in6)];
1134 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1135 int Length;
1136 BOOL ret;
1137 DWORD err;
1138
Oren Milman1d1d3e92017-08-20 18:35:36 +03001139 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1140 &ConnectSocket, &PyTuple_Type, &AddressObj))
1141 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001142 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001143 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001144
1145 if (self->type != TYPE_NONE) {
1146 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1147 return NULL;
1148 }
1149
1150 Length = sizeof(AddressBuf);
1151 Length = parse_address(AddressObj, Address, Length);
1152 if (Length < 0)
1153 return NULL;
1154
1155 self->type = TYPE_CONNECT;
1156 self->handle = (HANDLE)ConnectSocket;
1157
1158 Py_BEGIN_ALLOW_THREADS
1159 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1160 NULL, 0, NULL, &self->overlapped);
1161 Py_END_ALLOW_THREADS
1162
1163 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1164 switch (err) {
1165 case ERROR_SUCCESS:
1166 case ERROR_IO_PENDING:
1167 Py_RETURN_NONE;
1168 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001169 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001170 return SetFromWindowsErr(err);
1171 }
1172}
1173
1174PyDoc_STRVAR(
1175 Overlapped_DisconnectEx_doc,
1176 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1177 "Start overlapped connect. client_handle should be unbound.");
1178
1179static PyObject *
1180Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1181{
1182 SOCKET Socket;
1183 DWORD flags;
1184 BOOL ret;
1185 DWORD err;
1186
1187 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1188 return NULL;
1189
1190 if (self->type != TYPE_NONE) {
1191 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1192 return NULL;
1193 }
1194
1195 self->type = TYPE_DISCONNECT;
1196 self->handle = (HANDLE)Socket;
1197
1198 Py_BEGIN_ALLOW_THREADS
1199 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1200 Py_END_ALLOW_THREADS
1201
1202 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1203 switch (err) {
1204 case ERROR_SUCCESS:
1205 case ERROR_IO_PENDING:
1206 Py_RETURN_NONE;
1207 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001208 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001209 return SetFromWindowsErr(err);
1210 }
1211}
1212
1213PyDoc_STRVAR(
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -08001214 Overlapped_TransmitFile_doc,
1215 "TransmitFile(socket, file, offset, offset_high, "
1216 "count_to_write, count_per_send, flags) "
1217 "-> Overlapped[None]\n\n"
1218 "Transmit file data over a connected socket.");
1219
1220static PyObject *
1221Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
1222{
1223 SOCKET Socket;
1224 HANDLE File;
1225 DWORD offset;
1226 DWORD offset_high;
1227 DWORD count_to_write;
1228 DWORD count_per_send;
1229 DWORD flags;
1230 BOOL ret;
1231 DWORD err;
1232
1233 if (!PyArg_ParseTuple(args,
1234 F_HANDLE F_HANDLE F_DWORD F_DWORD
1235 F_DWORD F_DWORD F_DWORD,
1236 &Socket, &File, &offset, &offset_high,
1237 &count_to_write, &count_per_send,
1238 &flags))
1239 return NULL;
1240
1241 if (self->type != TYPE_NONE) {
1242 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1243 return NULL;
1244 }
1245
1246 self->type = TYPE_TRANSMIT_FILE;
1247 self->handle = (HANDLE)Socket;
1248 self->overlapped.Offset = offset;
1249 self->overlapped.OffsetHigh = offset_high;
1250
1251 Py_BEGIN_ALLOW_THREADS
1252 ret = Py_TransmitFile(Socket, File, count_to_write, count_per_send,
1253 &self->overlapped,
1254 NULL, flags);
1255 Py_END_ALLOW_THREADS
1256
1257 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1258 switch (err) {
1259 case ERROR_SUCCESS:
1260 case ERROR_IO_PENDING:
1261 Py_RETURN_NONE;
1262 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001263 Overlapped_clear(self);
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -08001264 return SetFromWindowsErr(err);
1265 }
1266}
1267
1268PyDoc_STRVAR(
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001269 Overlapped_ConnectNamedPipe_doc,
1270 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1271 "Start overlapped wait for a client to connect.");
1272
1273static PyObject *
1274Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1275{
1276 HANDLE Pipe;
1277 BOOL ret;
1278 DWORD err;
1279
1280 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1281 return NULL;
1282
1283 if (self->type != TYPE_NONE) {
1284 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1285 return NULL;
1286 }
1287
1288 self->type = TYPE_CONNECT_NAMED_PIPE;
1289 self->handle = Pipe;
1290
1291 Py_BEGIN_ALLOW_THREADS
1292 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1293 Py_END_ALLOW_THREADS
1294
1295 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1296 switch (err) {
1297 case ERROR_PIPE_CONNECTED:
1298 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001299 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001300 case ERROR_SUCCESS:
1301 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001302 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001303 default:
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001304 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001305 return SetFromWindowsErr(err);
1306 }
1307}
1308
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001309PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001310 ConnectPipe_doc,
1311 "ConnectPipe(addr) -> pipe_handle\n\n"
1312 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001313
1314static PyObject *
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001315ConnectPipe(OverlappedObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001316{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001317 PyObject *AddressObj;
1318 wchar_t *Address;
1319 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001320
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001321 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001322 return NULL;
1323
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001324 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1325 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001326 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001327
Victor Stinner498b1f62015-01-26 22:43:39 +01001328 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001329 PipeHandle = CreateFileW(Address,
1330 GENERIC_READ | GENERIC_WRITE,
1331 0, NULL, OPEN_EXISTING,
1332 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001333 Py_END_ALLOW_THREADS
1334
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001335 PyMem_Free(Address);
1336 if (PipeHandle == INVALID_HANDLE_VALUE)
1337 return SetFromWindowsErr(0);
1338 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001339}
1340
1341static PyObject*
1342Overlapped_getaddress(OverlappedObject *self)
1343{
1344 return PyLong_FromVoidPtr(&self->overlapped);
1345}
1346
1347static PyObject*
1348Overlapped_getpending(OverlappedObject *self)
1349{
1350 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1351 self->type != TYPE_NOT_STARTED);
1352}
1353
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001354static int
1355Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1356{
1357 switch (self->type) {
1358 case TYPE_READ:
1359 case TYPE_ACCEPT:
1360 Py_VISIT(self->allocated_buffer);
1361 break;
1362 case TYPE_WRITE:
1363 case TYPE_READINTO:
1364 if (self->user_buffer.obj) {
1365 Py_VISIT(&self->user_buffer.obj);
1366 }
1367 break;
1368 }
1369 return 0;
1370}
1371
1372
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001373static PyMethodDef Overlapped_methods[] = {
1374 {"getresult", (PyCFunction) Overlapped_getresult,
1375 METH_VARARGS, Overlapped_getresult_doc},
1376 {"cancel", (PyCFunction) Overlapped_cancel,
1377 METH_NOARGS, Overlapped_cancel_doc},
1378 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1379 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001380 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1381 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001382 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1383 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001384 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1385 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001386 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1387 METH_VARARGS, Overlapped_WriteFile_doc},
1388 {"WSASend", (PyCFunction) Overlapped_WSASend,
1389 METH_VARARGS, Overlapped_WSASend_doc},
1390 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1391 METH_VARARGS, Overlapped_AcceptEx_doc},
1392 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1393 METH_VARARGS, Overlapped_ConnectEx_doc},
1394 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1395 METH_VARARGS, Overlapped_DisconnectEx_doc},
Miss Islington (bot)632c1cb2018-02-25 09:10:58 -08001396 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1397 METH_VARARGS, Overlapped_TransmitFile_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001398 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1399 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001400 {NULL}
1401};
1402
1403static PyMemberDef Overlapped_members[] = {
1404 {"error", T_ULONG,
1405 offsetof(OverlappedObject, error),
1406 READONLY, "Error from last operation"},
1407 {"event", T_HANDLE,
1408 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1409 READONLY, "Overlapped event handle"},
1410 {NULL}
1411};
1412
1413static PyGetSetDef Overlapped_getsets[] = {
1414 {"address", (getter)Overlapped_getaddress, NULL,
1415 "Address of overlapped structure"},
1416 {"pending", (getter)Overlapped_getpending, NULL,
1417 "Whether the operation is pending"},
1418 {NULL},
1419};
1420
1421PyTypeObject OverlappedType = {
1422 PyVarObject_HEAD_INIT(NULL, 0)
1423 /* tp_name */ "_overlapped.Overlapped",
1424 /* tp_basicsize */ sizeof(OverlappedObject),
1425 /* tp_itemsize */ 0,
1426 /* tp_dealloc */ (destructor) Overlapped_dealloc,
1427 /* tp_print */ 0,
1428 /* tp_getattr */ 0,
1429 /* tp_setattr */ 0,
1430 /* tp_reserved */ 0,
1431 /* tp_repr */ 0,
1432 /* tp_as_number */ 0,
1433 /* tp_as_sequence */ 0,
1434 /* tp_as_mapping */ 0,
1435 /* tp_hash */ 0,
1436 /* tp_call */ 0,
1437 /* tp_str */ 0,
1438 /* tp_getattro */ 0,
1439 /* tp_setattro */ 0,
1440 /* tp_as_buffer */ 0,
1441 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1442 /* tp_doc */ "OVERLAPPED structure wrapper",
Miss Islington (bot)059997d2019-01-11 06:01:50 -08001443 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001444 /* tp_clear */ 0,
1445 /* tp_richcompare */ 0,
1446 /* tp_weaklistoffset */ 0,
1447 /* tp_iter */ 0,
1448 /* tp_iternext */ 0,
1449 /* tp_methods */ Overlapped_methods,
1450 /* tp_members */ Overlapped_members,
1451 /* tp_getset */ Overlapped_getsets,
1452 /* tp_base */ 0,
1453 /* tp_dict */ 0,
1454 /* tp_descr_get */ 0,
1455 /* tp_descr_set */ 0,
1456 /* tp_dictoffset */ 0,
1457 /* tp_init */ 0,
1458 /* tp_alloc */ 0,
1459 /* tp_new */ Overlapped_new,
1460};
1461
1462static PyMethodDef overlapped_functions[] = {
1463 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1464 METH_VARARGS, CreateIoCompletionPort_doc},
1465 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1466 METH_VARARGS, GetQueuedCompletionStatus_doc},
1467 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1468 METH_VARARGS, PostQueuedCompletionStatus_doc},
1469 {"FormatMessage", overlapped_FormatMessage,
1470 METH_VARARGS, FormatMessage_doc},
1471 {"BindLocal", overlapped_BindLocal,
1472 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001473 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1474 METH_VARARGS, RegisterWaitWithQueue_doc},
1475 {"UnregisterWait", overlapped_UnregisterWait,
1476 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001477 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1478 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001479 {"CreateEvent", overlapped_CreateEvent,
1480 METH_VARARGS, CreateEvent_doc},
1481 {"SetEvent", overlapped_SetEvent,
1482 METH_VARARGS, SetEvent_doc},
1483 {"ResetEvent", overlapped_ResetEvent,
1484 METH_VARARGS, ResetEvent_doc},
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001485 {"ConnectPipe",
1486 (PyCFunction) ConnectPipe,
1487 METH_VARARGS, ConnectPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001488 {NULL}
1489};
1490
1491static struct PyModuleDef overlapped_module = {
1492 PyModuleDef_HEAD_INIT,
1493 "_overlapped",
1494 NULL,
1495 -1,
1496 overlapped_functions,
1497 NULL,
1498 NULL,
1499 NULL,
1500 NULL
1501};
1502
1503#define WINAPI_CONSTANT(fmt, con) \
1504 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1505
1506PyMODINIT_FUNC
1507PyInit__overlapped(void)
1508{
1509 PyObject *m, *d;
1510
1511 /* Ensure WSAStartup() called before initializing function pointers */
1512 m = PyImport_ImportModule("_socket");
1513 if (!m)
1514 return NULL;
1515 Py_DECREF(m);
1516
1517 if (initialize_function_pointers() < 0)
1518 return NULL;
1519
1520 if (PyType_Ready(&OverlappedType) < 0)
1521 return NULL;
1522
1523 m = PyModule_Create(&overlapped_module);
1524 if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
1525 return NULL;
1526
1527 d = PyModule_GetDict(m);
1528
1529 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1530 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001531 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001532 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001533 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001534 WINAPI_CONSTANT(F_DWORD, INFINITE);
1535 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1536 WINAPI_CONSTANT(F_HANDLE, NULL);
1537 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1538 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1539 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1540
1541 return m;
1542}