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