• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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