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