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