blob: e66e856684054c839ac2460343a3697fc1cd2715 [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,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070042 TYPE_WAIT_NAMED_PIPE_AND_CONNECT};
43
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;
92static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
93
94#define GET_WSA_POINTER(s, x) \
95 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
96 &Guid##x, sizeof(Guid##x), &Py_##x, \
97 sizeof(Py_##x), &dwBytes, NULL, NULL))
98
99static int
100initialize_function_pointers(void)
101{
102 GUID GuidAcceptEx = WSAID_ACCEPTEX;
103 GUID GuidConnectEx = WSAID_CONNECTEX;
104 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
105 HINSTANCE hKernel32;
106 SOCKET s;
107 DWORD dwBytes;
108
109 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
110 if (s == INVALID_SOCKET) {
111 SetFromWindowsErr(WSAGetLastError());
112 return -1;
113 }
114
115 if (!GET_WSA_POINTER(s, AcceptEx) ||
116 !GET_WSA_POINTER(s, ConnectEx) ||
117 !GET_WSA_POINTER(s, DisconnectEx))
118 {
119 closesocket(s);
120 SetFromWindowsErr(WSAGetLastError());
121 return -1;
122 }
123
124 closesocket(s);
125
126 /* On WinXP we will have Py_CancelIoEx == NULL */
127 hKernel32 = GetModuleHandle("KERNEL32");
128 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
129 return 0;
130}
131
132/*
133 * Completion port stuff
134 */
135
136PyDoc_STRVAR(
137 CreateIoCompletionPort_doc,
138 "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
139 "Create a completion port or register a handle with a port.");
140
141static PyObject *
142overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
143{
144 HANDLE FileHandle;
145 HANDLE ExistingCompletionPort;
146 ULONG_PTR CompletionKey;
147 DWORD NumberOfConcurrentThreads;
148 HANDLE ret;
149
150 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
151 &FileHandle, &ExistingCompletionPort, &CompletionKey,
152 &NumberOfConcurrentThreads))
153 return NULL;
154
155 Py_BEGIN_ALLOW_THREADS
156 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
157 CompletionKey, NumberOfConcurrentThreads);
158 Py_END_ALLOW_THREADS
159
160 if (ret == NULL)
161 return SetFromWindowsErr(0);
162 return Py_BuildValue(F_HANDLE, ret);
163}
164
165PyDoc_STRVAR(
166 GetQueuedCompletionStatus_doc,
167 "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
168 "Get a message from completion port. Wait for up to msecs milliseconds.");
169
170static PyObject *
171overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
172{
173 HANDLE CompletionPort = NULL;
174 DWORD NumberOfBytes = 0;
175 ULONG_PTR CompletionKey = 0;
176 OVERLAPPED *Overlapped = NULL;
177 DWORD Milliseconds;
178 DWORD err;
179 BOOL ret;
180
181 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
182 &CompletionPort, &Milliseconds))
183 return NULL;
184
185 Py_BEGIN_ALLOW_THREADS
186 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
187 &CompletionKey, &Overlapped, Milliseconds);
188 Py_END_ALLOW_THREADS
189
190 err = ret ? ERROR_SUCCESS : GetLastError();
191 if (Overlapped == NULL) {
192 if (err == WAIT_TIMEOUT)
193 Py_RETURN_NONE;
194 else
195 return SetFromWindowsErr(err);
196 }
197 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
198 err, NumberOfBytes, CompletionKey, Overlapped);
199}
200
201PyDoc_STRVAR(
202 PostQueuedCompletionStatus_doc,
203 "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
204 "Post a message to completion port.");
205
206static PyObject *
207overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
208{
209 HANDLE CompletionPort;
210 DWORD NumberOfBytes;
211 ULONG_PTR CompletionKey;
212 OVERLAPPED *Overlapped;
213 BOOL ret;
214
215 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
216 &CompletionPort, &NumberOfBytes, &CompletionKey,
217 &Overlapped))
218 return NULL;
219
220 Py_BEGIN_ALLOW_THREADS
221 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
222 CompletionKey, Overlapped);
223 Py_END_ALLOW_THREADS
224
225 if (!ret)
226 return SetFromWindowsErr(0);
227 Py_RETURN_NONE;
228}
229
230/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700231 * Wait for a handle
232 */
233
234struct PostCallbackData {
235 HANDLE CompletionPort;
236 LPOVERLAPPED Overlapped;
237};
238
239static VOID CALLBACK
240PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
241{
242 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
243
244 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
245 0, p->Overlapped);
246 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100247 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700248}
249
250PyDoc_STRVAR(
251 RegisterWaitWithQueue_doc,
252 "RegisterWaitWithQueue(Object, CompletionPort, Overlapped, Timeout)\n"
253 " -> WaitHandle\n\n"
254 "Register wait for Object; when complete CompletionPort is notified.\n");
255
256static PyObject *
257overlapped_RegisterWaitWithQueue(PyObject *self, PyObject *args)
258{
259 HANDLE NewWaitObject;
260 HANDLE Object;
261 ULONG Milliseconds;
262 struct PostCallbackData data, *pdata;
263
264 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_POINTER F_DWORD,
265 &Object,
266 &data.CompletionPort,
267 &data.Overlapped,
268 &Milliseconds))
269 return NULL;
270
Victor Stinner6150f312016-03-16 23:25:02 +0100271 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
272 PostToQueueCallback() will call PyMem_Free() from a new C thread
273 which doesn't hold the GIL. */
274 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700275 if (pdata == NULL)
276 return SetFromWindowsErr(0);
277
278 *pdata = data;
279
280 if (!RegisterWaitForSingleObject(
281 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
282 pdata, Milliseconds,
283 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
284 {
Victor Stinner6150f312016-03-16 23:25:02 +0100285 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700286 return SetFromWindowsErr(0);
287 }
288
289 return Py_BuildValue(F_HANDLE, NewWaitObject);
290}
291
292PyDoc_STRVAR(
293 UnregisterWait_doc,
294 "UnregisterWait(WaitHandle) -> None\n\n"
295 "Unregister wait handle.\n");
296
297static PyObject *
298overlapped_UnregisterWait(PyObject *self, PyObject *args)
299{
300 HANDLE WaitHandle;
301 BOOL ret;
302
303 if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
304 return NULL;
305
306 Py_BEGIN_ALLOW_THREADS
307 ret = UnregisterWait(WaitHandle);
308 Py_END_ALLOW_THREADS
309
310 if (!ret)
311 return SetFromWindowsErr(0);
312 Py_RETURN_NONE;
313}
314
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100315PyDoc_STRVAR(
316 UnregisterWaitEx_doc,
317 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
318 "Unregister wait handle.\n");
319
320static PyObject *
321overlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
322{
323 HANDLE WaitHandle, Event;
324 BOOL ret;
325
326 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
327 return NULL;
328
329 Py_BEGIN_ALLOW_THREADS
330 ret = UnregisterWaitEx(WaitHandle, Event);
331 Py_END_ALLOW_THREADS
332
333 if (!ret)
334 return SetFromWindowsErr(0);
335 Py_RETURN_NONE;
336}
337
Guido van Rossum90fb9142013-10-30 14:44:05 -0700338/*
339 * Event functions -- currently only used by tests
340 */
341
342PyDoc_STRVAR(
343 CreateEvent_doc,
344 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
345 " -> Handle\n\n"
346 "Create an event. EventAttributes must be None.\n");
347
348static PyObject *
349overlapped_CreateEvent(PyObject *self, PyObject *args)
350{
351 PyObject *EventAttributes;
352 BOOL ManualReset;
353 BOOL InitialState;
354 Py_UNICODE *Name;
355 HANDLE Event;
356
357 if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
358 &EventAttributes, &ManualReset,
359 &InitialState, &Name))
360 return NULL;
361
362 if (EventAttributes != Py_None) {
363 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
364 return NULL;
365 }
366
367 Py_BEGIN_ALLOW_THREADS
368 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
369 Py_END_ALLOW_THREADS
370
371 if (Event == NULL)
372 return SetFromWindowsErr(0);
373 return Py_BuildValue(F_HANDLE, Event);
374}
375
376PyDoc_STRVAR(
377 SetEvent_doc,
378 "SetEvent(Handle) -> None\n\n"
379 "Set event.\n");
380
381static PyObject *
382overlapped_SetEvent(PyObject *self, PyObject *args)
383{
384 HANDLE Handle;
385 BOOL ret;
386
387 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
388 return NULL;
389
390 Py_BEGIN_ALLOW_THREADS
391 ret = SetEvent(Handle);
392 Py_END_ALLOW_THREADS
393
394 if (!ret)
395 return SetFromWindowsErr(0);
396 Py_RETURN_NONE;
397}
398
399PyDoc_STRVAR(
400 ResetEvent_doc,
401 "ResetEvent(Handle) -> None\n\n"
402 "Reset event.\n");
403
404static PyObject *
405overlapped_ResetEvent(PyObject *self, PyObject *args)
406{
407 HANDLE Handle;
408 BOOL ret;
409
410 if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
411 return NULL;
412
413 Py_BEGIN_ALLOW_THREADS
414 ret = ResetEvent(Handle);
415 Py_END_ALLOW_THREADS
416
417 if (!ret)
418 return SetFromWindowsErr(0);
419 Py_RETURN_NONE;
420}
421
422/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700423 * Bind socket handle to local port without doing slow getaddrinfo()
424 */
425
426PyDoc_STRVAR(
427 BindLocal_doc,
428 "BindLocal(handle, family) -> None\n\n"
429 "Bind a socket handle to an arbitrary local port.\n"
430 "family should AF_INET or AF_INET6.\n");
431
432static PyObject *
433overlapped_BindLocal(PyObject *self, PyObject *args)
434{
435 SOCKET Socket;
436 int Family;
437 BOOL ret;
438
439 if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
440 return NULL;
441
442 if (Family == AF_INET) {
443 struct sockaddr_in addr;
444 memset(&addr, 0, sizeof(addr));
445 addr.sin_family = AF_INET;
446 addr.sin_port = 0;
447 addr.sin_addr.S_un.S_addr = INADDR_ANY;
448 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
449 } else if (Family == AF_INET6) {
450 struct sockaddr_in6 addr;
451 memset(&addr, 0, sizeof(addr));
452 addr.sin6_family = AF_INET6;
453 addr.sin6_port = 0;
454 addr.sin6_addr = in6addr_any;
455 ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
456 } else {
457 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
458 return NULL;
459 }
460
461 if (!ret)
462 return SetFromWindowsErr(WSAGetLastError());
463 Py_RETURN_NONE;
464}
465
466/*
467 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
468 */
469
470PyDoc_STRVAR(
471 FormatMessage_doc,
472 "FormatMessage(error_code) -> error_message\n\n"
473 "Return error message for an error code.");
474
475static PyObject *
476overlapped_FormatMessage(PyObject *ignore, PyObject *args)
477{
478 DWORD code, n;
479 WCHAR *lpMsgBuf;
480 PyObject *res;
481
482 if (!PyArg_ParseTuple(args, F_DWORD, &code))
483 return NULL;
484
485 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
486 FORMAT_MESSAGE_FROM_SYSTEM,
487 NULL,
488 code,
489 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
490 (LPWSTR) &lpMsgBuf,
491 0,
492 NULL);
493 if (n) {
494 while (iswspace(lpMsgBuf[n-1]))
495 --n;
496 lpMsgBuf[n] = L'\0';
497 res = Py_BuildValue("u", lpMsgBuf);
498 } else {
499 res = PyUnicode_FromFormat("unknown error code %u", code);
500 }
501 LocalFree(lpMsgBuf);
502 return res;
503}
504
505
506/*
507 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
508 */
509
510static void
511mark_as_completed(OVERLAPPED *ov)
512{
513 ov->Internal = 0;
514 if (ov->hEvent != NULL)
515 SetEvent(ov->hEvent);
516}
517
518/*
519 * A Python object wrapping an OVERLAPPED structure and other useful data
520 * for overlapped I/O
521 */
522
523PyDoc_STRVAR(
524 Overlapped_doc,
525 "Overlapped object");
526
527static PyObject *
528Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
529{
530 OverlappedObject *self;
531 HANDLE event = INVALID_HANDLE_VALUE;
532 static char *kwlist[] = {"event", NULL};
533
534 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
535 return NULL;
536
537 if (event == INVALID_HANDLE_VALUE) {
538 event = CreateEvent(NULL, TRUE, FALSE, NULL);
539 if (event == NULL)
540 return SetFromWindowsErr(0);
541 }
542
543 self = PyObject_New(OverlappedObject, type);
544 if (self == NULL) {
545 if (event != NULL)
546 CloseHandle(event);
547 return NULL;
548 }
549
550 self->handle = NULL;
551 self->error = 0;
552 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200553 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700554 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200555 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700556 if (event)
557 self->overlapped.hEvent = event;
558 return (PyObject *)self;
559}
560
561static void
562Overlapped_dealloc(OverlappedObject *self)
563{
564 DWORD bytes;
565 DWORD olderr = GetLastError();
566 BOOL wait = FALSE;
567 BOOL ret;
568
569 if (!HasOverlappedIoCompleted(&self->overlapped) &&
570 self->type != TYPE_NOT_STARTED)
571 {
572 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
573 wait = TRUE;
574
575 Py_BEGIN_ALLOW_THREADS
576 ret = GetOverlappedResult(self->handle, &self->overlapped,
577 &bytes, wait);
578 Py_END_ALLOW_THREADS
579
580 switch (ret ? ERROR_SUCCESS : GetLastError()) {
581 case ERROR_SUCCESS:
582 case ERROR_NOT_FOUND:
583 case ERROR_OPERATION_ABORTED:
584 break;
585 default:
586 PyErr_Format(
587 PyExc_RuntimeError,
588 "%R still has pending operation at "
589 "deallocation, the process may crash", self);
590 PyErr_WriteUnraisable(NULL);
591 }
592 }
593
594 if (self->overlapped.hEvent != NULL)
595 CloseHandle(self->overlapped.hEvent);
596
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700597 switch (self->type) {
Victor Stinner91445fb2014-01-30 19:06:44 +0100598 case TYPE_READ:
599 case TYPE_ACCEPT:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200600 Py_CLEAR(self->allocated_buffer);
Victor Stinner91445fb2014-01-30 19:06:44 +0100601 break;
602 case TYPE_WRITE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200603 case TYPE_READINTO:
604 if (self->user_buffer.obj)
605 PyBuffer_Release(&self->user_buffer);
Victor Stinner91445fb2014-01-30 19:06:44 +0100606 break;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700607 }
608 PyObject_Del(self);
609 SetLastError(olderr);
610}
611
612PyDoc_STRVAR(
613 Overlapped_cancel_doc,
614 "cancel() -> None\n\n"
615 "Cancel overlapped operation");
616
617static PyObject *
618Overlapped_cancel(OverlappedObject *self)
619{
620 BOOL ret = TRUE;
621
622 if (self->type == TYPE_NOT_STARTED
623 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
624 Py_RETURN_NONE;
625
626 if (!HasOverlappedIoCompleted(&self->overlapped)) {
627 Py_BEGIN_ALLOW_THREADS
628 if (Py_CancelIoEx)
629 ret = Py_CancelIoEx(self->handle, &self->overlapped);
630 else
631 ret = CancelIo(self->handle);
632 Py_END_ALLOW_THREADS
633 }
634
635 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
636 if (!ret && GetLastError() != ERROR_NOT_FOUND)
637 return SetFromWindowsErr(0);
638 Py_RETURN_NONE;
639}
640
641PyDoc_STRVAR(
642 Overlapped_getresult_doc,
643 "getresult(wait=False) -> result\n\n"
644 "Retrieve result of operation. If wait is true then it blocks\n"
645 "until the operation is finished. If wait is false and the\n"
646 "operation is still pending then an error is raised.");
647
648static PyObject *
649Overlapped_getresult(OverlappedObject *self, PyObject *args)
650{
651 BOOL wait = FALSE;
652 DWORD transferred = 0;
653 BOOL ret;
654 DWORD err;
655
656 if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
657 return NULL;
658
659 if (self->type == TYPE_NONE) {
660 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
661 return NULL;
662 }
663
664 if (self->type == TYPE_NOT_STARTED) {
665 PyErr_SetString(PyExc_ValueError, "operation failed to start");
666 return NULL;
667 }
668
669 Py_BEGIN_ALLOW_THREADS
670 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
671 wait);
672 Py_END_ALLOW_THREADS
673
674 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
675 switch (err) {
676 case ERROR_SUCCESS:
677 case ERROR_MORE_DATA:
678 break;
679 case ERROR_BROKEN_PIPE:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200680 if (self->type == TYPE_READ || self->type == TYPE_READINTO)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700681 break;
682 /* fall through */
683 default:
684 return SetFromWindowsErr(err);
685 }
686
687 switch (self->type) {
688 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200689 assert(PyBytes_CheckExact(self->allocated_buffer));
690 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
691 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700692 return NULL;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200693 Py_INCREF(self->allocated_buffer);
694 return self->allocated_buffer;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700695 default:
696 return PyLong_FromUnsignedLong((unsigned long) transferred);
697 }
698}
699
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200700static PyObject *
701do_ReadFile(OverlappedObject *self, HANDLE handle,
702 char *bufstart, DWORD buflen)
703{
704 DWORD nread;
705 int ret;
706 DWORD err;
707
708 Py_BEGIN_ALLOW_THREADS
709 ret = ReadFile(handle, bufstart, buflen, &nread,
710 &self->overlapped);
711 Py_END_ALLOW_THREADS
712
713 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
714 switch (err) {
715 case ERROR_BROKEN_PIPE:
716 mark_as_completed(&self->overlapped);
717 return SetFromWindowsErr(err);
718 case ERROR_SUCCESS:
719 case ERROR_MORE_DATA:
720 case ERROR_IO_PENDING:
721 Py_RETURN_NONE;
722 default:
723 self->type = TYPE_NOT_STARTED;
724 return SetFromWindowsErr(err);
725 }
726}
727
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700728PyDoc_STRVAR(
729 Overlapped_ReadFile_doc,
730 "ReadFile(handle, size) -> Overlapped[message]\n\n"
731 "Start overlapped read");
732
733static PyObject *
734Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
735{
736 HANDLE handle;
737 DWORD size;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700738 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700739
740 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
741 return NULL;
742
743 if (self->type != TYPE_NONE) {
744 PyErr_SetString(PyExc_ValueError, "operation already attempted");
745 return NULL;
746 }
747
748#if SIZEOF_SIZE_T <= SIZEOF_LONG
749 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
750#endif
751 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
752 if (buf == NULL)
753 return NULL;
754
755 self->type = TYPE_READ;
756 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200757 self->allocated_buffer = buf;
758
759 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
760}
761
762PyDoc_STRVAR(
763 Overlapped_ReadFileInto_doc,
764 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
765 "Start overlapped receive");
766
767static PyObject *
768Overlapped_ReadFileInto(OverlappedObject *self, PyObject *args)
769{
770 HANDLE handle;
771 PyObject *bufobj;
772
773 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
774 return NULL;
775
776 if (self->type != TYPE_NONE) {
777 PyErr_SetString(PyExc_ValueError, "operation already attempted");
778 return NULL;
779 }
780
781 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
782 return NULL;
783
784#if SIZEOF_SIZE_T > SIZEOF_LONG
785 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
786 PyBuffer_Release(&self->user_buffer);
787 PyErr_SetString(PyExc_ValueError, "buffer too large");
788 return NULL;
789 }
790#endif
791
792 self->type = TYPE_READINTO;
793 self->handle = handle;
794
795 return do_ReadFile(self, handle, self->user_buffer.buf,
796 (DWORD)self->user_buffer.len);
797}
798
799static PyObject *
800do_WSARecv(OverlappedObject *self, HANDLE handle,
801 char *bufstart, DWORD buflen, DWORD flags)
802{
803 DWORD nread;
804 WSABUF wsabuf;
805 int ret;
806 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +0300807
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200808 wsabuf.buf = bufstart;
809 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700810
811 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200812 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
813 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700814 Py_END_ALLOW_THREADS
815
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200816 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700817 switch (err) {
818 case ERROR_BROKEN_PIPE:
819 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +0100820 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700821 case ERROR_SUCCESS:
822 case ERROR_MORE_DATA:
823 case ERROR_IO_PENDING:
824 Py_RETURN_NONE;
825 default:
826 self->type = TYPE_NOT_STARTED;
827 return SetFromWindowsErr(err);
828 }
829}
830
831PyDoc_STRVAR(
832 Overlapped_WSARecv_doc,
833 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
834 "Start overlapped receive");
835
836static PyObject *
837Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
838{
839 HANDLE handle;
840 DWORD size;
841 DWORD flags = 0;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700842 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700843
844 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
845 &handle, &size, &flags))
846 return NULL;
847
848 if (self->type != TYPE_NONE) {
849 PyErr_SetString(PyExc_ValueError, "operation already attempted");
850 return NULL;
851 }
852
853#if SIZEOF_SIZE_T <= SIZEOF_LONG
854 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
855#endif
856 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
857 if (buf == NULL)
858 return NULL;
859
860 self->type = TYPE_READ;
861 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200862 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700863
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200864 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
865}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700866
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200867PyDoc_STRVAR(
868 Overlapped_WSARecvInto_doc,
869 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
870 "Start overlapped receive");
871
872static PyObject *
873Overlapped_WSARecvInto(OverlappedObject *self, PyObject *args)
874{
875 HANDLE handle;
876 PyObject *bufobj;
877 DWORD flags;
878
879 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
880 &handle, &bufobj, &flags))
881 return NULL;
882
883 if (self->type != TYPE_NONE) {
884 PyErr_SetString(PyExc_ValueError, "operation already attempted");
885 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700886 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200887
888 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
889 return NULL;
890
891#if SIZEOF_SIZE_T > SIZEOF_LONG
892 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
893 PyBuffer_Release(&self->user_buffer);
894 PyErr_SetString(PyExc_ValueError, "buffer too large");
895 return NULL;
896 }
897#endif
898
899 self->type = TYPE_READINTO;
900 self->handle = handle;
901
902 return do_WSARecv(self, handle, self->user_buffer.buf,
903 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700904}
905
906PyDoc_STRVAR(
907 Overlapped_WriteFile_doc,
908 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
909 "Start overlapped write");
910
911static PyObject *
912Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
913{
914 HANDLE handle;
915 PyObject *bufobj;
916 DWORD written;
917 BOOL ret;
918 DWORD err;
919
920 if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
921 return NULL;
922
923 if (self->type != TYPE_NONE) {
924 PyErr_SetString(PyExc_ValueError, "operation already attempted");
925 return NULL;
926 }
927
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200928 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700929 return NULL;
930
931#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200932 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
933 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300934 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700935 return NULL;
936 }
937#endif
938
939 self->type = TYPE_WRITE;
940 self->handle = handle;
941
942 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200943 ret = WriteFile(handle, self->user_buffer.buf,
944 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700945 &written, &self->overlapped);
946 Py_END_ALLOW_THREADS
947
948 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
949 switch (err) {
950 case ERROR_SUCCESS:
951 case ERROR_IO_PENDING:
952 Py_RETURN_NONE;
953 default:
954 self->type = TYPE_NOT_STARTED;
955 return SetFromWindowsErr(err);
956 }
957}
958
959PyDoc_STRVAR(
960 Overlapped_WSASend_doc,
961 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
962 "Start overlapped send");
963
964static PyObject *
965Overlapped_WSASend(OverlappedObject *self, PyObject *args)
966{
967 HANDLE handle;
968 PyObject *bufobj;
969 DWORD flags;
970 DWORD written;
971 WSABUF wsabuf;
972 int ret;
973 DWORD err;
974
975 if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
976 &handle, &bufobj, &flags))
977 return NULL;
978
979 if (self->type != TYPE_NONE) {
980 PyErr_SetString(PyExc_ValueError, "operation already attempted");
981 return NULL;
982 }
983
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200984 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700985 return NULL;
986
987#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200988 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
989 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +0300990 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700991 return NULL;
992 }
993#endif
994
995 self->type = TYPE_WRITE;
996 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200997 wsabuf.len = (DWORD)self->user_buffer.len;
998 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700999
1000 Py_BEGIN_ALLOW_THREADS
1001 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1002 &self->overlapped, NULL);
1003 Py_END_ALLOW_THREADS
1004
1005 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1006 switch (err) {
1007 case ERROR_SUCCESS:
1008 case ERROR_IO_PENDING:
1009 Py_RETURN_NONE;
1010 default:
1011 self->type = TYPE_NOT_STARTED;
1012 return SetFromWindowsErr(err);
1013 }
1014}
1015
1016PyDoc_STRVAR(
1017 Overlapped_AcceptEx_doc,
1018 "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
1019 "Start overlapped wait for client to connect");
1020
1021static PyObject *
1022Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
1023{
1024 SOCKET ListenSocket;
1025 SOCKET AcceptSocket;
1026 DWORD BytesReceived;
1027 DWORD size;
1028 PyObject *buf;
1029 BOOL ret;
1030 DWORD err;
1031
1032 if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
1033 &ListenSocket, &AcceptSocket))
1034 return NULL;
1035
1036 if (self->type != TYPE_NONE) {
1037 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1038 return NULL;
1039 }
1040
1041 size = sizeof(struct sockaddr_in6) + 16;
1042 buf = PyBytes_FromStringAndSize(NULL, size*2);
1043 if (!buf)
1044 return NULL;
1045
1046 self->type = TYPE_ACCEPT;
1047 self->handle = (HANDLE)ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001048 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001049
1050 Py_BEGIN_ALLOW_THREADS
1051 ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
1052 0, size, size, &BytesReceived, &self->overlapped);
1053 Py_END_ALLOW_THREADS
1054
1055 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1056 switch (err) {
1057 case ERROR_SUCCESS:
1058 case ERROR_IO_PENDING:
1059 Py_RETURN_NONE;
1060 default:
1061 self->type = TYPE_NOT_STARTED;
1062 return SetFromWindowsErr(err);
1063 }
1064}
1065
1066
1067static int
1068parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1069{
Steve Dowercc16be82016-09-08 10:35:16 -07001070 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001071 unsigned short Port;
1072 unsigned long FlowInfo;
1073 unsigned long ScopeId;
1074
1075 memset(Address, 0, Length);
1076
Steve Dowercc16be82016-09-08 10:35:16 -07001077 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001078 {
1079 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001080 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001081 SetFromWindowsErr(WSAGetLastError());
1082 return -1;
1083 }
1084 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1085 return Length;
1086 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001087 else if (PyArg_ParseTuple(obj,
1088 "uHkk;ConnectEx(): illegal address_as_bytes "
1089 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001090 {
1091 PyErr_Clear();
1092 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001093 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001094 SetFromWindowsErr(WSAGetLastError());
1095 return -1;
1096 }
1097 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1098 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1099 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1100 return Length;
1101 }
1102
1103 return -1;
1104}
1105
1106
1107PyDoc_STRVAR(
1108 Overlapped_ConnectEx_doc,
1109 "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1110 "Start overlapped connect. client_handle should be unbound.");
1111
1112static PyObject *
1113Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1114{
1115 SOCKET ConnectSocket;
1116 PyObject *AddressObj;
1117 char AddressBuf[sizeof(struct sockaddr_in6)];
1118 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1119 int Length;
1120 BOOL ret;
1121 DWORD err;
1122
Oren Milman1d1d3e92017-08-20 18:35:36 +03001123 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1124 &ConnectSocket, &PyTuple_Type, &AddressObj))
1125 {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001126 return NULL;
Oren Milman1d1d3e92017-08-20 18:35:36 +03001127 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001128
1129 if (self->type != TYPE_NONE) {
1130 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1131 return NULL;
1132 }
1133
1134 Length = sizeof(AddressBuf);
1135 Length = parse_address(AddressObj, Address, Length);
1136 if (Length < 0)
1137 return NULL;
1138
1139 self->type = TYPE_CONNECT;
1140 self->handle = (HANDLE)ConnectSocket;
1141
1142 Py_BEGIN_ALLOW_THREADS
1143 ret = Py_ConnectEx(ConnectSocket, Address, Length,
1144 NULL, 0, NULL, &self->overlapped);
1145 Py_END_ALLOW_THREADS
1146
1147 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1148 switch (err) {
1149 case ERROR_SUCCESS:
1150 case ERROR_IO_PENDING:
1151 Py_RETURN_NONE;
1152 default:
1153 self->type = TYPE_NOT_STARTED;
1154 return SetFromWindowsErr(err);
1155 }
1156}
1157
1158PyDoc_STRVAR(
1159 Overlapped_DisconnectEx_doc,
1160 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1161 "Start overlapped connect. client_handle should be unbound.");
1162
1163static PyObject *
1164Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1165{
1166 SOCKET Socket;
1167 DWORD flags;
1168 BOOL ret;
1169 DWORD err;
1170
1171 if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1172 return NULL;
1173
1174 if (self->type != TYPE_NONE) {
1175 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1176 return NULL;
1177 }
1178
1179 self->type = TYPE_DISCONNECT;
1180 self->handle = (HANDLE)Socket;
1181
1182 Py_BEGIN_ALLOW_THREADS
1183 ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1184 Py_END_ALLOW_THREADS
1185
1186 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1187 switch (err) {
1188 case ERROR_SUCCESS:
1189 case ERROR_IO_PENDING:
1190 Py_RETURN_NONE;
1191 default:
1192 self->type = TYPE_NOT_STARTED;
1193 return SetFromWindowsErr(err);
1194 }
1195}
1196
1197PyDoc_STRVAR(
1198 Overlapped_ConnectNamedPipe_doc,
1199 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1200 "Start overlapped wait for a client to connect.");
1201
1202static PyObject *
1203Overlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1204{
1205 HANDLE Pipe;
1206 BOOL ret;
1207 DWORD err;
1208
1209 if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1210 return NULL;
1211
1212 if (self->type != TYPE_NONE) {
1213 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1214 return NULL;
1215 }
1216
1217 self->type = TYPE_CONNECT_NAMED_PIPE;
1218 self->handle = Pipe;
1219
1220 Py_BEGIN_ALLOW_THREADS
1221 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1222 Py_END_ALLOW_THREADS
1223
1224 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1225 switch (err) {
1226 case ERROR_PIPE_CONNECTED:
1227 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001228 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001229 case ERROR_SUCCESS:
1230 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001231 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001232 default:
1233 self->type = TYPE_NOT_STARTED;
1234 return SetFromWindowsErr(err);
1235 }
1236}
1237
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001238PyDoc_STRVAR(
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001239 ConnectPipe_doc,
1240 "ConnectPipe(addr) -> pipe_handle\n\n"
1241 "Connect to the pipe for asynchronous I/O (overlapped).");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001242
1243static PyObject *
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001244ConnectPipe(OverlappedObject *self, PyObject *args)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001245{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001246 PyObject *AddressObj;
1247 wchar_t *Address;
1248 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001249
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001250 if (!PyArg_ParseTuple(args, "U", &AddressObj))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001251 return NULL;
1252
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001253 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1254 if (Address == NULL)
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001255 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001256
Victor Stinner498b1f62015-01-26 22:43:39 +01001257 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001258 PipeHandle = CreateFileW(Address,
1259 GENERIC_READ | GENERIC_WRITE,
1260 0, NULL, OPEN_EXISTING,
1261 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001262 Py_END_ALLOW_THREADS
1263
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001264 PyMem_Free(Address);
1265 if (PipeHandle == INVALID_HANDLE_VALUE)
1266 return SetFromWindowsErr(0);
1267 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001268}
1269
1270static PyObject*
1271Overlapped_getaddress(OverlappedObject *self)
1272{
1273 return PyLong_FromVoidPtr(&self->overlapped);
1274}
1275
1276static PyObject*
1277Overlapped_getpending(OverlappedObject *self)
1278{
1279 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1280 self->type != TYPE_NOT_STARTED);
1281}
1282
1283static PyMethodDef Overlapped_methods[] = {
1284 {"getresult", (PyCFunction) Overlapped_getresult,
1285 METH_VARARGS, Overlapped_getresult_doc},
1286 {"cancel", (PyCFunction) Overlapped_cancel,
1287 METH_NOARGS, Overlapped_cancel_doc},
1288 {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1289 METH_VARARGS, Overlapped_ReadFile_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001290 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1291 METH_VARARGS, Overlapped_ReadFileInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001292 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1293 METH_VARARGS, Overlapped_WSARecv_doc},
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001294 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1295 METH_VARARGS, Overlapped_WSARecvInto_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001296 {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1297 METH_VARARGS, Overlapped_WriteFile_doc},
1298 {"WSASend", (PyCFunction) Overlapped_WSASend,
1299 METH_VARARGS, Overlapped_WSASend_doc},
1300 {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1301 METH_VARARGS, Overlapped_AcceptEx_doc},
1302 {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1303 METH_VARARGS, Overlapped_ConnectEx_doc},
1304 {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1305 METH_VARARGS, Overlapped_DisconnectEx_doc},
1306 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1307 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001308 {NULL}
1309};
1310
1311static PyMemberDef Overlapped_members[] = {
1312 {"error", T_ULONG,
1313 offsetof(OverlappedObject, error),
1314 READONLY, "Error from last operation"},
1315 {"event", T_HANDLE,
1316 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1317 READONLY, "Overlapped event handle"},
1318 {NULL}
1319};
1320
1321static PyGetSetDef Overlapped_getsets[] = {
1322 {"address", (getter)Overlapped_getaddress, NULL,
1323 "Address of overlapped structure"},
1324 {"pending", (getter)Overlapped_getpending, NULL,
1325 "Whether the operation is pending"},
1326 {NULL},
1327};
1328
1329PyTypeObject OverlappedType = {
1330 PyVarObject_HEAD_INIT(NULL, 0)
1331 /* tp_name */ "_overlapped.Overlapped",
1332 /* tp_basicsize */ sizeof(OverlappedObject),
1333 /* tp_itemsize */ 0,
1334 /* tp_dealloc */ (destructor) Overlapped_dealloc,
1335 /* tp_print */ 0,
1336 /* tp_getattr */ 0,
1337 /* tp_setattr */ 0,
1338 /* tp_reserved */ 0,
1339 /* tp_repr */ 0,
1340 /* tp_as_number */ 0,
1341 /* tp_as_sequence */ 0,
1342 /* tp_as_mapping */ 0,
1343 /* tp_hash */ 0,
1344 /* tp_call */ 0,
1345 /* tp_str */ 0,
1346 /* tp_getattro */ 0,
1347 /* tp_setattro */ 0,
1348 /* tp_as_buffer */ 0,
1349 /* tp_flags */ Py_TPFLAGS_DEFAULT,
1350 /* tp_doc */ "OVERLAPPED structure wrapper",
1351 /* tp_traverse */ 0,
1352 /* tp_clear */ 0,
1353 /* tp_richcompare */ 0,
1354 /* tp_weaklistoffset */ 0,
1355 /* tp_iter */ 0,
1356 /* tp_iternext */ 0,
1357 /* tp_methods */ Overlapped_methods,
1358 /* tp_members */ Overlapped_members,
1359 /* tp_getset */ Overlapped_getsets,
1360 /* tp_base */ 0,
1361 /* tp_dict */ 0,
1362 /* tp_descr_get */ 0,
1363 /* tp_descr_set */ 0,
1364 /* tp_dictoffset */ 0,
1365 /* tp_init */ 0,
1366 /* tp_alloc */ 0,
1367 /* tp_new */ Overlapped_new,
1368};
1369
1370static PyMethodDef overlapped_functions[] = {
1371 {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1372 METH_VARARGS, CreateIoCompletionPort_doc},
1373 {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1374 METH_VARARGS, GetQueuedCompletionStatus_doc},
1375 {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1376 METH_VARARGS, PostQueuedCompletionStatus_doc},
1377 {"FormatMessage", overlapped_FormatMessage,
1378 METH_VARARGS, FormatMessage_doc},
1379 {"BindLocal", overlapped_BindLocal,
1380 METH_VARARGS, BindLocal_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001381 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1382 METH_VARARGS, RegisterWaitWithQueue_doc},
1383 {"UnregisterWait", overlapped_UnregisterWait,
1384 METH_VARARGS, UnregisterWait_doc},
Victor Stinnerd0a28de2015-01-21 23:39:51 +01001385 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1386 METH_VARARGS, UnregisterWaitEx_doc},
Guido van Rossum90fb9142013-10-30 14:44:05 -07001387 {"CreateEvent", overlapped_CreateEvent,
1388 METH_VARARGS, CreateEvent_doc},
1389 {"SetEvent", overlapped_SetEvent,
1390 METH_VARARGS, SetEvent_doc},
1391 {"ResetEvent", overlapped_ResetEvent,
1392 METH_VARARGS, ResetEvent_doc},
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001393 {"ConnectPipe",
1394 (PyCFunction) ConnectPipe,
1395 METH_VARARGS, ConnectPipe_doc},
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001396 {NULL}
1397};
1398
1399static struct PyModuleDef overlapped_module = {
1400 PyModuleDef_HEAD_INIT,
1401 "_overlapped",
1402 NULL,
1403 -1,
1404 overlapped_functions,
1405 NULL,
1406 NULL,
1407 NULL,
1408 NULL
1409};
1410
1411#define WINAPI_CONSTANT(fmt, con) \
1412 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1413
1414PyMODINIT_FUNC
1415PyInit__overlapped(void)
1416{
1417 PyObject *m, *d;
1418
1419 /* Ensure WSAStartup() called before initializing function pointers */
1420 m = PyImport_ImportModule("_socket");
1421 if (!m)
1422 return NULL;
1423 Py_DECREF(m);
1424
1425 if (initialize_function_pointers() < 0)
1426 return NULL;
1427
1428 if (PyType_Ready(&OverlappedType) < 0)
1429 return NULL;
1430
1431 m = PyModule_Create(&overlapped_module);
1432 if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
1433 return NULL;
1434
1435 d = PyModule_GetDict(m);
1436
1437 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1438 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1439 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001440 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001441 WINAPI_CONSTANT(F_DWORD, INFINITE);
1442 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1443 WINAPI_CONSTANT(F_HANDLE, NULL);
1444 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1445 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1446 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1447
1448 return m;
1449}