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"         // PyMemberDef
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 #define F_HANDLE F_POINTER
27 #define F_ULONG_PTR F_POINTER
28 #define F_DWORD "k"
29 #define F_BOOL "i"
30 #define F_UINT "I"
31 
32 #define T_HANDLE T_POINTER
33 
34 /*[python input]
35 class OVERLAPPED_converter(CConverter):
36     type = 'OVERLAPPED *'
37     format_unit = '"F_POINTER"'
38 
39 class HANDLE_converter(CConverter):
40     type = 'HANDLE'
41     format_unit = '"F_HANDLE"'
42 
43 class ULONG_PTR_converter(CConverter):
44     type = 'ULONG_PTR'
45     format_unit = '"F_ULONG_PTR"'
46 
47 class DWORD_converter(CConverter):
48     type = 'DWORD'
49     format_unit = 'k'
50 
51 class BOOL_converter(CConverter):
52     type = 'BOOL'
53     format_unit = 'i'
54 [python start generated code]*/
55 /*[python end generated code: output=da39a3ee5e6b4b0d input=83bb8c2c2514f2a8]*/
56 
57 /*[clinic input]
58 module _overlapped
59 class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType"
60 [clinic start generated code]*/
61 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=92e5a799db35b96c]*/
62 
63 
64 enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
65       TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
66       TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
67       TYPE_WRITE_TO, TYPE_READ_FROM_INTO};
68 
69 typedef struct {
70     PyObject_HEAD
71     OVERLAPPED overlapped;
72     /* For convenience, we store the file handle too */
73     HANDLE handle;
74     /* Error returned by last method call */
75     DWORD error;
76     /* Type of operation */
77     DWORD type;
78     union {
79         /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
80         PyObject *allocated_buffer;
81         /* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */
82         Py_buffer user_buffer;
83 
84         /* Data used for reading from a connectionless socket:
85            TYPE_READ_FROM */
86         struct {
87             // A (buffer, (host, port)) tuple
88             PyObject *result;
89             // The actual read buffer
90             PyObject *allocated_buffer;
91             struct sockaddr_in6 address;
92             int address_length;
93         } read_from;
94 
95         /* Data used for reading from a connectionless socket:
96            TYPE_READ_FROM_INTO */
97         struct {
98             // A (number of bytes read, (host, port)) tuple
99             PyObject* result;
100             /* Buffer passed by the user */
101             Py_buffer user_buffer;
102             struct sockaddr_in6 address;
103             int address_length;
104         } read_from_into;
105     };
106 } OverlappedObject;
107 
108 typedef struct {
109     PyTypeObject *overlapped_type;
110 } OverlappedState;
111 
112 static inline OverlappedState*
overlapped_get_state(PyObject * module)113 overlapped_get_state(PyObject *module)
114 {
115     void *state = PyModule_GetState(module);
116     assert(state != NULL);
117     return (OverlappedState *)state;
118 }
119 
120 
121 static inline void
steal_buffer(Py_buffer * dst,Py_buffer * src)122 steal_buffer(Py_buffer * dst, Py_buffer * src)
123 {
124     memcpy(dst, src, sizeof(Py_buffer));
125     memset(src, 0, sizeof(Py_buffer));
126 }
127 
128 /*
129  * Map Windows error codes to subclasses of OSError
130  */
131 
132 static PyObject *
SetFromWindowsErr(DWORD err)133 SetFromWindowsErr(DWORD err)
134 {
135     PyObject *exception_type;
136 
137     if (err == 0)
138         err = GetLastError();
139     switch (err) {
140         case ERROR_CONNECTION_REFUSED:
141             exception_type = PyExc_ConnectionRefusedError;
142             break;
143         case ERROR_CONNECTION_ABORTED:
144             exception_type = PyExc_ConnectionAbortedError;
145             break;
146         default:
147             exception_type = PyExc_OSError;
148     }
149     return PyErr_SetExcFromWindowsErr(exception_type, err);
150 }
151 
152 /*
153  * Some functions should be loaded at runtime
154  */
155 
156 static LPFN_ACCEPTEX Py_AcceptEx = NULL;
157 static LPFN_CONNECTEX Py_ConnectEx = NULL;
158 static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
159 static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
160 
161 #define GET_WSA_POINTER(s, x)                                           \
162     (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,    \
163                               &Guid##x, sizeof(Guid##x), &Py_##x,       \
164                               sizeof(Py_##x), &dwBytes, NULL, NULL))
165 
166 static int
initialize_function_pointers(void)167 initialize_function_pointers(void)
168 {
169     GUID GuidAcceptEx = WSAID_ACCEPTEX;
170     GUID GuidConnectEx = WSAID_CONNECTEX;
171     GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
172     GUID GuidTransmitFile = WSAID_TRANSMITFILE;
173     SOCKET s;
174     DWORD dwBytes;
175 
176     if (Py_AcceptEx != NULL &&
177         Py_ConnectEx != NULL &&
178         Py_DisconnectEx != NULL &&
179         Py_TransmitFile != NULL)
180     {
181         // All function pointers are initialized already
182         // by previous module import
183         return 0;
184     }
185 
186     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
187     if (s == INVALID_SOCKET) {
188         SetFromWindowsErr(WSAGetLastError());
189         return -1;
190     }
191 
192     if (!GET_WSA_POINTER(s, AcceptEx) ||
193         !GET_WSA_POINTER(s, ConnectEx) ||
194         !GET_WSA_POINTER(s, DisconnectEx) ||
195         !GET_WSA_POINTER(s, TransmitFile))
196     {
197         closesocket(s);
198         SetFromWindowsErr(WSAGetLastError());
199         return -1;
200     }
201 
202     closesocket(s);
203     return 0;
204 }
205 
206 /*
207  * Completion port stuff
208  */
209 
210 /*[clinic input]
211 _overlapped.CreateIoCompletionPort
212 
213     handle as FileHandle: HANDLE
214     port as ExistingCompletionPort: HANDLE
215     key as CompletionKey: ULONG_PTR
216     concurrency as NumberOfConcurrentThreads: DWORD
217     /
218 
219 Create a completion port or register a handle with a port.
220 [clinic start generated code]*/
221 
222 static PyObject *
_overlapped_CreateIoCompletionPort_impl(PyObject * module,HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads)223 _overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle,
224                                         HANDLE ExistingCompletionPort,
225                                         ULONG_PTR CompletionKey,
226                                         DWORD NumberOfConcurrentThreads)
227 /*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/
228 {
229     HANDLE ret;
230 
231     Py_BEGIN_ALLOW_THREADS
232     ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
233                                  CompletionKey, NumberOfConcurrentThreads);
234     Py_END_ALLOW_THREADS
235 
236     if (ret == NULL)
237         return SetFromWindowsErr(0);
238     return Py_BuildValue(F_HANDLE, ret);
239 }
240 
241 /*[clinic input]
242 _overlapped.GetQueuedCompletionStatus
243 
244     port as CompletionPort: HANDLE
245     msecs as Milliseconds: DWORD
246     /
247 
248 Get a message from completion port.
249 
250 Wait for up to msecs milliseconds.
251 [clinic start generated code]*/
252 
253 static PyObject *
_overlapped_GetQueuedCompletionStatus_impl(PyObject * module,HANDLE CompletionPort,DWORD Milliseconds)254 _overlapped_GetQueuedCompletionStatus_impl(PyObject *module,
255                                            HANDLE CompletionPort,
256                                            DWORD Milliseconds)
257 /*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/
258 {
259     DWORD NumberOfBytes = 0;
260     ULONG_PTR CompletionKey = 0;
261     OVERLAPPED *Overlapped = NULL;
262     DWORD err;
263     BOOL ret;
264 
265     Py_BEGIN_ALLOW_THREADS
266     ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
267                                     &CompletionKey, &Overlapped, Milliseconds);
268     Py_END_ALLOW_THREADS
269 
270     err = ret ? ERROR_SUCCESS : GetLastError();
271     if (Overlapped == NULL) {
272         if (err == WAIT_TIMEOUT)
273             Py_RETURN_NONE;
274         else
275             return SetFromWindowsErr(err);
276     }
277     return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
278                          err, NumberOfBytes, CompletionKey, Overlapped);
279 }
280 
281 /*[clinic input]
282 _overlapped.PostQueuedCompletionStatus
283 
284     port as CompletionPort: HANDLE
285     bytes as NumberOfBytes: DWORD
286     key as CompletionKey: ULONG_PTR
287     address as Overlapped: OVERLAPPED
288     /
289 
290 Post a message to completion port.
291 [clinic start generated code]*/
292 
293 static PyObject *
_overlapped_PostQueuedCompletionStatus_impl(PyObject * module,HANDLE CompletionPort,DWORD NumberOfBytes,ULONG_PTR CompletionKey,OVERLAPPED * Overlapped)294 _overlapped_PostQueuedCompletionStatus_impl(PyObject *module,
295                                             HANDLE CompletionPort,
296                                             DWORD NumberOfBytes,
297                                             ULONG_PTR CompletionKey,
298                                             OVERLAPPED *Overlapped)
299 /*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/
300 {
301     BOOL ret;
302 
303     Py_BEGIN_ALLOW_THREADS
304     ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
305                                      CompletionKey, Overlapped);
306     Py_END_ALLOW_THREADS
307 
308     if (!ret)
309         return SetFromWindowsErr(0);
310     Py_RETURN_NONE;
311 }
312 
313 /*
314  * Wait for a handle
315  */
316 
317 struct PostCallbackData {
318     HANDLE CompletionPort;
319     LPOVERLAPPED Overlapped;
320 };
321 
322 static VOID CALLBACK
PostToQueueCallback(PVOID lpParameter,BOOLEAN TimerOrWaitFired)323 PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
324 {
325     struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
326 
327     PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
328                                0, p->Overlapped);
329     /* ignore possible error! */
330     PyMem_RawFree(p);
331 }
332 
333 /*[clinic input]
334 _overlapped.RegisterWaitWithQueue
335 
336     Object: HANDLE
337     CompletionPort: HANDLE
338     Overlapped: OVERLAPPED
339     Timeout as Milliseconds: DWORD
340     /
341 
342 Register wait for Object; when complete CompletionPort is notified.
343 [clinic start generated code]*/
344 
345 static PyObject *
_overlapped_RegisterWaitWithQueue_impl(PyObject * module,HANDLE Object,HANDLE CompletionPort,OVERLAPPED * Overlapped,DWORD Milliseconds)346 _overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
347                                        HANDLE CompletionPort,
348                                        OVERLAPPED *Overlapped,
349                                        DWORD Milliseconds)
350 /*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/
351 {
352     HANDLE NewWaitObject;
353     struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata;
354 
355     /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
356        PostToQueueCallback() will call PyMem_Free() from a new C thread
357        which doesn't hold the GIL. */
358     pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
359     if (pdata == NULL)
360         return SetFromWindowsErr(0);
361 
362     *pdata = data;
363 
364     if (!RegisterWaitForSingleObject(
365             &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
366             WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
367     {
368         PyMem_RawFree(pdata);
369         return SetFromWindowsErr(0);
370     }
371 
372     return Py_BuildValue(F_HANDLE, NewWaitObject);
373 }
374 
375 /*[clinic input]
376 _overlapped.UnregisterWait
377 
378     WaitHandle: HANDLE
379     /
380 
381 Unregister wait handle.
382 [clinic start generated code]*/
383 
384 static PyObject *
_overlapped_UnregisterWait_impl(PyObject * module,HANDLE WaitHandle)385 _overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
386 /*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
387 {
388     BOOL ret;
389 
390     Py_BEGIN_ALLOW_THREADS
391     ret = UnregisterWait(WaitHandle);
392     Py_END_ALLOW_THREADS
393 
394     if (!ret)
395         return SetFromWindowsErr(0);
396     Py_RETURN_NONE;
397 }
398 
399 /*[clinic input]
400 _overlapped.UnregisterWaitEx
401 
402     WaitHandle: HANDLE
403     Event: HANDLE
404     /
405 
406 Unregister wait handle.
407 [clinic start generated code]*/
408 
409 static PyObject *
_overlapped_UnregisterWaitEx_impl(PyObject * module,HANDLE WaitHandle,HANDLE Event)410 _overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
411                                   HANDLE Event)
412 /*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
413 {
414     BOOL ret;
415 
416     Py_BEGIN_ALLOW_THREADS
417     ret = UnregisterWaitEx(WaitHandle, Event);
418     Py_END_ALLOW_THREADS
419 
420     if (!ret)
421         return SetFromWindowsErr(0);
422     Py_RETURN_NONE;
423 }
424 
425 /*
426  * Event functions -- currently only used by tests
427  */
428 
429 /*[clinic input]
430 _overlapped.CreateEvent
431 
432     EventAttributes: object
433     ManualReset: BOOL
434     InitialState: BOOL
435     Name: Py_UNICODE(accept={str, NoneType})
436     /
437 
438 Create an event.
439 
440 EventAttributes must be None.
441 [clinic start generated code]*/
442 
443 static PyObject *
_overlapped_CreateEvent_impl(PyObject * module,PyObject * EventAttributes,BOOL ManualReset,BOOL InitialState,const Py_UNICODE * Name)444 _overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
445                              BOOL ManualReset, BOOL InitialState,
446                              const Py_UNICODE *Name)
447 /*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
448 {
449     HANDLE Event;
450 
451     if (EventAttributes != Py_None) {
452         PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
453         return NULL;
454     }
455 
456     Py_BEGIN_ALLOW_THREADS
457     Event = CreateEventW(NULL, ManualReset, InitialState, Name);
458     Py_END_ALLOW_THREADS
459 
460     if (Event == NULL)
461         return SetFromWindowsErr(0);
462     return Py_BuildValue(F_HANDLE, Event);
463 }
464 
465 /*[clinic input]
466 _overlapped.SetEvent
467 
468     Handle: HANDLE
469     /
470 
471 Set event.
472 [clinic start generated code]*/
473 
474 static PyObject *
_overlapped_SetEvent_impl(PyObject * module,HANDLE Handle)475 _overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
476 /*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
477 {
478     BOOL ret;
479 
480     Py_BEGIN_ALLOW_THREADS
481     ret = SetEvent(Handle);
482     Py_END_ALLOW_THREADS
483 
484     if (!ret)
485         return SetFromWindowsErr(0);
486     Py_RETURN_NONE;
487 }
488 
489 /*[clinic input]
490 _overlapped.ResetEvent
491 
492     Handle: HANDLE
493     /
494 
495 Reset event.
496 [clinic start generated code]*/
497 
498 static PyObject *
_overlapped_ResetEvent_impl(PyObject * module,HANDLE Handle)499 _overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
500 /*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
501 {
502     BOOL ret;
503 
504     Py_BEGIN_ALLOW_THREADS
505     ret = ResetEvent(Handle);
506     Py_END_ALLOW_THREADS
507 
508     if (!ret)
509         return SetFromWindowsErr(0);
510     Py_RETURN_NONE;
511 }
512 
513 /*
514  * Bind socket handle to local port without doing slow getaddrinfo()
515  */
516 
517 /*[clinic input]
518 _overlapped.BindLocal
519 
520     handle as Socket: HANDLE
521     family as Family: int
522     /
523 
524 Bind a socket handle to an arbitrary local port.
525 
526 family should be AF_INET or AF_INET6.
527 [clinic start generated code]*/
528 
529 static PyObject *
_overlapped_BindLocal_impl(PyObject * module,HANDLE Socket,int Family)530 _overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
531 /*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
532 {
533     BOOL ret;
534 
535     if (Family == AF_INET) {
536         struct sockaddr_in addr;
537         memset(&addr, 0, sizeof(addr));
538         addr.sin_family = AF_INET;
539         addr.sin_port = 0;
540         addr.sin_addr.S_un.S_addr = INADDR_ANY;
541         ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
542                 != SOCKET_ERROR;
543     } else if (Family == AF_INET6) {
544         struct sockaddr_in6 addr;
545         memset(&addr, 0, sizeof(addr));
546         addr.sin6_family = AF_INET6;
547         addr.sin6_port = 0;
548         addr.sin6_addr = in6addr_any;
549         ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
550                 != SOCKET_ERROR;
551     } else {
552         PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
553         return NULL;
554     }
555 
556     if (!ret)
557         return SetFromWindowsErr(WSAGetLastError());
558     Py_RETURN_NONE;
559 }
560 
561 /*
562  * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
563  */
564 
565 /*[clinic input]
566 _overlapped.FormatMessage
567 
568     error_code as code: DWORD
569     /
570 
571 Return error message for an error code.
572 [clinic start generated code]*/
573 
574 static PyObject *
_overlapped_FormatMessage_impl(PyObject * module,DWORD code)575 _overlapped_FormatMessage_impl(PyObject *module, DWORD code)
576 /*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
577 {
578     DWORD n;
579     WCHAR *lpMsgBuf;
580     PyObject *res;
581 
582     n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
583                        FORMAT_MESSAGE_FROM_SYSTEM |
584                        FORMAT_MESSAGE_IGNORE_INSERTS,
585                        NULL,
586                        code,
587                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
588                        (LPWSTR) &lpMsgBuf,
589                        0,
590                        NULL);
591     if (n) {
592         while (iswspace(lpMsgBuf[n-1]))
593             --n;
594         lpMsgBuf[n] = L'\0';
595         res = Py_BuildValue("u", lpMsgBuf);
596     } else {
597         res = PyUnicode_FromFormat("unknown error code %u", code);
598     }
599     LocalFree(lpMsgBuf);
600     return res;
601 }
602 
603 
604 /*
605  * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
606  */
607 
608 static inline void
mark_as_completed(OVERLAPPED * ov)609 mark_as_completed(OVERLAPPED *ov)
610 {
611     ov->Internal = 0;
612     if (ov->hEvent != NULL)
613         SetEvent(ov->hEvent);
614 }
615 
616 /*
617  * A Python object wrapping an OVERLAPPED structure and other useful data
618  * for overlapped I/O
619  */
620 
621 /*[clinic input]
622 @classmethod
623 _overlapped.Overlapped.__new__
624 
625     event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
626 
627 OVERLAPPED structure wrapper.
628 [clinic start generated code]*/
629 
630 static PyObject *
_overlapped_Overlapped_impl(PyTypeObject * type,HANDLE event)631 _overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
632 /*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
633 {
634     OverlappedObject *self;
635 
636     if (event == INVALID_HANDLE_VALUE) {
637         event = CreateEvent(NULL, TRUE, FALSE, NULL);
638         if (event == NULL)
639             return SetFromWindowsErr(0);
640     }
641 
642     self = PyObject_New(OverlappedObject, type);
643     if (self == NULL) {
644         if (event != NULL)
645             CloseHandle(event);
646         return NULL;
647     }
648 
649     self->handle = NULL;
650     self->error = 0;
651     self->type = TYPE_NONE;
652     self->allocated_buffer = NULL;
653     memset(&self->overlapped, 0, sizeof(OVERLAPPED));
654     memset(&self->user_buffer, 0, sizeof(Py_buffer));
655     if (event)
656         self->overlapped.hEvent = event;
657     return (PyObject *)self;
658 }
659 
660 
661 /* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
662    buffers while overlapped are still running, to prevent a crash. */
663 static int
Overlapped_clear(OverlappedObject * self)664 Overlapped_clear(OverlappedObject *self)
665 {
666     switch (self->type) {
667         case TYPE_READ:
668         case TYPE_ACCEPT: {
669             Py_CLEAR(self->allocated_buffer);
670             break;
671         }
672         case TYPE_READ_FROM: {
673             // An initial call to WSARecvFrom will only allocate the buffer.
674             // The result tuple of (message, address) is only
675             // allocated _after_ a message has been received.
676             if(self->read_from.result) {
677                 // We've received a message, free the result tuple.
678                 Py_CLEAR(self->read_from.result);
679             }
680             if(self->read_from.allocated_buffer) {
681                 Py_CLEAR(self->read_from.allocated_buffer);
682             }
683             break;
684         }
685         case TYPE_READ_FROM_INTO: {
686             if (self->read_from_into.result) {
687                 // We've received a message, free the result tuple.
688                 Py_CLEAR(self->read_from_into.result);
689             }
690             if (self->read_from_into.user_buffer.obj) {
691                 PyBuffer_Release(&self->read_from_into.user_buffer);
692             }
693             break;
694         }
695         case TYPE_WRITE:
696         case TYPE_WRITE_TO:
697         case TYPE_READINTO: {
698             if (self->user_buffer.obj) {
699                 PyBuffer_Release(&self->user_buffer);
700             }
701             break;
702         }
703     }
704     self->type = TYPE_NOT_STARTED;
705     return 0;
706 }
707 
708 static void
Overlapped_dealloc(OverlappedObject * self)709 Overlapped_dealloc(OverlappedObject *self)
710 {
711     DWORD bytes;
712     DWORD olderr = GetLastError();
713     BOOL wait = FALSE;
714     BOOL ret;
715 
716     if (!HasOverlappedIoCompleted(&self->overlapped) &&
717         self->type != TYPE_NOT_STARTED)
718     {
719         Py_BEGIN_ALLOW_THREADS
720         if (CancelIoEx(self->handle, &self->overlapped))
721             wait = TRUE;
722 
723         ret = GetOverlappedResult(self->handle, &self->overlapped,
724                                   &bytes, wait);
725         Py_END_ALLOW_THREADS
726 
727         switch (ret ? ERROR_SUCCESS : GetLastError()) {
728             case ERROR_SUCCESS:
729             case ERROR_NOT_FOUND:
730             case ERROR_OPERATION_ABORTED:
731                 break;
732             default:
733                 PyErr_Format(
734                     PyExc_RuntimeError,
735                     "%R still has pending operation at "
736                     "deallocation, the process may crash", self);
737                 PyErr_WriteUnraisable(NULL);
738         }
739     }
740 
741     if (self->overlapped.hEvent != NULL) {
742         CloseHandle(self->overlapped.hEvent);
743     }
744 
745     Overlapped_clear(self);
746     SetLastError(olderr);
747 
748     PyTypeObject *tp = Py_TYPE(self);
749     PyObject_Free(self);
750     Py_DECREF(tp);
751 }
752 
753 
754 /* Convert IPv4 sockaddr to a Python str. */
755 
756 static PyObject *
make_ipv4_addr(const struct sockaddr_in * addr)757 make_ipv4_addr(const struct sockaddr_in *addr)
758 {
759         char buf[INET_ADDRSTRLEN];
760         if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
761                 PyErr_SetFromErrno(PyExc_OSError);
762                 return NULL;
763         }
764         return PyUnicode_FromString(buf);
765 }
766 
767 /* Convert IPv6 sockaddr to a Python str. */
768 
769 static PyObject *
make_ipv6_addr(const struct sockaddr_in6 * addr)770 make_ipv6_addr(const struct sockaddr_in6 *addr)
771 {
772         char buf[INET6_ADDRSTRLEN];
773         if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
774                 PyErr_SetFromErrno(PyExc_OSError);
775                 return NULL;
776         }
777         return PyUnicode_FromString(buf);
778 }
779 
780 static PyObject*
unparse_address(LPSOCKADDR Address,DWORD Length)781 unparse_address(LPSOCKADDR Address, DWORD Length)
782 {
783         /* The function is adopted from mocketmodule.c makesockaddr()*/
784 
785     switch(Address->sa_family) {
786         case AF_INET: {
787             const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
788             PyObject *addrobj = make_ipv4_addr(a);
789             PyObject *ret = NULL;
790             if (addrobj) {
791                 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
792                 Py_DECREF(addrobj);
793             }
794             return ret;
795         }
796         case AF_INET6: {
797             const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
798             PyObject *addrobj = make_ipv6_addr(a);
799             PyObject *ret = NULL;
800             if (addrobj) {
801                 ret = Py_BuildValue("OiII",
802                                     addrobj,
803                                     ntohs(a->sin6_port),
804                                     ntohl(a->sin6_flowinfo),
805                                     a->sin6_scope_id);
806                 Py_DECREF(addrobj);
807             }
808             return ret;
809         }
810         default: {
811             PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
812             return NULL;
813         }
814     }
815 }
816 
817 /*[clinic input]
818 _overlapped.Overlapped.cancel
819 
820 Cancel overlapped operation.
821 [clinic start generated code]*/
822 
823 static PyObject *
_overlapped_Overlapped_cancel_impl(OverlappedObject * self)824 _overlapped_Overlapped_cancel_impl(OverlappedObject *self)
825 /*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
826 {
827     BOOL ret = TRUE;
828 
829     if (self->type == TYPE_NOT_STARTED
830         || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
831         Py_RETURN_NONE;
832 
833     if (!HasOverlappedIoCompleted(&self->overlapped)) {
834         Py_BEGIN_ALLOW_THREADS
835         ret = CancelIoEx(self->handle, &self->overlapped);
836         Py_END_ALLOW_THREADS
837     }
838 
839     /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
840     if (!ret && GetLastError() != ERROR_NOT_FOUND)
841         return SetFromWindowsErr(0);
842     Py_RETURN_NONE;
843 }
844 
845 /*[clinic input]
846 _overlapped.Overlapped.getresult
847 
848     wait: BOOL(c_default='FALSE') = False
849     /
850 
851 Retrieve result of operation.
852 
853 If wait is true then it blocks until the operation is finished.  If wait
854 is false and the operation is still pending then an error is raised.
855 [clinic start generated code]*/
856 
857 static PyObject *
_overlapped_Overlapped_getresult_impl(OverlappedObject * self,BOOL wait)858 _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
859 /*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
860 {
861     DWORD transferred = 0;
862     BOOL ret;
863     DWORD err;
864     PyObject *addr;
865 
866     if (self->type == TYPE_NONE) {
867         PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
868         return NULL;
869     }
870 
871     if (self->type == TYPE_NOT_STARTED) {
872         PyErr_SetString(PyExc_ValueError, "operation failed to start");
873         return NULL;
874     }
875 
876     Py_BEGIN_ALLOW_THREADS
877     ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
878                               wait);
879     Py_END_ALLOW_THREADS
880 
881     self->error = err = ret ? ERROR_SUCCESS : GetLastError();
882     switch (err) {
883         case ERROR_SUCCESS:
884         case ERROR_MORE_DATA:
885             break;
886         case ERROR_BROKEN_PIPE:
887             if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
888                 break;
889             }
890             else if (self->type == TYPE_READ_FROM &&
891                      (self->read_from.result != NULL ||
892                       self->read_from.allocated_buffer != NULL))
893             {
894                 break;
895             }
896             else if (self->type == TYPE_READ_FROM_INTO &&
897                      self->read_from_into.result != NULL)
898             {
899                 break;
900             }
901             /* fall through */
902         default:
903             return SetFromWindowsErr(err);
904     }
905 
906     switch (self->type) {
907         case TYPE_READ:
908             assert(PyBytes_CheckExact(self->allocated_buffer));
909             if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
910                 _PyBytes_Resize(&self->allocated_buffer, transferred))
911                 return NULL;
912 
913             Py_INCREF(self->allocated_buffer);
914             return self->allocated_buffer;
915         case TYPE_READ_FROM:
916             assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
917 
918             if (transferred != PyBytes_GET_SIZE(
919                     self->read_from.allocated_buffer) &&
920                 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
921             {
922                 return NULL;
923             }
924 
925             // unparse the address
926             addr = unparse_address((SOCKADDR*)&self->read_from.address,
927                                    self->read_from.address_length);
928 
929             if (addr == NULL) {
930                 return NULL;
931             }
932 
933             // The result is a two item tuple: (message, address)
934             self->read_from.result = PyTuple_New(2);
935             if (self->read_from.result == NULL) {
936                 Py_CLEAR(addr);
937                 return NULL;
938             }
939 
940             // first item: message
941             Py_INCREF(self->read_from.allocated_buffer);
942             PyTuple_SET_ITEM(self->read_from.result, 0,
943                              self->read_from.allocated_buffer);
944             // second item: address
945             PyTuple_SET_ITEM(self->read_from.result, 1, addr);
946 
947             Py_INCREF(self->read_from.result);
948             return self->read_from.result;
949         case TYPE_READ_FROM_INTO:
950             // unparse the address
951             addr = unparse_address((SOCKADDR*)&self->read_from_into.address,
952                 self->read_from_into.address_length);
953 
954             if (addr == NULL) {
955                 return NULL;
956             }
957 
958             // The result is a two item tuple: (number of bytes read, address)
959             self->read_from_into.result = PyTuple_New(2);
960             if (self->read_from_into.result == NULL) {
961                 Py_CLEAR(addr);
962                 return NULL;
963             }
964 
965             // first item: number of bytes read
966             PyTuple_SET_ITEM(self->read_from_into.result, 0,
967                 PyLong_FromUnsignedLong((unsigned long)transferred));
968             // second item: address
969             PyTuple_SET_ITEM(self->read_from_into.result, 1, addr);
970 
971             Py_INCREF(self->read_from_into.result);
972             return self->read_from_into.result;
973         default:
974             return PyLong_FromUnsignedLong((unsigned long) transferred);
975     }
976 }
977 
978 static PyObject *
do_ReadFile(OverlappedObject * self,HANDLE handle,char * bufstart,DWORD buflen)979 do_ReadFile(OverlappedObject *self, HANDLE handle,
980             char *bufstart, DWORD buflen)
981 {
982     DWORD nread;
983     int ret;
984     DWORD err;
985 
986     Py_BEGIN_ALLOW_THREADS
987     ret = ReadFile(handle, bufstart, buflen, &nread,
988                    &self->overlapped);
989     Py_END_ALLOW_THREADS
990 
991     self->error = err = ret ? ERROR_SUCCESS : GetLastError();
992     switch (err) {
993         case ERROR_BROKEN_PIPE:
994             mark_as_completed(&self->overlapped);
995             return SetFromWindowsErr(err);
996         case ERROR_SUCCESS:
997         case ERROR_MORE_DATA:
998         case ERROR_IO_PENDING:
999             Py_RETURN_NONE;
1000         default:
1001             Overlapped_clear(self);
1002             return SetFromWindowsErr(err);
1003     }
1004 }
1005 
1006 /*[clinic input]
1007 _overlapped.Overlapped.ReadFile
1008 
1009     handle: HANDLE
1010     size: DWORD
1011     /
1012 
1013 Start overlapped read.
1014 [clinic start generated code]*/
1015 
1016 static PyObject *
_overlapped_Overlapped_ReadFile_impl(OverlappedObject * self,HANDLE handle,DWORD size)1017 _overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
1018                                      DWORD size)
1019 /*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
1020 {
1021     PyObject *buf;
1022 
1023     if (self->type != TYPE_NONE) {
1024         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1025         return NULL;
1026     }
1027 
1028 #if SIZEOF_SIZE_T <= SIZEOF_LONG
1029     size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1030 #endif
1031     buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1032     if (buf == NULL)
1033         return NULL;
1034 
1035     self->type = TYPE_READ;
1036     self->handle = handle;
1037     self->allocated_buffer = buf;
1038 
1039     return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
1040 }
1041 
1042 /*[clinic input]
1043 _overlapped.Overlapped.ReadFileInto
1044 
1045     handle: HANDLE
1046     buf as bufobj: Py_buffer
1047     /
1048 
1049 Start overlapped receive.
1050 [clinic start generated code]*/
1051 
1052 static PyObject *
_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj)1053 _overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
1054                                          HANDLE handle, Py_buffer *bufobj)
1055 /*[clinic end generated code: output=8754744506023071 input=4f037ba09939e32d]*/
1056 {
1057     if (self->type != TYPE_NONE) {
1058         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1059         return NULL;
1060     }
1061 
1062 #if SIZEOF_SIZE_T > SIZEOF_LONG
1063     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1064         PyErr_SetString(PyExc_ValueError, "buffer too large");
1065         return NULL;
1066     }
1067 #endif
1068     steal_buffer(&self->user_buffer, bufobj);
1069 
1070     self->type = TYPE_READINTO;
1071     self->handle = handle;
1072 
1073     return do_ReadFile(self, handle, self->user_buffer.buf,
1074                        (DWORD)self->user_buffer.len);
1075 }
1076 
1077 static PyObject *
do_WSARecv(OverlappedObject * self,HANDLE handle,char * bufstart,DWORD buflen,DWORD flags)1078 do_WSARecv(OverlappedObject *self, HANDLE handle,
1079            char *bufstart, DWORD buflen, DWORD flags)
1080 {
1081     DWORD nread;
1082     WSABUF wsabuf;
1083     int ret;
1084     DWORD err;
1085 
1086     wsabuf.buf = bufstart;
1087     wsabuf.len = buflen;
1088 
1089     Py_BEGIN_ALLOW_THREADS
1090     ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1091                   &self->overlapped, NULL);
1092     Py_END_ALLOW_THREADS
1093 
1094     self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1095     switch (err) {
1096         case ERROR_BROKEN_PIPE:
1097             mark_as_completed(&self->overlapped);
1098             return SetFromWindowsErr(err);
1099         case ERROR_SUCCESS:
1100         case ERROR_MORE_DATA:
1101         case ERROR_IO_PENDING:
1102             Py_RETURN_NONE;
1103         default:
1104             Overlapped_clear(self);
1105             return SetFromWindowsErr(err);
1106     }
1107 }
1108 
1109 
1110 /*[clinic input]
1111 _overlapped.Overlapped.WSARecv
1112 
1113     handle: HANDLE
1114     size: DWORD
1115     flags: DWORD = 0
1116     /
1117 
1118 Start overlapped receive.
1119 [clinic start generated code]*/
1120 
1121 static PyObject *
_overlapped_Overlapped_WSARecv_impl(OverlappedObject * self,HANDLE handle,DWORD size,DWORD flags)1122 _overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
1123                                     DWORD size, DWORD flags)
1124 /*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
1125 {
1126     PyObject *buf;
1127 
1128     if (self->type != TYPE_NONE) {
1129         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1130         return NULL;
1131     }
1132 
1133 #if SIZEOF_SIZE_T <= SIZEOF_LONG
1134     size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1135 #endif
1136     buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1137     if (buf == NULL)
1138         return NULL;
1139 
1140     self->type = TYPE_READ;
1141     self->handle = handle;
1142     self->allocated_buffer = buf;
1143 
1144     return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1145 }
1146 
1147 /*[clinic input]
1148 _overlapped.Overlapped.WSARecvInto
1149 
1150     handle: HANDLE
1151     buf as bufobj: Py_buffer
1152     flags: DWORD
1153     /
1154 
1155 Start overlapped receive.
1156 [clinic start generated code]*/
1157 
1158 static PyObject *
_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj,DWORD flags)1159 _overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
1160                                         HANDLE handle, Py_buffer *bufobj,
1161                                         DWORD flags)
1162 /*[clinic end generated code: output=59ae7688786cf86b input=73e7fa00db633edd]*/
1163 {
1164     if (self->type != TYPE_NONE) {
1165         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1166         return NULL;
1167     }
1168 
1169 #if SIZEOF_SIZE_T > SIZEOF_LONG
1170     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1171         PyErr_SetString(PyExc_ValueError, "buffer too large");
1172         return NULL;
1173     }
1174 #endif
1175     steal_buffer(&self->user_buffer, bufobj);
1176 
1177     self->type = TYPE_READINTO;
1178     self->handle = handle;
1179 
1180     return do_WSARecv(self, handle, self->user_buffer.buf,
1181                       (DWORD)self->user_buffer.len, flags);
1182 }
1183 
1184 /*[clinic input]
1185 _overlapped.Overlapped.WriteFile
1186 
1187     handle: HANDLE
1188     buf as bufobj: Py_buffer
1189     /
1190 
1191 Start overlapped write.
1192 [clinic start generated code]*/
1193 
1194 static PyObject *
_overlapped_Overlapped_WriteFile_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj)1195 _overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
1196                                       Py_buffer *bufobj)
1197 /*[clinic end generated code: output=fa5d5880a1bf04b1 input=ac54424c362abfc1]*/
1198 {
1199     DWORD written;
1200     BOOL ret;
1201     DWORD err;
1202 
1203     if (self->type != TYPE_NONE) {
1204         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1205         return NULL;
1206     }
1207 
1208 #if SIZEOF_SIZE_T > SIZEOF_LONG
1209     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1210         PyErr_SetString(PyExc_ValueError, "buffer too large");
1211         return NULL;
1212     }
1213 #endif
1214     steal_buffer(&self->user_buffer, bufobj);
1215 
1216     self->type = TYPE_WRITE;
1217     self->handle = handle;
1218 
1219     Py_BEGIN_ALLOW_THREADS
1220     ret = WriteFile(handle, self->user_buffer.buf,
1221                     (DWORD)self->user_buffer.len,
1222                     &written, &self->overlapped);
1223     Py_END_ALLOW_THREADS
1224 
1225     self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1226     switch (err) {
1227         case ERROR_SUCCESS:
1228         case ERROR_IO_PENDING:
1229             Py_RETURN_NONE;
1230         default:
1231             Overlapped_clear(self);
1232             return SetFromWindowsErr(err);
1233     }
1234 }
1235 
1236 /*[clinic input]
1237 _overlapped.Overlapped.WSASend
1238 
1239     handle: HANDLE
1240     buf as bufobj: Py_buffer
1241     flags: DWORD
1242     /
1243 
1244 Start overlapped send.
1245 [clinic start generated code]*/
1246 
1247 static PyObject *
_overlapped_Overlapped_WSASend_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj,DWORD flags)1248 _overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
1249                                     Py_buffer *bufobj, DWORD flags)
1250 /*[clinic end generated code: output=3baaa6e1f7fe229e input=c4167420ba2f93d8]*/
1251 {
1252     DWORD written;
1253     WSABUF wsabuf;
1254     int ret;
1255     DWORD err;
1256 
1257     if (self->type != TYPE_NONE) {
1258         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1259         return NULL;
1260     }
1261 
1262 #if SIZEOF_SIZE_T > SIZEOF_LONG
1263     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1264         PyErr_SetString(PyExc_ValueError, "buffer too large");
1265         return NULL;
1266     }
1267 #endif
1268     steal_buffer(&self->user_buffer, bufobj);
1269 
1270     self->type = TYPE_WRITE;
1271     self->handle = handle;
1272     wsabuf.len = (DWORD)self->user_buffer.len;
1273     wsabuf.buf = self->user_buffer.buf;
1274 
1275     Py_BEGIN_ALLOW_THREADS
1276     ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1277                   &self->overlapped, NULL);
1278     Py_END_ALLOW_THREADS
1279 
1280     self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1281     switch (err) {
1282         case ERROR_SUCCESS:
1283         case ERROR_IO_PENDING:
1284             Py_RETURN_NONE;
1285         default:
1286             Overlapped_clear(self);
1287             return SetFromWindowsErr(err);
1288     }
1289 }
1290 
1291 /*[clinic input]
1292 _overlapped.Overlapped.AcceptEx
1293 
1294     listen_handle as ListenSocket: HANDLE
1295     accept_handle as AcceptSocket: HANDLE
1296     /
1297 
1298 Start overlapped wait for client to connect.
1299 [clinic start generated code]*/
1300 
1301 static PyObject *
_overlapped_Overlapped_AcceptEx_impl(OverlappedObject * self,HANDLE ListenSocket,HANDLE AcceptSocket)1302 _overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
1303                                      HANDLE ListenSocket,
1304                                      HANDLE AcceptSocket)
1305 /*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
1306 {
1307     DWORD BytesReceived;
1308     DWORD size;
1309     PyObject *buf;
1310     BOOL ret;
1311     DWORD err;
1312 
1313     if (self->type != TYPE_NONE) {
1314         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1315         return NULL;
1316     }
1317 
1318     size = sizeof(struct sockaddr_in6) + 16;
1319     buf = PyBytes_FromStringAndSize(NULL, size*2);
1320     if (!buf)
1321         return NULL;
1322 
1323     self->type = TYPE_ACCEPT;
1324     self->handle = ListenSocket;
1325     self->allocated_buffer = buf;
1326 
1327     Py_BEGIN_ALLOW_THREADS
1328     ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
1329                       PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
1330                       &self->overlapped);
1331     Py_END_ALLOW_THREADS
1332 
1333     self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1334     switch (err) {
1335         case ERROR_SUCCESS:
1336         case ERROR_IO_PENDING:
1337             Py_RETURN_NONE;
1338         default:
1339             Overlapped_clear(self);
1340             return SetFromWindowsErr(err);
1341     }
1342 }
1343 
1344 
1345 static int
parse_address(PyObject * obj,SOCKADDR * Address,int Length)1346 parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1347 {
1348     PyObject *Host_obj;
1349     Py_UNICODE *Host;
1350     unsigned short Port;
1351     unsigned long FlowInfo;
1352     unsigned long ScopeId;
1353 
1354     memset(Address, 0, Length);
1355 
1356     switch (PyTuple_GET_SIZE(obj)) {
1357     case 2: {
1358         if (!PyArg_ParseTuple(obj, "UH", &Host_obj, &Port)) {
1359             return -1;
1360         }
1361 #if USE_UNICODE_WCHAR_CACHE
1362         Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1363 #else /* USE_UNICODE_WCHAR_CACHE */
1364         Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1365 #endif /* USE_UNICODE_WCHAR_CACHE */
1366         if (Host == NULL) {
1367             return -1;
1368         }
1369         Address->sa_family = AF_INET;
1370         if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
1371             SetFromWindowsErr(WSAGetLastError());
1372             Length = -1;
1373         }
1374         else {
1375             ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1376         }
1377 #if !USE_UNICODE_WCHAR_CACHE
1378         PyMem_Free(Host);
1379 #endif /* USE_UNICODE_WCHAR_CACHE */
1380         return Length;
1381     }
1382     case 4: {
1383         if (!PyArg_ParseTuple(obj,
1384                 "UHkk;ConnectEx(): illegal address_as_bytes argument",
1385                 &Host_obj, &Port, &FlowInfo, &ScopeId))
1386         {
1387             return -1;
1388         }
1389 #if USE_UNICODE_WCHAR_CACHE
1390         Host = (wchar_t *)_PyUnicode_AsUnicode(Host_obj);
1391 #else /* USE_UNICODE_WCHAR_CACHE */
1392         Host = PyUnicode_AsWideCharString(Host_obj, NULL);
1393 #endif /* USE_UNICODE_WCHAR_CACHE */
1394         if (Host == NULL) {
1395             return -1;
1396         }
1397         Address->sa_family = AF_INET6;
1398         if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
1399             SetFromWindowsErr(WSAGetLastError());
1400             Length = -1;
1401         }
1402         else {
1403             ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1404             ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1405             ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1406         }
1407 #if !USE_UNICODE_WCHAR_CACHE
1408         PyMem_Free(Host);
1409 #endif /* USE_UNICODE_WCHAR_CACHE */
1410         return Length;
1411     }
1412     default:
1413         PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument");
1414         return -1;
1415     }
1416 }
1417 
1418 /*[clinic input]
1419 _overlapped.Overlapped.ConnectEx
1420 
1421     client_handle as ConnectSocket: HANDLE
1422     address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1423     /
1424 
1425 Start overlapped connect.
1426 
1427 client_handle should be unbound.
1428 [clinic start generated code]*/
1429 
1430 static PyObject *
_overlapped_Overlapped_ConnectEx_impl(OverlappedObject * self,HANDLE ConnectSocket,PyObject * AddressObj)1431 _overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
1432                                       HANDLE ConnectSocket,
1433                                       PyObject *AddressObj)
1434 /*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
1435 {
1436     char AddressBuf[sizeof(struct sockaddr_in6)];
1437     SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1438     int Length;
1439     BOOL ret;
1440     DWORD err;
1441 
1442     if (self->type != TYPE_NONE) {
1443         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1444         return NULL;
1445     }
1446 
1447     Length = sizeof(AddressBuf);
1448     Length = parse_address(AddressObj, Address, Length);
1449     if (Length < 0)
1450         return NULL;
1451 
1452     self->type = TYPE_CONNECT;
1453     self->handle = ConnectSocket;
1454 
1455     Py_BEGIN_ALLOW_THREADS
1456     ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
1457                        NULL, 0, NULL, &self->overlapped);
1458     Py_END_ALLOW_THREADS
1459 
1460     self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1461     switch (err) {
1462         case ERROR_SUCCESS:
1463         case ERROR_IO_PENDING:
1464             Py_RETURN_NONE;
1465         default:
1466             Overlapped_clear(self);
1467             return SetFromWindowsErr(err);
1468     }
1469 }
1470 
1471 /*[clinic input]
1472 _overlapped.Overlapped.DisconnectEx
1473 
1474     handle as Socket: HANDLE
1475     flags: DWORD
1476     /
1477 
1478 [clinic start generated code]*/
1479 
1480 static PyObject *
_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject * self,HANDLE Socket,DWORD flags)1481 _overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
1482                                          HANDLE Socket, DWORD flags)
1483 /*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
1484 {
1485     BOOL ret;
1486     DWORD err;
1487 
1488     if (self->type != TYPE_NONE) {
1489         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1490         return NULL;
1491     }
1492 
1493     self->type = TYPE_DISCONNECT;
1494     self->handle = Socket;
1495 
1496     Py_BEGIN_ALLOW_THREADS
1497     ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
1498     Py_END_ALLOW_THREADS
1499 
1500     self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1501     switch (err) {
1502         case ERROR_SUCCESS:
1503         case ERROR_IO_PENDING:
1504             Py_RETURN_NONE;
1505         default:
1506             Overlapped_clear(self);
1507             return SetFromWindowsErr(err);
1508     }
1509 }
1510 
1511 /*[clinic input]
1512 _overlapped.Overlapped.TransmitFile
1513 
1514     socket as Socket: HANDLE
1515     file as File: HANDLE
1516     offset: DWORD
1517     offset_high: DWORD
1518     count_to_write: DWORD
1519     count_per_send: DWORD
1520     flags: DWORD
1521     /
1522 
1523 Transmit file data over a connected socket.
1524 [clinic start generated code]*/
1525 
1526 static PyObject *
_overlapped_Overlapped_TransmitFile_impl(OverlappedObject * self,HANDLE Socket,HANDLE File,DWORD offset,DWORD offset_high,DWORD count_to_write,DWORD count_per_send,DWORD flags)1527 _overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
1528                                          HANDLE Socket, HANDLE File,
1529                                          DWORD offset, DWORD offset_high,
1530                                          DWORD count_to_write,
1531                                          DWORD count_per_send, DWORD flags)
1532 /*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
1533 {
1534     BOOL ret;
1535     DWORD err;
1536 
1537     if (self->type != TYPE_NONE) {
1538         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1539         return NULL;
1540     }
1541 
1542     self->type = TYPE_TRANSMIT_FILE;
1543     self->handle = Socket;
1544     self->overlapped.Offset = offset;
1545     self->overlapped.OffsetHigh = offset_high;
1546 
1547     Py_BEGIN_ALLOW_THREADS
1548     ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
1549                           count_per_send, &self->overlapped, NULL, flags);
1550     Py_END_ALLOW_THREADS
1551 
1552     self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1553     switch (err) {
1554         case ERROR_SUCCESS:
1555         case ERROR_IO_PENDING:
1556             Py_RETURN_NONE;
1557         default:
1558             Overlapped_clear(self);
1559             return SetFromWindowsErr(err);
1560     }
1561 }
1562 
1563 /*[clinic input]
1564 _overlapped.Overlapped.ConnectNamedPipe
1565 
1566     handle as Pipe: HANDLE
1567     /
1568 
1569 Start overlapped wait for a client to connect.
1570 [clinic start generated code]*/
1571 
1572 static PyObject *
_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject * self,HANDLE Pipe)1573 _overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
1574                                              HANDLE Pipe)
1575 /*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
1576 {
1577     BOOL ret;
1578     DWORD err;
1579 
1580     if (self->type != TYPE_NONE) {
1581         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1582         return NULL;
1583     }
1584 
1585     self->type = TYPE_CONNECT_NAMED_PIPE;
1586     self->handle = Pipe;
1587 
1588     Py_BEGIN_ALLOW_THREADS
1589     ret = ConnectNamedPipe(Pipe, &self->overlapped);
1590     Py_END_ALLOW_THREADS
1591 
1592     self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1593     switch (err) {
1594         case ERROR_PIPE_CONNECTED:
1595             mark_as_completed(&self->overlapped);
1596             Py_RETURN_TRUE;
1597         case ERROR_SUCCESS:
1598         case ERROR_IO_PENDING:
1599             Py_RETURN_FALSE;
1600         default:
1601             Overlapped_clear(self);
1602             return SetFromWindowsErr(err);
1603     }
1604 }
1605 
1606 /*[clinic input]
1607 _overlapped.Overlapped.ConnectPipe
1608 
1609     addr as Address: Py_UNICODE
1610     /
1611 
1612 Connect to the pipe for asynchronous I/O (overlapped).
1613 [clinic start generated code]*/
1614 
1615 static PyObject *
_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject * self,const Py_UNICODE * Address)1616 _overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
1617                                         const Py_UNICODE *Address)
1618 /*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
1619 {
1620     HANDLE PipeHandle;
1621 
1622     Py_BEGIN_ALLOW_THREADS
1623     PipeHandle = CreateFileW(Address,
1624                              GENERIC_READ | GENERIC_WRITE,
1625                              0, NULL, OPEN_EXISTING,
1626                              FILE_FLAG_OVERLAPPED, NULL);
1627     Py_END_ALLOW_THREADS
1628 
1629     if (PipeHandle == INVALID_HANDLE_VALUE)
1630         return SetFromWindowsErr(0);
1631     return Py_BuildValue(F_HANDLE, PipeHandle);
1632 }
1633 
1634 static PyObject*
Overlapped_getaddress(OverlappedObject * self)1635 Overlapped_getaddress(OverlappedObject *self)
1636 {
1637     return PyLong_FromVoidPtr(&self->overlapped);
1638 }
1639 
1640 static PyObject*
Overlapped_getpending(OverlappedObject * self)1641 Overlapped_getpending(OverlappedObject *self)
1642 {
1643     return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1644                            self->type != TYPE_NOT_STARTED);
1645 }
1646 
1647 static int
Overlapped_traverse(OverlappedObject * self,visitproc visit,void * arg)1648 Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1649 {
1650     switch (self->type) {
1651     case TYPE_READ:
1652     case TYPE_ACCEPT:
1653         Py_VISIT(self->allocated_buffer);
1654         break;
1655     case TYPE_WRITE:
1656     case TYPE_WRITE_TO:
1657     case TYPE_READINTO:
1658         if (self->user_buffer.obj) {
1659             Py_VISIT(&self->user_buffer.obj);
1660         }
1661         break;
1662     case TYPE_READ_FROM:
1663         Py_VISIT(self->read_from.result);
1664         Py_VISIT(self->read_from.allocated_buffer);
1665         break;
1666     case TYPE_READ_FROM_INTO:
1667         Py_VISIT(self->read_from_into.result);
1668         if (self->read_from_into.user_buffer.obj) {
1669             Py_VISIT(&self->read_from_into.user_buffer.obj);
1670         }
1671         break;
1672     }
1673     return 0;
1674 }
1675 
1676 // UDP functions
1677 
1678 /*
1679  * Note: WSAConnect does not support Overlapped I/O so this function should
1680  * _only_ be used for connectionless sockets (UDP).
1681  */
1682 
1683 /*[clinic input]
1684 _overlapped.WSAConnect
1685 
1686     client_handle as ConnectSocket: HANDLE
1687     address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1688     /
1689 
1690 Bind a remote address to a connectionless (UDP) socket.
1691 [clinic start generated code]*/
1692 
1693 static PyObject *
_overlapped_WSAConnect_impl(PyObject * module,HANDLE ConnectSocket,PyObject * AddressObj)1694 _overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
1695                             PyObject *AddressObj)
1696 /*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/
1697 {
1698     char AddressBuf[sizeof(struct sockaddr_in6)];
1699     SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1700     int Length;
1701     int err;
1702 
1703     Length = sizeof(AddressBuf);
1704     Length = parse_address(AddressObj, Address, Length);
1705     if (Length < 0) {
1706         return NULL;
1707     }
1708 
1709     Py_BEGIN_ALLOW_THREADS
1710     // WSAConnect does not support overlapped I/O so this call will
1711     // successfully complete immediately.
1712     err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
1713                         NULL, NULL, NULL, NULL);
1714     Py_END_ALLOW_THREADS
1715 
1716     if (err == 0) {
1717         Py_RETURN_NONE;
1718     }
1719     else {
1720         return SetFromWindowsErr(WSAGetLastError());
1721     }
1722 }
1723 
1724 /*[clinic input]
1725 _overlapped.Overlapped.WSASendTo
1726 
1727     handle: HANDLE
1728     buf as bufobj: Py_buffer
1729     flags: DWORD
1730     address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1731     /
1732 
1733 Start overlapped sendto over a connectionless (UDP) socket.
1734 [clinic start generated code]*/
1735 
1736 static PyObject *
_overlapped_Overlapped_WSASendTo_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj,DWORD flags,PyObject * AddressObj)1737 _overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
1738                                       Py_buffer *bufobj, DWORD flags,
1739                                       PyObject *AddressObj)
1740 /*[clinic end generated code: output=3cdedc4cfaeb70cd input=31f44cd4ab92fc33]*/
1741 {
1742     char AddressBuf[sizeof(struct sockaddr_in6)];
1743     SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1744     int AddressLength;
1745     DWORD written;
1746     WSABUF wsabuf;
1747     int ret;
1748     DWORD err;
1749 
1750     // Parse the "to" address
1751     AddressLength = sizeof(AddressBuf);
1752     AddressLength = parse_address(AddressObj, Address, AddressLength);
1753     if (AddressLength < 0) {
1754         return NULL;
1755     }
1756 
1757     if (self->type != TYPE_NONE) {
1758         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1759         return NULL;
1760     }
1761 
1762 #if SIZEOF_SIZE_T > SIZEOF_LONG
1763     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1764         PyErr_SetString(PyExc_ValueError, "buffer too large");
1765         return NULL;
1766     }
1767 #endif
1768     steal_buffer(&self->user_buffer, bufobj);
1769 
1770     self->type = TYPE_WRITE_TO;
1771     self->handle = handle;
1772     wsabuf.len = (DWORD)self->user_buffer.len;
1773     wsabuf.buf = self->user_buffer.buf;
1774 
1775     Py_BEGIN_ALLOW_THREADS
1776     ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1777                     Address, AddressLength, &self->overlapped, NULL);
1778     Py_END_ALLOW_THREADS
1779 
1780     self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1781                                                ERROR_SUCCESS);
1782 
1783     switch(err) {
1784         case ERROR_SUCCESS:
1785         case ERROR_IO_PENDING:
1786             Py_RETURN_NONE;
1787         default:
1788             self->type = TYPE_NOT_STARTED;
1789             return SetFromWindowsErr(err);
1790     }
1791 }
1792 
1793 
1794 
1795 PyDoc_STRVAR(
1796     Overlapped_WSARecvFrom_doc,
1797     "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1798     "Start overlapped receive");
1799 
1800 /*[clinic input]
1801 _overlapped.Overlapped.WSARecvFrom
1802 
1803     handle: HANDLE
1804     size: DWORD
1805     flags: DWORD = 0
1806     /
1807 
1808 Start overlapped receive.
1809 [clinic start generated code]*/
1810 
1811 static PyObject *
_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject * self,HANDLE handle,DWORD size,DWORD flags)1812 _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
1813                                         HANDLE handle, DWORD size,
1814                                         DWORD flags)
1815 /*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
1816 {
1817     PyObject *buf;
1818     DWORD nread;
1819     WSABUF wsabuf;
1820     int ret;
1821     DWORD err;
1822 
1823     if (self->type != TYPE_NONE) {
1824         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1825         return NULL;
1826     }
1827 
1828 #if SIZEOF_SIZE_T <= SIZEOF_LONG
1829     size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1830 #endif
1831     buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1832     if (buf == NULL) {
1833         return NULL;
1834     }
1835 
1836     wsabuf.buf = PyBytes_AS_STRING(buf);
1837     wsabuf.len = size;
1838 
1839     self->type = TYPE_READ_FROM;
1840     self->handle = handle;
1841     self->read_from.allocated_buffer = buf;
1842     memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1843     self->read_from.address_length = sizeof(self->read_from.address);
1844 
1845     Py_BEGIN_ALLOW_THREADS
1846     ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1847                       (SOCKADDR*)&self->read_from.address,
1848                       &self->read_from.address_length,
1849                       &self->overlapped, NULL);
1850     Py_END_ALLOW_THREADS
1851 
1852     self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1853     switch (err) {
1854     case ERROR_BROKEN_PIPE:
1855         mark_as_completed(&self->overlapped);
1856         return SetFromWindowsErr(err);
1857     case ERROR_SUCCESS:
1858     case ERROR_MORE_DATA:
1859     case ERROR_IO_PENDING:
1860         Py_RETURN_NONE;
1861     default:
1862         self->type = TYPE_NOT_STARTED;
1863         return SetFromWindowsErr(err);
1864     }
1865 }
1866 
1867 
1868 /*[clinic input]
1869 _overlapped.Overlapped.WSARecvFromInto
1870 
1871     handle: HANDLE
1872     buf as bufobj: Py_buffer
1873     size: DWORD
1874     flags: DWORD = 0
1875     /
1876 
1877 Start overlapped receive.
1878 [clinic start generated code]*/
1879 
1880 static PyObject *
_overlapped_Overlapped_WSARecvFromInto_impl(OverlappedObject * self,HANDLE handle,Py_buffer * bufobj,DWORD size,DWORD flags)1881 _overlapped_Overlapped_WSARecvFromInto_impl(OverlappedObject *self,
1882                                             HANDLE handle, Py_buffer *bufobj,
1883                                             DWORD size, DWORD flags)
1884 /*[clinic end generated code: output=30c7ea171a691757 input=4be4b08d03531e76]*/
1885 {
1886     DWORD nread;
1887     WSABUF wsabuf;
1888     int ret;
1889     DWORD err;
1890 
1891     if (self->type != TYPE_NONE) {
1892         PyErr_SetString(PyExc_ValueError, "operation already attempted");
1893         return NULL;
1894     }
1895 
1896 #if SIZEOF_SIZE_T > SIZEOF_LONG
1897     if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
1898         PyErr_SetString(PyExc_ValueError, "buffer too large");
1899         return NULL;
1900     }
1901 #endif
1902 
1903     wsabuf.buf = bufobj->buf;
1904     wsabuf.len = size;
1905 
1906     self->type = TYPE_READ_FROM_INTO;
1907     self->handle = handle;
1908     steal_buffer(&self->read_from_into.user_buffer, bufobj);
1909     memset(&self->read_from_into.address, 0, sizeof(self->read_from_into.address));
1910     self->read_from_into.address_length = sizeof(self->read_from_into.address);
1911 
1912     Py_BEGIN_ALLOW_THREADS
1913     ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1914                       (SOCKADDR*)&self->read_from_into.address,
1915                       &self->read_from_into.address_length,
1916                       &self->overlapped, NULL);
1917     Py_END_ALLOW_THREADS
1918 
1919     self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1920     switch (err) {
1921     case ERROR_BROKEN_PIPE:
1922         mark_as_completed(&self->overlapped);
1923         return SetFromWindowsErr(err);
1924     case ERROR_SUCCESS:
1925     case ERROR_MORE_DATA:
1926     case ERROR_IO_PENDING:
1927         Py_RETURN_NONE;
1928     default:
1929         self->type = TYPE_NOT_STARTED;
1930         return SetFromWindowsErr(err);
1931     }
1932 }
1933 
1934 
1935 #include "clinic/overlapped.c.h"
1936 
1937 static PyMethodDef Overlapped_methods[] = {
1938     _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
1939     _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
1940     _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
1941     _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
1942     _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
1943     _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
1944     _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1945     _OVERLAPPED_OVERLAPPED_WSARECVFROMINTO_METHODDEF
1946     _OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
1947     _OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
1948     _OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
1949     _OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
1950     _OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
1951     _OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
1952     _OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
1953     _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1954     _OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
1955     {NULL}
1956 };
1957 
1958 static PyMemberDef Overlapped_members[] = {
1959     {"error", T_ULONG,
1960      offsetof(OverlappedObject, error),
1961      READONLY, "Error from last operation"},
1962     {"event", T_HANDLE,
1963      offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1964      READONLY, "Overlapped event handle"},
1965     {NULL}
1966 };
1967 
1968 static PyGetSetDef Overlapped_getsets[] = {
1969     {"address", (getter)Overlapped_getaddress, NULL,
1970      "Address of overlapped structure"},
1971     {"pending", (getter)Overlapped_getpending, NULL,
1972      "Whether the operation is pending"},
1973     {NULL},
1974 };
1975 
1976 static PyType_Slot overlapped_type_slots[] = {
1977     {Py_tp_dealloc, Overlapped_dealloc},
1978     {Py_tp_doc, (char *)_overlapped_Overlapped__doc__},
1979     {Py_tp_traverse, Overlapped_traverse},
1980     {Py_tp_methods, Overlapped_methods},
1981     {Py_tp_members, Overlapped_members},
1982     {Py_tp_getset, Overlapped_getsets},
1983     {Py_tp_new, _overlapped_Overlapped},
1984     {0,0}
1985 };
1986 
1987 static PyType_Spec overlapped_type_spec = {
1988     .name = "_overlapped.Overlapped",
1989     .basicsize = sizeof(OverlappedObject),
1990     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
1991     .slots = overlapped_type_slots
1992 };
1993 
1994 static PyMethodDef overlapped_functions[] = {
1995     _OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
1996     _OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
1997     _OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
1998     _OVERLAPPED_FORMATMESSAGE_METHODDEF
1999     _OVERLAPPED_BINDLOCAL_METHODDEF
2000     _OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
2001     _OVERLAPPED_UNREGISTERWAIT_METHODDEF
2002     _OVERLAPPED_UNREGISTERWAITEX_METHODDEF
2003     _OVERLAPPED_CREATEEVENT_METHODDEF
2004     _OVERLAPPED_SETEVENT_METHODDEF
2005     _OVERLAPPED_RESETEVENT_METHODDEF
2006     _OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
2007     _OVERLAPPED_WSACONNECT_METHODDEF
2008     {NULL}
2009 };
2010 
2011 static int
overlapped_traverse(PyObject * module,visitproc visit,void * arg)2012 overlapped_traverse(PyObject *module, visitproc visit, void *arg)
2013 {
2014     OverlappedState *state = overlapped_get_state(module);
2015     Py_VISIT(state->overlapped_type);
2016     return 0;
2017 }
2018 
2019 static int
overlapped_clear(PyObject * module)2020 overlapped_clear(PyObject *module)
2021 {
2022     OverlappedState *state = overlapped_get_state(module);
2023     Py_CLEAR(state->overlapped_type);
2024     return 0;
2025 }
2026 
2027 static void
overlapped_free(void * module)2028 overlapped_free(void *module)
2029 {
2030     overlapped_clear((PyObject *)module);
2031 }
2032 
2033 #define WINAPI_CONSTANT(fmt, con) \
2034     do { \
2035         PyObject *value = Py_BuildValue(fmt, con); \
2036         if (value == NULL) { \
2037             return -1; \
2038         } \
2039         if (PyModule_AddObject(module, #con, value) < 0 ) { \
2040             Py_DECREF(value); \
2041             return -1; \
2042         } \
2043     } while (0)
2044 
2045 static int
overlapped_exec(PyObject * module)2046 overlapped_exec(PyObject *module)
2047 {
2048     /* Ensure WSAStartup() called before initializing function pointers */
2049     PyObject *socket_module = PyImport_ImportModule("_socket");
2050     if (!socket_module) {
2051         return -1;
2052     }
2053 
2054     Py_DECREF(socket_module);
2055 
2056     if (initialize_function_pointers() < 0) {
2057         return -1;
2058     }
2059 
2060     OverlappedState *st = overlapped_get_state(module);
2061     st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(
2062         module, &overlapped_type_spec, NULL);
2063     if (st->overlapped_type == NULL) {
2064         return -1;
2065     }
2066 
2067     if (PyModule_AddType(module, st->overlapped_type) < 0) {
2068         return -1;
2069     }
2070 
2071     WINAPI_CONSTANT(F_DWORD,  ERROR_IO_PENDING);
2072     WINAPI_CONSTANT(F_DWORD,  ERROR_NETNAME_DELETED);
2073     WINAPI_CONSTANT(F_DWORD,  ERROR_OPERATION_ABORTED);
2074     WINAPI_CONSTANT(F_DWORD,  ERROR_SEM_TIMEOUT);
2075     WINAPI_CONSTANT(F_DWORD,  ERROR_PIPE_BUSY);
2076     WINAPI_CONSTANT(F_DWORD,  INFINITE);
2077     WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
2078     WINAPI_CONSTANT(F_HANDLE, NULL);
2079     WINAPI_CONSTANT(F_DWORD,  SO_UPDATE_ACCEPT_CONTEXT);
2080     WINAPI_CONSTANT(F_DWORD,  SO_UPDATE_CONNECT_CONTEXT);
2081     WINAPI_CONSTANT(F_DWORD,  TF_REUSE_SOCKET);
2082 
2083     return 0;
2084 }
2085 
2086 static PyModuleDef_Slot overlapped_slots[] = {
2087     {Py_mod_exec, overlapped_exec},
2088     {0, NULL}
2089 };
2090 
2091 static struct PyModuleDef overlapped_module = {
2092     PyModuleDef_HEAD_INIT,
2093     .m_name = "_overlapped",
2094     .m_size = sizeof(OverlappedState),
2095     .m_methods = overlapped_functions,
2096     .m_slots = overlapped_slots,
2097     .m_traverse = overlapped_traverse,
2098     .m_clear = overlapped_clear,
2099     .m_free = overlapped_free
2100 };
2101 
2102 PyMODINIT_FUNC
PyInit__overlapped(void)2103 PyInit__overlapped(void)
2104 {
2105     return PyModuleDef_Init(&overlapped_module);
2106 }
2107