blob: 69875a7f37da5172705b72beaa053527845c932e [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 */
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
564static void
565Overlapped_dealloc(OverlappedObject *self)
566{
567 DWORD bytes;
568 DWORD olderr = GetLastError();
569 BOOL wait = FALSE;
570 BOOL ret;
571
572 if (!HasOverlappedIoCompleted(&self->overlapped) &&
573 self->type != TYPE_NOT_STARTED)
574 {
575 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
576 wait = TRUE;
577
578 Py_BEGIN_ALLOW_THREADS
579 ret = GetOverlappedResult(self->handle, &self->overlapped,
580 &bytes, wait);
581 Py_END_ALLOW_THREADS
582
583 switch (ret ? ERROR_SUCCESS : GetLastError()) {
584 case ERROR_SUCCESS:
585 case ERROR_NOT_FOUND:
586 case ERROR_OPERATION_ABORTED:
587 break;
588 default:
589 PyErr_Format(
590 PyExc_RuntimeError,
591 "%R still has pending operation at "
592 "deallocation, the process may crash", self);
593 PyErr_WriteUnraisable(NULL);
594 }
595 }
596
597 if (self->overlapped.hEvent != NULL)
598 CloseHandle(self->overlapped.hEvent);
599
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700600 switch (self->type) {
Victor Stinner91445fb2014-01-30 19:06:44 +0100601 case TYPE_READ:
602 case TYPE_ACCEPT:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200603 Py_CLEAR(self->allocated_buffer);
Victor Stinner91445fb2014-01-30 19:06:44 +0100604 break;
605 case TYPE_WRITE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200606 case TYPE_READINTO:
607 if (self->user_buffer.obj)
608 PyBuffer_Release(&self->user_buffer);
Victor Stinner91445fb2014-01-30 19:06:44 +0100609 break;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700610 }
611 PyObject_Del(self);
612 SetLastError(olderr);
613}
614
615PyDoc_STRVAR(
616 Overlapped_cancel_doc,
617 "cancel() -> None\n\n"
618 "Cancel overlapped operation");
619
620static PyObject *
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530621Overlapped_cancel(OverlappedObject *self, PyObject *Py_UNUSED(ignored))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700622{
623 BOOL ret = TRUE;
624
625 if (self->type == TYPE_NOT_STARTED
626 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
627 Py_RETURN_NONE;
628
629 if (!HasOverlappedIoCompleted(&self->overlapped)) {
630 Py_BEGIN_ALLOW_THREADS
631 if (Py_CancelIoEx)
632 ret = Py_CancelIoEx(self->handle, &self->overlapped);
633 else
634 ret = CancelIo(self->handle);
635 Py_END_ALLOW_THREADS
636 }
637
638 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
639 if (!ret && GetLastError() != ERROR_NOT_FOUND)
640 return SetFromWindowsErr(0);
641 Py_RETURN_NONE;
642}
643
644PyDoc_STRVAR(
645 Overlapped_getresult_doc,
646 "getresult(wait=False) -> result\n\n"
647 "Retrieve result of operation. If wait is true then it blocks\n"
648 "until the operation is finished. If wait is false and the\n"
649 "operation is still pending then an error is raised.");
650
651static PyObject *
652Overlapped_getresult(OverlappedObject *self, PyObject *args)
653{
654 BOOL wait = FALSE;
655 DWORD transferred = 0;
656 BOOL ret;
657 DWORD err;
658
659 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
660 return NULL;
661
662 if (self->type == TYPE_NONE) {
663 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
664 return NULL;
665 }
666
667 if (self->type == TYPE_NOT_STARTED) {
668 PyErr_SetString(PyExc_ValueError, "operation failed to start");
669 return NULL;
670 }
671
672 Py_BEGIN_ALLOW_THREADS
673 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
674 wait);
675 Py_END_ALLOW_THREADS
676
677 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
678 switch (err) {
679 case ERROR_SUCCESS:
680 case ERROR_MORE_DATA:
681 break;
682 case ERROR_BROKEN_PIPE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200683 if (self->type == TYPE_READ || self->type == TYPE_READINTO)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700684 break;
685 /* fall through */
686 default:
687 return SetFromWindowsErr(err);
688 }
689
690 switch (self->type) {
691 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200692 assert(PyBytes_CheckExact(self->allocated_buffer));
693 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
694 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700695 return NULL;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200696 Py_INCREF(self->allocated_buffer);
697 return self->allocated_buffer;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700698 default:
699 return PyLong_FromUnsignedLong((unsigned long) transferred);
700 }
701}
702
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200703static PyObject *
704do_ReadFile(OverlappedObject *self, HANDLE handle,
705 char *bufstart, DWORD buflen)
706{
707 DWORD nread;
708 int ret;
709 DWORD err;
710
711 Py_BEGIN_ALLOW_THREADS
712 ret = ReadFile(handle, bufstart, buflen, &nread,
713 &self->overlapped);
714 Py_END_ALLOW_THREADS
715
716 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
717 switch (err) {
718 case ERROR_BROKEN_PIPE:
719 mark_as_completed(&self->overlapped);
720 return SetFromWindowsErr(err);
721 case ERROR_SUCCESS:
722 case ERROR_MORE_DATA:
723 case ERROR_IO_PENDING:
724 Py_RETURN_NONE;
725 default:
726 self->type = TYPE_NOT_STARTED;
727 return SetFromWindowsErr(err);
728 }
729}
730
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700731PyDoc_STRVAR(
732 Overlapped_ReadFile_doc,
733 "ReadFile(handle, size) -> Overlapped[message]\n\n"
734 "Start overlapped read");
735
736static PyObject *
737Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
738{
739 HANDLE handle;
740 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700741 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700742
743 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
744 return NULL;
745
746 if (self->type != TYPE_NONE) {
747 PyErr_SetString(PyExc_ValueError, "operation already attempted");
748 return NULL;
749 }
750
751#if SIZEOF_SIZE_T <= SIZEOF_LONG
752 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
753#endif
754 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
755 if (buf == NULL)
756 return NULL;
757
758 self->type = TYPE_READ;
759 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200760 self->allocated_buffer = buf;
761
762 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
763}
764
765PyDoc_STRVAR(
766 Overlapped_ReadFileInto_doc,
767 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
768 "Start overlapped receive");
769
770static PyObject *
771Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
772{
773 HANDLE handle;
774 PyObject *bufobj;
775
776 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
777 return NULL;
778
779 if (self->type != TYPE_NONE) {
780 PyErr_SetString(PyExc_ValueError, "operation already attempted");
781 return NULL;
782 }
783
784 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
785 return NULL;
786
787#if SIZEOF_SIZE_T > SIZEOF_LONG
788 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
789 PyBuffer_Release(&self->user_buffer);
790 PyErr_SetString(PyExc_ValueError, "buffer too large");
791 return NULL;
792 }
793#endif
794
795 self->type = TYPE_READINTO;
796 self->handle = handle;
797
798 return do_ReadFile(self, handle, self->user_buffer.buf,
799 (DWORD)self->user_buffer.len);
800}
801
802static PyObject *
803do_WSARecv(OverlappedObject *self, HANDLE handle,
804 char *bufstart, DWORD buflen, DWORD flags)
805{
806 DWORD nread;
807 WSABUF wsabuf;
808 int ret;
809 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300810
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200811 wsabuf.buf = bufstart;
812 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700813
814 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200815 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
816 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700817 Py_END_ALLOW_THREADS
818
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200819 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700820 switch (err) {
821 case ERROR_BROKEN_PIPE:
822 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100823 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700824 case ERROR_SUCCESS:
825 case ERROR_MORE_DATA:
826 case ERROR_IO_PENDING:
827 Py_RETURN_NONE;
828 default:
829 self->type = TYPE_NOT_STARTED;
830 return SetFromWindowsErr(err);
831 }
832}
833
834PyDoc_STRVAR(
835 Overlapped_WSARecv_doc,
836 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
837 "Start overlapped receive");
838
839static PyObject *
840Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
841{
842 HANDLE handle;
843 DWORD size;
844 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700845 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700846
847 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
848 &handle, &size, &flags))
849 return NULL;
850
851 if (self->type != TYPE_NONE) {
852 PyErr_SetString(PyExc_ValueError, "operation already attempted");
853 return NULL;
854 }
855
856#if SIZEOF_SIZE_T <= SIZEOF_LONG
857 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
858#endif
859 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
860 if (buf == NULL)
861 return NULL;
862
863 self->type = TYPE_READ;
864 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200865 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700866
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200867 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
868}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700869
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200870PyDoc_STRVAR(
871 Overlapped_WSARecvInto_doc,
872 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
873 "Start overlapped receive");
874
875static PyObject *
876Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
877{
878 HANDLE handle;
879 PyObject *bufobj;
880 DWORD flags;
881
882 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
883 &handle, &bufobj, &flags))
884 return NULL;
885
886 if (self->type != TYPE_NONE) {
887 PyErr_SetString(PyExc_ValueError, "operation already attempted");
888 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700889 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200890
891 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
892 return NULL;
893
894#if SIZEOF_SIZE_T > SIZEOF_LONG
895 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
896 PyBuffer_Release(&self->user_buffer);
897 PyErr_SetString(PyExc_ValueError, "buffer too large");
898 return NULL;
899 }
900#endif
901
902 self->type = TYPE_READINTO;
903 self->handle = handle;
904
905 return do_WSARecv(self, handle, self->user_buffer.buf,
906 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700907}
908
909PyDoc_STRVAR(
910 Overlapped_WriteFile_doc,
911 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
912 "Start overlapped write");
913
914static PyObject *
915Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
916{
917 HANDLE handle;
918 PyObject *bufobj;
919 DWORD written;
920 BOOL ret;
921 DWORD err;
922
923 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
924 return NULL;
925
926 if (self->type != TYPE_NONE) {
927 PyErr_SetString(PyExc_ValueError, "operation already attempted");
928 return NULL;
929 }
930
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200931 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700932 return NULL;
933
934#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200935 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
936 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300937 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700938 return NULL;
939 }
940#endif
941
942 self->type = TYPE_WRITE;
943 self->handle = handle;
944
945 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200946 ret = WriteFile(handle, self->user_buffer.buf,
947 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700948 &written, &self->overlapped);
949 Py_END_ALLOW_THREADS
950
951 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
952 switch (err) {
953 case ERROR_SUCCESS:
954 case ERROR_IO_PENDING:
955 Py_RETURN_NONE;
956 default:
957 self->type = TYPE_NOT_STARTED;
958 return SetFromWindowsErr(err);
959 }
960}
961
962PyDoc_STRVAR(
963 Overlapped_WSASend_doc,
964 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
965 "Start overlapped send");
966
967static PyObject *
968Overlapped_WSASend(OverlappedObject *self, PyObject *args)
969{
970 HANDLE handle;
971 PyObject *bufobj;
972 DWORD flags;
973 DWORD written;
974 WSABUF wsabuf;
975 int ret;
976 DWORD err;
977
978 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
979 &handle, &bufobj, &flags))
980 return NULL;
981
982 if (self->type != TYPE_NONE) {
983 PyErr_SetString(PyExc_ValueError, "operation already attempted");
984 return NULL;
985 }
986
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200987 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700988 return NULL;
989
990#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200991 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
992 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300993 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700994 return NULL;
995 }
996#endif
997
998 self->type = TYPE_WRITE;
999 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001000 wsabuf.len = (DWORD)self->user_buffer.len;
1001 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001002
1003 Py_BEGIN_ALLOW_THREADS
1004 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1005 &self->overlapped, NULL);
1006 Py_END_ALLOW_THREADS
1007
1008 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1009 switch (err) {
1010 case ERROR_SUCCESS:
1011 case ERROR_IO_PENDING:
1012 Py_RETURN_NONE;
1013 default:
1014 self->type = TYPE_NOT_STARTED;
1015 return SetFromWindowsErr(err);
1016 }
1017}
1018
1019PyDoc_STRVAR(
1020 Overlapped_AcceptEx_doc,
1021 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1022 "Start overlapped wait for client to connect");
1023
1024static PyObject *
1025Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1026{
1027 SOCKET ListenSocket;
1028 SOCKET AcceptSocket;
1029 DWORD BytesReceived;
1030 DWORD size;
1031 PyObject *buf;
1032 BOOL ret;
1033 DWORD err;
1034
1035 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1036 &ListenSocket, &AcceptSocket))
1037 return NULL;
1038
1039 if (self->type != TYPE_NONE) {
1040 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1041 return NULL;
1042 }
1043
1044 size = sizeof(struct sockaddr_in6) + 16;
1045 buf = PyBytes_FromStringAndSize(NULL, size*2);
1046 if (!buf)
1047 return NULL;
1048
1049 self->type = TYPE_ACCEPT;
1050 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001051 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001052
1053 Py_BEGIN_ALLOW_THREADS
1054 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1055 0, size, size, &BytesReceived, &self->overlapped);
1056 Py_END_ALLOW_THREADS
1057
1058 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1059 switch (err) {
1060 case ERROR_SUCCESS:
1061 case ERROR_IO_PENDING:
1062 Py_RETURN_NONE;
1063 default:
1064 self->type = TYPE_NOT_STARTED;
1065 return SetFromWindowsErr(err);
1066 }
1067}
1068
1069
1070static int
1071parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1072{
Steve Dowercc16be82016-09-08 10:35:16 -07001073 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001074 unsigned short Port;
1075 unsigned long FlowInfo;
1076 unsigned long ScopeId;
1077
1078 memset(Address, 0, Length);
1079
Steve Dowercc16be82016-09-08 10:35:16 -07001080 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001081 {
1082 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001083 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001084 SetFromWindowsErr(WSAGetLastError());
1085 return -1;
1086 }
1087 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1088 return Length;
1089 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001090 else if (PyArg_ParseTuple(obj,
1091 "uHkk;ConnectEx(): illegal address_as_bytes "
1092 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001093 {
1094 PyErr_Clear();
1095 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001096 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001097 SetFromWindowsErr(WSAGetLastError());
1098 return -1;
1099 }
1100 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1101 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1102 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1103 return Length;
1104 }
1105
1106 return -1;
1107}
1108
1109
1110PyDoc_STRVAR(
1111 Overlapped_ConnectEx_doc,
1112 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1113 "Start overlapped connect. client_handle should be unbound.");
1114
1115static PyObject *
1116Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1117{
1118 SOCKET ConnectSocket;
1119 PyObject *AddressObj;
1120 char AddressBuf[sizeof(struct sockaddr_in6)];
1121 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1122 int Length;
1123 BOOL ret;
1124 DWORD err;
1125
Oren Milman1d1d3e92017-08-20 18:35:36 +03001126 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1127 &ConnectSocket, &PyTuple_Type, &AddressObj))
1128 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001129 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001130 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001131
1132 if (self->type != TYPE_NONE) {
1133 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1134 return NULL;
1135 }
1136
1137 Length = sizeof(AddressBuf);
1138 Length = parse_address(AddressObj, Address, Length);
1139 if (Length < 0)
1140 return NULL;
1141
1142 self->type = TYPE_CONNECT;
1143 self->handle = (HANDLE)ConnectSocket;
1144
1145 Py_BEGIN_ALLOW_THREADS
1146 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1147 NULL, 0, NULL, &self->overlapped);
1148 Py_END_ALLOW_THREADS
1149
1150 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1151 switch (err) {
1152 case ERROR_SUCCESS:
1153 case ERROR_IO_PENDING:
1154 Py_RETURN_NONE;
1155 default:
1156 self->type = TYPE_NOT_STARTED;
1157 return SetFromWindowsErr(err);
1158 }
1159}
1160
1161PyDoc_STRVAR(
1162 Overlapped_DisconnectEx_doc,
1163 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1164 "Start overlapped connect. client_handle should be unbound.");
1165
1166static PyObject *
1167Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1168{
1169 SOCKET Socket;
1170 DWORD flags;
1171 BOOL ret;
1172 DWORD err;
1173
1174 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1175 return NULL;
1176
1177 if (self->type != TYPE_NONE) {
1178 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1179 return NULL;
1180 }
1181
1182 self->type = TYPE_DISCONNECT;
1183 self->handle = (HANDLE)Socket;
1184
1185 Py_BEGIN_ALLOW_THREADS
1186 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1187 Py_END_ALLOW_THREADS
1188
1189 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1190 switch (err) {
1191 case ERROR_SUCCESS:
1192 case ERROR_IO_PENDING:
1193 Py_RETURN_NONE;
1194 default:
1195 self->type = TYPE_NOT_STARTED;
1196 return SetFromWindowsErr(err);
1197 }
1198}
1199
1200PyDoc_STRVAR(
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001201 Overlapped_TransmitFile_doc,
1202 "TransmitFile(socket, file, offset, offset_high, "
1203 "count_to_write, count_per_send, flags) "
1204 "-> Overlapped[None]\n\n"
1205 "Transmit file data over a connected socket.");
1206
1207static PyObject *
1208Overlapped_TransmitFile(OverlappedObject *self, PyObject *args)
1209{
1210 SOCKET Socket;
1211 HANDLE File;
1212 DWORD offset;
1213 DWORD offset_high;
1214 DWORD count_to_write;
1215 DWORD count_per_send;
1216 DWORD flags;
1217 BOOL ret;
1218 DWORD err;
1219
1220 if (!PyArg_ParseTuple(args,
1221 F_HANDLE F_HANDLE F_DWORD F_DWORD
1222 F_DWORD F_DWORD F_DWORD,
1223 &Socket, &File, &offset, &offset_high,
1224 &count_to_write, &count_per_send,
1225 &flags))
1226 return NULL;
1227
1228 if (self->type != TYPE_NONE) {
1229 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1230 return NULL;
1231 }
1232
1233 self->type = TYPE_TRANSMIT_FILE;
1234 self->handle = (HANDLE)Socket;
1235 self->overlapped.Offset = offset;
1236 self->overlapped.OffsetHigh = offset_high;
1237
1238 Py_BEGIN_ALLOW_THREADS
1239 ret = Py_TransmitFile(Socket, File, count_to_write, count_per_send,
1240 &self->overlapped,
1241 NULL, flags);
1242 Py_END_ALLOW_THREADS
1243
1244 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1245 switch (err) {
1246 case ERROR_SUCCESS:
1247 case ERROR_IO_PENDING:
1248 Py_RETURN_NONE;
1249 default:
1250 self->type = TYPE_NOT_STARTED;
1251 return SetFromWindowsErr(err);
1252 }
1253}
1254
1255PyDoc_STRVAR(
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001256 Overlapped_ConnectNamedPipe_doc,
1257 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1258 "Start overlapped wait for a client to connect.");
1259
1260static PyObject *
1261Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1262{
1263 HANDLE Pipe;
1264 BOOL ret;
1265 DWORD err;
1266
1267 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1268 return NULL;
1269
1270 if (self->type != TYPE_NONE) {
1271 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1272 return NULL;
1273 }
1274
1275 self->type = TYPE_CONNECT_NAMED_PIPE;
1276 self->handle = Pipe;
1277
1278 Py_BEGIN_ALLOW_THREADS
1279 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1280 Py_END_ALLOW_THREADS
1281
1282 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1283 switch (err) {
1284 case ERROR_PIPE_CONNECTED:
1285 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001286 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001287 case ERROR_SUCCESS:
1288 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001289 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001290 default:
1291 self->type = TYPE_NOT_STARTED;
1292 return SetFromWindowsErr(err);
1293 }
1294}
1295
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001296PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001297 ConnectPipe_doc,
1298 "ConnectPipe(addr) -> pipe_handle\n\n"
1299 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001300
1301static PyObject *
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001302ConnectPipe(OverlappedObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001303{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001304 PyObject *AddressObj;
1305 wchar_t *Address;
1306 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001307
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001308 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001309 return NULL;
1310
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001311 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1312 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001313 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001314
Victor Stinner498b1f62015-01-26 22:43:39 +01001315 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001316 PipeHandle = CreateFileW(Address,
1317 GENERIC_READ | GENERIC_WRITE,
1318 0, NULL, OPEN_EXISTING,
1319 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001320 Py_END_ALLOW_THREADS
1321
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001322 PyMem_Free(Address);
1323 if (PipeHandle == INVALID_HANDLE_VALUE)
1324 return SetFromWindowsErr(0);
1325 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001326}
1327
1328static PyObject*
1329Overlapped_getaddress(OverlappedObject *self)
1330{
1331 return PyLong_FromVoidPtr(&self->overlapped);
1332}
1333
1334static PyObject*
1335Overlapped_getpending(OverlappedObject *self)
1336{
1337 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1338 self->type != TYPE_NOT_STARTED);
1339}
1340
1341static PyMethodDef Overlapped_methods[] = {
1342 {"getresult", (PyCFunction) Overlapped_getresult,
1343 METH_VARARGS, Overlapped_getresult_doc},
1344 {"cancel", (PyCFunction) Overlapped_cancel,
1345 METH_NOARGS, Overlapped_cancel_doc},
1346 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1347 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001348 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1349 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001350 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1351 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001352 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1353 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001354 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1355 METH_VARARGS, Overlapped_WriteFile_doc},
1356 {"WSASend", (PyCFunction) Overlapped_WSASend,
1357 METH_VARARGS, Overlapped_WSASend_doc},
1358 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1359 METH_VARARGS, Overlapped_AcceptEx_doc},
1360 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1361 METH_VARARGS, Overlapped_ConnectEx_doc},
1362 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1363 METH_VARARGS, Overlapped_DisconnectEx_doc},
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001364 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1365 METH_VARARGS, Overlapped_TransmitFile_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001366 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1367 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001368 {NULL}
1369};
1370
1371static PyMemberDef Overlapped_members[] = {
1372 {"error", T_ULONG,
1373 offsetof(OverlappedObject, error),
1374 READONLY, "Error from last operation"},
1375 {"event", T_HANDLE,
1376 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1377 READONLY, "Overlapped event handle"},
1378 {NULL}
1379};
1380
1381static PyGetSetDef Overlapped_getsets[] = {
1382 {"address", (getter)Overlapped_getaddress, NULL,
1383 "Address of overlapped structure"},
1384 {"pending", (getter)Overlapped_getpending, NULL,
1385 "Whether the operation is pending"},
1386 {NULL},
1387};
1388
1389PyTypeObject OverlappedType = {
1390 PyVarObject_HEAD_INIT(NULL, 0)
1391 /* tp_name */ "_overlapped.Overlapped",
1392 /* tp_basicsize */ sizeof(OverlappedObject),
1393 /* tp_itemsize */ 0,
1394 /* tp_dealloc */ (destructor) Overlapped_dealloc,
1395 /* tp_print */ 0,
1396 /* tp_getattr */ 0,
1397 /* tp_setattr */ 0,
1398 /* tp_reserved */ 0,
1399 /* tp_repr */ 0,
1400 /* tp_as_number */ 0,
1401 /* tp_as_sequence */ 0,
1402 /* tp_as_mapping */ 0,
1403 /* tp_hash */ 0,
1404 /* tp_call */ 0,
1405 /* tp_str */ 0,
1406 /* tp_getattro */ 0,
1407 /* tp_setattro */ 0,
1408 /* tp_as_buffer */ 0,
1409 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1410 /* tp_doc */ "OVERLAPPED structure wrapper",
1411 /* tp_traverse */ 0,
1412 /* tp_clear */ 0,
1413 /* tp_richcompare */ 0,
1414 /* tp_weaklistoffset */ 0,
1415 /* tp_iter */ 0,
1416 /* tp_iternext */ 0,
1417 /* tp_methods */ Overlapped_methods,
1418 /* tp_members */ Overlapped_members,
1419 /* tp_getset */ Overlapped_getsets,
1420 /* tp_base */ 0,
1421 /* tp_dict */ 0,
1422 /* tp_descr_get */ 0,
1423 /* tp_descr_set */ 0,
1424 /* tp_dictoffset */ 0,
1425 /* tp_init */ 0,
1426 /* tp_alloc */ 0,
1427 /* tp_new */ Overlapped_new,
1428};
1429
1430static PyMethodDef overlapped_functions[] = {
1431 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1432 METH_VARARGS, CreateIoCompletionPort_doc},
1433 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1434 METH_VARARGS, GetQueuedCompletionStatus_doc},
1435 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1436 METH_VARARGS, PostQueuedCompletionStatus_doc},
1437 {"FormatMessage", overlapped_FormatMessage,
1438 METH_VARARGS, FormatMessage_doc},
1439 {"BindLocal", overlapped_BindLocal,
1440 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001441 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1442 METH_VARARGS, RegisterWaitWithQueue_doc},
1443 {"UnregisterWait", overlapped_UnregisterWait,
1444 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001445 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1446 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001447 {"CreateEvent", overlapped_CreateEvent,
1448 METH_VARARGS, CreateEvent_doc},
1449 {"SetEvent", overlapped_SetEvent,
1450 METH_VARARGS, SetEvent_doc},
1451 {"ResetEvent", overlapped_ResetEvent,
1452 METH_VARARGS, ResetEvent_doc},
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001453 {"ConnectPipe",
1454 (PyCFunction) ConnectPipe,
1455 METH_VARARGS, ConnectPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001456 {NULL}
1457};
1458
1459static struct PyModuleDef overlapped_module = {
1460 PyModuleDef_HEAD_INIT,
1461 "_overlapped",
1462 NULL,
1463 -1,
1464 overlapped_functions,
1465 NULL,
1466 NULL,
1467 NULL,
1468 NULL
1469};
1470
1471#define WINAPI_CONSTANT(fmt, con) \
1472 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1473
1474PyMODINIT_FUNC
1475PyInit__overlapped(void)
1476{
1477 PyObject *m, *d;
1478
1479 /* Ensure WSAStartup() called before initializing function pointers */
1480 m = PyImport_ImportModule("_socket");
1481 if (!m)
1482 return NULL;
1483 Py_DECREF(m);
1484
1485 if (initialize_function_pointers() < 0)
1486 return NULL;
1487
1488 if (PyType_Ready(&OverlappedType) < 0)
1489 return NULL;
1490
1491 m = PyModule_Create(&overlapped_module);
1492 if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
1493 return NULL;
1494
1495 d = PyModule_GetDict(m);
1496
1497 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1498 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001499 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001500 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001501 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001502 WINAPI_CONSTANT(F_DWORD, INFINITE);
1503 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1504 WINAPI_CONSTANT(F_HANDLE, NULL);
1505 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1506 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1507 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1508
1509 return m;
1510}