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