1 /*
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
26 /* 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
32 #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
40 enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
41 TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
42 TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE};
43
44 typedef 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 {
54 /* 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;
58 };
59 } OverlappedObject;
60
61 /*
62 * Map Windows error codes to subclasses of OSError
63 */
64
65 static PyObject *
SetFromWindowsErr(DWORD err)66 SetFromWindowsErr(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
89 static LPFN_ACCEPTEX Py_AcceptEx = NULL;
90 static LPFN_CONNECTEX Py_ConnectEx = NULL;
91 static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
92 static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
93 static 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
100 static int
initialize_function_pointers(void)101 initialize_function_pointers(void)
102 {
103 GUID GuidAcceptEx = WSAID_ACCEPTEX;
104 GUID GuidConnectEx = WSAID_CONNECTEX;
105 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
106 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
107 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) ||
119 !GET_WSA_POINTER(s, DisconnectEx) ||
120 !GET_WSA_POINTER(s, TransmitFile))
121 {
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
139 PyDoc_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
144 static PyObject *
overlapped_CreateIoCompletionPort(PyObject * self,PyObject * args)145 overlapped_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
168 PyDoc_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
173 static PyObject *
overlapped_GetQueuedCompletionStatus(PyObject * self,PyObject * args)174 overlapped_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
204 PyDoc_STRVAR(
205 PostQueuedCompletionStatus_doc,
206 "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
207 "Post a message to completion port.");
208
209 static PyObject *
overlapped_PostQueuedCompletionStatus(PyObject * self,PyObject * args)210 overlapped_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 /*
234 * Wait for a handle
235 */
236
237 struct PostCallbackData {
238 HANDLE CompletionPort;
239 LPOVERLAPPED Overlapped;
240 };
241
242 static VOID CALLBACK
PostToQueueCallback(PVOID lpParameter,BOOL TimerOrWaitFired)243 PostToQueueCallback(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! */
250 PyMem_RawFree(p);
251 }
252
253 PyDoc_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
259 static PyObject *
overlapped_RegisterWaitWithQueue(PyObject * self,PyObject * args)260 overlapped_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
274 /* 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));
278 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 {
288 PyMem_RawFree(pdata);
289 return SetFromWindowsErr(0);
290 }
291
292 return Py_BuildValue(F_HANDLE, NewWaitObject);
293 }
294
295 PyDoc_STRVAR(
296 UnregisterWait_doc,
297 "UnregisterWait(WaitHandle) -> None\n\n"
298 "Unregister wait handle.\n");
299
300 static PyObject *
overlapped_UnregisterWait(PyObject * self,PyObject * args)301 overlapped_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
318 PyDoc_STRVAR(
319 UnregisterWaitEx_doc,
320 "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
321 "Unregister wait handle.\n");
322
323 static PyObject *
overlapped_UnregisterWaitEx(PyObject * self,PyObject * args)324 overlapped_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
341 /*
342 * Event functions -- currently only used by tests
343 */
344
345 PyDoc_STRVAR(
346 CreateEvent_doc,
347 "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
348 " -> Handle\n\n"
349 "Create an event. EventAttributes must be None.\n");
350
351 static PyObject *
overlapped_CreateEvent(PyObject * self,PyObject * args)352 overlapped_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
379 PyDoc_STRVAR(
380 SetEvent_doc,
381 "SetEvent(Handle) -> None\n\n"
382 "Set event.\n");
383
384 static PyObject *
overlapped_SetEvent(PyObject * self,PyObject * args)385 overlapped_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
402 PyDoc_STRVAR(
403 ResetEvent_doc,
404 "ResetEvent(Handle) -> None\n\n"
405 "Reset event.\n");
406
407 static PyObject *
overlapped_ResetEvent(PyObject * self,PyObject * args)408 overlapped_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 /*
426 * Bind socket handle to local port without doing slow getaddrinfo()
427 */
428
429 PyDoc_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
435 static PyObject *
overlapped_BindLocal(PyObject * self,PyObject * args)436 overlapped_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
473 PyDoc_STRVAR(
474 FormatMessage_doc,
475 "FormatMessage(error_code) -> error_message\n\n"
476 "Return error message for an error code.");
477
478 static PyObject *
overlapped_FormatMessage(PyObject * ignore,PyObject * args)479 overlapped_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
513 static void
mark_as_completed(OVERLAPPED * ov)514 mark_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
526 PyDoc_STRVAR(
527 Overlapped_doc,
528 "Overlapped object");
529
530 static PyObject *
Overlapped_new(PyTypeObject * type,PyObject * args,PyObject * kwds)531 Overlapped_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;
556 self->allocated_buffer = NULL;
557 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
558 memset(&self->user_buffer, 0, sizeof(Py_buffer));
559 if (event)
560 self->overlapped.hEvent = event;
561 return (PyObject *)self;
562 }
563
564
565 /* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
566 buffers while overlapped are still running, to prevent a crash. */
567 static int
Overlapped_clear(OverlappedObject * self)568 Overlapped_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
586 static void
Overlapped_dealloc(OverlappedObject * self)587 Overlapped_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
619 if (self->overlapped.hEvent != NULL) {
620 CloseHandle(self->overlapped.hEvent);
621 }
622
623 Overlapped_clear(self);
624 PyObject_Del(self);
625 SetLastError(olderr);
626 }
627
628 PyDoc_STRVAR(
629 Overlapped_cancel_doc,
630 "cancel() -> None\n\n"
631 "Cancel overlapped operation");
632
633 static PyObject *
Overlapped_cancel(OverlappedObject * self)634 Overlapped_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
657 PyDoc_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
664 static PyObject *
Overlapped_getresult(OverlappedObject * self,PyObject * args)665 Overlapped_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:
696 if (self->type == TYPE_READ || self->type == TYPE_READINTO)
697 break;
698 /* fall through */
699 default:
700 return SetFromWindowsErr(err);
701 }
702
703 switch (self->type) {
704 case TYPE_READ:
705 assert(PyBytes_CheckExact(self->allocated_buffer));
706 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
707 _PyBytes_Resize(&self->allocated_buffer, transferred))
708 return NULL;
709 Py_INCREF(self->allocated_buffer);
710 return self->allocated_buffer;
711 default:
712 return PyLong_FromUnsignedLong((unsigned long) transferred);
713 }
714 }
715
716 static PyObject *
do_ReadFile(OverlappedObject * self,HANDLE handle,char * bufstart,DWORD buflen)717 do_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:
739 Overlapped_clear(self);
740 return SetFromWindowsErr(err);
741 }
742 }
743
744 PyDoc_STRVAR(
745 Overlapped_ReadFile_doc,
746 "ReadFile(handle, size) -> Overlapped[message]\n\n"
747 "Start overlapped read");
748
749 static PyObject *
Overlapped_ReadFile(OverlappedObject * self,PyObject * args)750 Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
751 {
752 HANDLE handle;
753 DWORD size;
754 PyObject *buf;
755
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;
773 self->allocated_buffer = buf;
774
775 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
776 }
777
778 PyDoc_STRVAR(
779 Overlapped_ReadFileInto_doc,
780 "ReadFileInto(handle, buf) -> Overlapped[bytes_transferred]\n\n"
781 "Start overlapped receive");
782
783 static PyObject *
Overlapped_ReadFileInto(OverlappedObject * self,PyObject * args)784 Overlapped_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
815 static PyObject *
do_WSARecv(OverlappedObject * self,HANDLE handle,char * bufstart,DWORD buflen,DWORD flags)816 do_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;
823
824 wsabuf.buf = bufstart;
825 wsabuf.len = buflen;
826
827 Py_BEGIN_ALLOW_THREADS
828 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
829 &self->overlapped, NULL);
830 Py_END_ALLOW_THREADS
831
832 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
833 switch (err) {
834 case ERROR_BROKEN_PIPE:
835 mark_as_completed(&self->overlapped);
836 return SetFromWindowsErr(err);
837 case ERROR_SUCCESS:
838 case ERROR_MORE_DATA:
839 case ERROR_IO_PENDING:
840 Py_RETURN_NONE;
841 default:
842 Overlapped_clear(self);
843 return SetFromWindowsErr(err);
844 }
845 }
846
847 PyDoc_STRVAR(
848 Overlapped_WSARecv_doc,
849 "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
850 "Start overlapped receive");
851
852 static PyObject *
Overlapped_WSARecv(OverlappedObject * self,PyObject * args)853 Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
854 {
855 HANDLE handle;
856 DWORD size;
857 DWORD flags = 0;
858 PyObject *buf;
859
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;
878 self->allocated_buffer = buf;
879
880 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
881 }
882
883 PyDoc_STRVAR(
884 Overlapped_WSARecvInto_doc,
885 "WSARecvInto(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
886 "Start overlapped receive");
887
888 static PyObject *
Overlapped_WSARecvInto(OverlappedObject * self,PyObject * args)889 Overlapped_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;
902 }
903
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);
920 }
921
922 PyDoc_STRVAR(
923 Overlapped_WriteFile_doc,
924 "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
925 "Start overlapped write");
926
927 static PyObject *
Overlapped_WriteFile(OverlappedObject * self,PyObject * args)928 Overlapped_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
944 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
945 return NULL;
946
947 #if SIZEOF_SIZE_T > SIZEOF_LONG
948 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
949 PyBuffer_Release(&self->user_buffer);
950 PyErr_SetString(PyExc_ValueError, "buffer too large");
951 return NULL;
952 }
953 #endif
954
955 self->type = TYPE_WRITE;
956 self->handle = handle;
957
958 Py_BEGIN_ALLOW_THREADS
959 ret = WriteFile(handle, self->user_buffer.buf,
960 (DWORD)self->user_buffer.len,
961 &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:
970 Overlapped_clear(self);
971 return SetFromWindowsErr(err);
972 }
973 }
974
975 PyDoc_STRVAR(
976 Overlapped_WSASend_doc,
977 "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
978 "Start overlapped send");
979
980 static PyObject *
Overlapped_WSASend(OverlappedObject * self,PyObject * args)981 Overlapped_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
1000 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1001 return NULL;
1002
1003 #if SIZEOF_SIZE_T > SIZEOF_LONG
1004 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1005 PyBuffer_Release(&self->user_buffer);
1006 PyErr_SetString(PyExc_ValueError, "buffer too large");
1007 return NULL;
1008 }
1009 #endif
1010
1011 self->type = TYPE_WRITE;
1012 self->handle = handle;
1013 wsabuf.len = (DWORD)self->user_buffer.len;
1014 wsabuf.buf = self->user_buffer.buf;
1015
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:
1027 Overlapped_clear(self);
1028 return SetFromWindowsErr(err);
1029 }
1030 }
1031
1032 PyDoc_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
1037 static PyObject *
Overlapped_AcceptEx(OverlappedObject * self,PyObject * args)1038 Overlapped_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;
1064 self->allocated_buffer = buf;
1065
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:
1077 Overlapped_clear(self);
1078 return SetFromWindowsErr(err);
1079 }
1080 }
1081
1082
1083 static int
parse_address(PyObject * obj,SOCKADDR * Address,int Length)1084 parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1085 {
1086 Py_UNICODE *Host;
1087 unsigned short Port;
1088 unsigned long FlowInfo;
1089 unsigned long ScopeId;
1090
1091 memset(Address, 0, Length);
1092
1093 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
1094 {
1095 Address->sa_family = AF_INET;
1096 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
1097 SetFromWindowsErr(WSAGetLastError());
1098 return -1;
1099 }
1100 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1101 return Length;
1102 }
1103 else if (PyArg_ParseTuple(obj,
1104 "uHkk;ConnectEx(): illegal address_as_bytes "
1105 "argument", &Host, &Port, &FlowInfo, &ScopeId))
1106 {
1107 PyErr_Clear();
1108 Address->sa_family = AF_INET6;
1109 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
1110 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
1123 PyDoc_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
1128 static PyObject *
Overlapped_ConnectEx(OverlappedObject * self,PyObject * args)1129 Overlapped_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
1139 if (!PyArg_ParseTuple(args, F_HANDLE "O!:ConnectEx",
1140 &ConnectSocket, &PyTuple_Type, &AddressObj))
1141 {
1142 return NULL;
1143 }
1144
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:
1169 Overlapped_clear(self);
1170 return SetFromWindowsErr(err);
1171 }
1172 }
1173
1174 PyDoc_STRVAR(
1175 Overlapped_DisconnectEx_doc,
1176 "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1177 "Start overlapped connect. client_handle should be unbound.");
1178
1179 static PyObject *
Overlapped_DisconnectEx(OverlappedObject * self,PyObject * args)1180 Overlapped_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:
1208 Overlapped_clear(self);
1209 return SetFromWindowsErr(err);
1210 }
1211 }
1212
1213 PyDoc_STRVAR(
1214 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
1220 static PyObject *
Overlapped_TransmitFile(OverlappedObject * self,PyObject * args)1221 Overlapped_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:
1263 Overlapped_clear(self);
1264 return SetFromWindowsErr(err);
1265 }
1266 }
1267
1268 PyDoc_STRVAR(
1269 Overlapped_ConnectNamedPipe_doc,
1270 "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1271 "Start overlapped wait for a client to connect.");
1272
1273 static PyObject *
Overlapped_ConnectNamedPipe(OverlappedObject * self,PyObject * args)1274 Overlapped_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);
1299 Py_RETURN_TRUE;
1300 case ERROR_SUCCESS:
1301 case ERROR_IO_PENDING:
1302 Py_RETURN_FALSE;
1303 default:
1304 Overlapped_clear(self);
1305 return SetFromWindowsErr(err);
1306 }
1307 }
1308
1309 PyDoc_STRVAR(
1310 ConnectPipe_doc,
1311 "ConnectPipe(addr) -> pipe_handle\n\n"
1312 "Connect to the pipe for asynchronous I/O (overlapped).");
1313
1314 static PyObject *
ConnectPipe(OverlappedObject * self,PyObject * args)1315 ConnectPipe(OverlappedObject *self, PyObject *args)
1316 {
1317 PyObject *AddressObj;
1318 wchar_t *Address;
1319 HANDLE PipeHandle;
1320
1321 if (!PyArg_ParseTuple(args, "U", &AddressObj))
1322 return NULL;
1323
1324 Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1325 if (Address == NULL)
1326 return NULL;
1327
1328 Py_BEGIN_ALLOW_THREADS
1329 PipeHandle = CreateFileW(Address,
1330 GENERIC_READ | GENERIC_WRITE,
1331 0, NULL, OPEN_EXISTING,
1332 FILE_FLAG_OVERLAPPED, NULL);
1333 Py_END_ALLOW_THREADS
1334
1335 PyMem_Free(Address);
1336 if (PipeHandle == INVALID_HANDLE_VALUE)
1337 return SetFromWindowsErr(0);
1338 return Py_BuildValue(F_HANDLE, PipeHandle);
1339 }
1340
1341 static PyObject*
Overlapped_getaddress(OverlappedObject * self)1342 Overlapped_getaddress(OverlappedObject *self)
1343 {
1344 return PyLong_FromVoidPtr(&self->overlapped);
1345 }
1346
1347 static PyObject*
Overlapped_getpending(OverlappedObject * self)1348 Overlapped_getpending(OverlappedObject *self)
1349 {
1350 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1351 self->type != TYPE_NOT_STARTED);
1352 }
1353
1354 static int
Overlapped_traverse(OverlappedObject * self,visitproc visit,void * arg)1355 Overlapped_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
1373 static 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},
1380 {"ReadFileInto", (PyCFunction) Overlapped_ReadFileInto,
1381 METH_VARARGS, Overlapped_ReadFileInto_doc},
1382 {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1383 METH_VARARGS, Overlapped_WSARecv_doc},
1384 {"WSARecvInto", (PyCFunction) Overlapped_WSARecvInto,
1385 METH_VARARGS, Overlapped_WSARecvInto_doc},
1386 {"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},
1396 {"TransmitFile", (PyCFunction) Overlapped_TransmitFile,
1397 METH_VARARGS, Overlapped_TransmitFile_doc},
1398 {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1399 METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
1400 {NULL}
1401 };
1402
1403 static 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
1413 static 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
1421 PyTypeObject 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",
1443 /* tp_traverse */ (traverseproc)Overlapped_traverse,
1444 /* 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
1462 static 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},
1473 {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1474 METH_VARARGS, RegisterWaitWithQueue_doc},
1475 {"UnregisterWait", overlapped_UnregisterWait,
1476 METH_VARARGS, UnregisterWait_doc},
1477 {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1478 METH_VARARGS, UnregisterWaitEx_doc},
1479 {"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},
1485 {"ConnectPipe",
1486 (PyCFunction) ConnectPipe,
1487 METH_VARARGS, ConnectPipe_doc},
1488 {NULL}
1489 };
1490
1491 static 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
1506 PyMODINIT_FUNC
PyInit__overlapped(void)1507 PyInit__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);
1531 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
1532 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1533 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1534 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 }
1543