blob: 9c4e2da9dfbd35b046ae99f2f4808c07bc4a43eb [file] [log] [blame]
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001/*
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"
Victor Stinner4a21e572020-04-15 02:35:41 +020011#include "structmember.h" // PyMemberDef
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070012
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
Victor Stinnerccdbe802016-04-01 21:37:41 +020026/* Compatibility with Python 3.3 */
27#if PY_VERSION_HEX < 0x03040000
28# define PyMem_RawMalloc PyMem_Malloc
29# define PyMem_RawFree PyMem_Free
30#endif
31
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070032#define F_HANDLE F_POINTER
33#define F_ULONG_PTR F_POINTER
34#define F_DWORD "k"
35#define F_BOOL "i"
36#define F_UINT "I"
37
38#define T_HANDLE T_POINTER
39
Zackery Spytz9650fe02020-07-10 11:43:37 -060040/*[python input]
41class OVERLAPPED_converter(CConverter):
42 type = 'OVERLAPPED *'
43 format_unit = '"F_POINTER"'
44
45class HANDLE_converter(CConverter):
46 type = 'HANDLE'
47 format_unit = '"F_HANDLE"'
48
49class ULONG_PTR_converter(CConverter):
50 type = 'ULONG_PTR'
51 format_unit = '"F_ULONG_PTR"'
52
53class DWORD_converter(CConverter):
54 type = 'DWORD'
55 format_unit = 'k'
56
57class BOOL_converter(CConverter):
58 type = 'BOOL'
59 format_unit = 'i'
60[python start generated code]*/
61/*[python end generated code: output=da39a3ee5e6b4b0d input=83bb8c2c2514f2a8]*/
62
63/*[clinic input]
64module _overlapped
65class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType"
66[clinic start generated code]*/
67/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92e5a799db35b96c]*/
68
69
Antoine Pitrou525f40d2017-10-19 21:46:40 +020070enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
71 TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030072 TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
73 TYPE_WRITE_TO};
Guido van Rossum27b7c7e2013-10-17 13:40:50 -070074
75typedef struct {
76 PyObject_HEAD
77 OVERLAPPED overlapped;
78 /* For convenience, we store the file handle too */
79 HANDLE handle;
80 /* Error returned by last method call */
81 DWORD error;
82 /* Type of operation */
83 DWORD type;
84 union {
Antoine Pitrou525f40d2017-10-19 21:46:40 +020085 /* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
86 PyObject *allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030087 /* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */
Antoine Pitrou525f40d2017-10-19 21:46:40 +020088 Py_buffer user_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +030089
90 /* Data used for reading from a connectionless socket:
91 TYPE_READ_FROM */
92 struct {
93 // A (buffer, (host, port)) tuple
94 PyObject *result;
95 // The actual read buffer
96 PyObject *allocated_buffer;
97 struct sockaddr_in6 address;
98 int address_length;
99 } read_from;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700100 };
101} OverlappedObject;
102
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700103/*
104 * Map Windows error codes to subclasses of OSError
105 */
106
107static PyObject *
108SetFromWindowsErr(DWORD err)
109{
110 PyObject *exception_type;
111
112 if (err == 0)
113 err = GetLastError();
114 switch (err) {
115 case ERROR_CONNECTION_REFUSED:
116 exception_type = PyExc_ConnectionRefusedError;
117 break;
118 case ERROR_CONNECTION_ABORTED:
119 exception_type = PyExc_ConnectionAbortedError;
120 break;
121 default:
122 exception_type = PyExc_OSError;
123 }
124 return PyErr_SetExcFromWindowsErr(exception_type, err);
125}
126
127/*
128 * Some functions should be loaded at runtime
129 */
130
131static LPFN_ACCEPTEX Py_AcceptEx = NULL;
132static LPFN_CONNECTEX Py_ConnectEx = NULL;
133static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300134static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700135static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
136
137#define GET_WSA_POINTER(s, x) \
138 (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
139 &Guid##x, sizeof(Guid##x), &Py_##x, \
140 sizeof(Py_##x), &dwBytes, NULL, NULL))
141
142static int
143initialize_function_pointers(void)
144{
145 GUID GuidAcceptEx = WSAID_ACCEPTEX;
146 GUID GuidConnectEx = WSAID_CONNECTEX;
147 GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300148 GUID GuidTransmitFile = WSAID_TRANSMITFILE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700149 HINSTANCE hKernel32;
150 SOCKET s;
151 DWORD dwBytes;
152
153 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
154 if (s == INVALID_SOCKET) {
155 SetFromWindowsErr(WSAGetLastError());
156 return -1;
157 }
158
159 if (!GET_WSA_POINTER(s, AcceptEx) ||
160 !GET_WSA_POINTER(s, ConnectEx) ||
Andrew Svetlova19fb3c2018-02-25 19:32:14 +0300161 !GET_WSA_POINTER(s, DisconnectEx) ||
162 !GET_WSA_POINTER(s, TransmitFile))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700163 {
164 closesocket(s);
165 SetFromWindowsErr(WSAGetLastError());
166 return -1;
167 }
168
169 closesocket(s);
170
171 /* On WinXP we will have Py_CancelIoEx == NULL */
Tony Roberts4860f012019-02-02 18:16:42 +0100172 Py_BEGIN_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700173 hKernel32 = GetModuleHandle("KERNEL32");
174 *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
Tony Roberts4860f012019-02-02 18:16:42 +0100175 Py_END_ALLOW_THREADS
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700176 return 0;
177}
178
179/*
180 * Completion port stuff
181 */
182
Zackery Spytz9650fe02020-07-10 11:43:37 -0600183/*[clinic input]
184_overlapped.CreateIoCompletionPort
185
186 handle as FileHandle: HANDLE
187 port as ExistingCompletionPort: HANDLE
188 key as CompletionKey: ULONG_PTR
189 concurrency as NumberOfConcurrentThreads: DWORD
190 /
191
192Create a completion port or register a handle with a port.
193[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700194
195static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600196_overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle,
197 HANDLE ExistingCompletionPort,
198 ULONG_PTR CompletionKey,
199 DWORD NumberOfConcurrentThreads)
200/*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700201{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700202 HANDLE ret;
203
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700204 Py_BEGIN_ALLOW_THREADS
205 ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
206 CompletionKey, NumberOfConcurrentThreads);
207 Py_END_ALLOW_THREADS
208
209 if (ret == NULL)
210 return SetFromWindowsErr(0);
211 return Py_BuildValue(F_HANDLE, ret);
212}
213
Zackery Spytz9650fe02020-07-10 11:43:37 -0600214/*[clinic input]
215_overlapped.GetQueuedCompletionStatus
216
217 port as CompletionPort: HANDLE
218 msecs as Milliseconds: DWORD
219 /
220
221Get a message from completion port.
222
223Wait for up to msecs milliseconds.
224[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700225
226static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600227_overlapped_GetQueuedCompletionStatus_impl(PyObject *module,
228 HANDLE CompletionPort,
229 DWORD Milliseconds)
230/*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700231{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700232 DWORD NumberOfBytes = 0;
233 ULONG_PTR CompletionKey = 0;
234 OVERLAPPED *Overlapped = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700235 DWORD err;
236 BOOL ret;
237
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700238 Py_BEGIN_ALLOW_THREADS
239 ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
240 &CompletionKey, &Overlapped, Milliseconds);
241 Py_END_ALLOW_THREADS
242
243 err = ret ? ERROR_SUCCESS : GetLastError();
244 if (Overlapped == NULL) {
245 if (err == WAIT_TIMEOUT)
246 Py_RETURN_NONE;
247 else
248 return SetFromWindowsErr(err);
249 }
250 return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
251 err, NumberOfBytes, CompletionKey, Overlapped);
252}
253
Zackery Spytz9650fe02020-07-10 11:43:37 -0600254/*[clinic input]
255_overlapped.PostQueuedCompletionStatus
256
257 port as CompletionPort: HANDLE
258 bytes as NumberOfBytes: DWORD
259 key as CompletionKey: ULONG_PTR
260 address as Overlapped: OVERLAPPED
261 /
262
263Post a message to completion port.
264[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700265
266static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600267_overlapped_PostQueuedCompletionStatus_impl(PyObject *module,
268 HANDLE CompletionPort,
269 DWORD NumberOfBytes,
270 ULONG_PTR CompletionKey,
271 OVERLAPPED *Overlapped)
272/*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700273{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700274 BOOL ret;
275
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700276 Py_BEGIN_ALLOW_THREADS
277 ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
278 CompletionKey, Overlapped);
279 Py_END_ALLOW_THREADS
280
281 if (!ret)
282 return SetFromWindowsErr(0);
283 Py_RETURN_NONE;
284}
285
286/*
Guido van Rossum90fb9142013-10-30 14:44:05 -0700287 * Wait for a handle
288 */
289
290struct PostCallbackData {
291 HANDLE CompletionPort;
292 LPOVERLAPPED Overlapped;
293};
294
295static VOID CALLBACK
296PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
297{
298 struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
299
300 PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
301 0, p->Overlapped);
302 /* ignore possible error! */
Victor Stinner6150f312016-03-16 23:25:02 +0100303 PyMem_RawFree(p);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700304}
305
Zackery Spytz9650fe02020-07-10 11:43:37 -0600306/*[clinic input]
307_overlapped.RegisterWaitWithQueue
308
309 Object: HANDLE
310 CompletionPort: HANDLE
311 Overlapped: OVERLAPPED
312 Timeout as Milliseconds: DWORD
313 /
314
315Register wait for Object; when complete CompletionPort is notified.
316[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700317
318static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600319_overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
320 HANDLE CompletionPort,
321 OVERLAPPED *Overlapped,
322 DWORD Milliseconds)
323/*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700324{
325 HANDLE NewWaitObject;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600326 struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata;
Guido van Rossum90fb9142013-10-30 14:44:05 -0700327
Victor Stinner6150f312016-03-16 23:25:02 +0100328 /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
329 PostToQueueCallback() will call PyMem_Free() from a new C thread
330 which doesn't hold the GIL. */
331 pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
Guido van Rossum90fb9142013-10-30 14:44:05 -0700332 if (pdata == NULL)
333 return SetFromWindowsErr(0);
334
335 *pdata = data;
336
337 if (!RegisterWaitForSingleObject(
338 &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
339 pdata, Milliseconds,
340 WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
341 {
Victor Stinner6150f312016-03-16 23:25:02 +0100342 PyMem_RawFree(pdata);
Guido van Rossum90fb9142013-10-30 14:44:05 -0700343 return SetFromWindowsErr(0);
344 }
345
346 return Py_BuildValue(F_HANDLE, NewWaitObject);
347}
348
Zackery Spytz9650fe02020-07-10 11:43:37 -0600349/*[clinic input]
350_overlapped.UnregisterWait
351
352 WaitHandle: HANDLE
353 /
354
355Unregister wait handle.
356[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700357
358static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600359_overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
360/*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700361{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700362 BOOL ret;
363
Guido van Rossum90fb9142013-10-30 14:44:05 -0700364 Py_BEGIN_ALLOW_THREADS
365 ret = UnregisterWait(WaitHandle);
366 Py_END_ALLOW_THREADS
367
368 if (!ret)
369 return SetFromWindowsErr(0);
370 Py_RETURN_NONE;
371}
372
Zackery Spytz9650fe02020-07-10 11:43:37 -0600373/*[clinic input]
374_overlapped.UnregisterWaitEx
375
376 WaitHandle: HANDLE
377 Event: HANDLE
378 /
379
380Unregister wait handle.
381[clinic start generated code]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100382
383static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600384_overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
385 HANDLE Event)
386/*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100387{
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100388 BOOL ret;
389
Victor Stinnerd0a28de2015-01-21 23:39:51 +0100390 Py_BEGIN_ALLOW_THREADS
391 ret = UnregisterWaitEx(WaitHandle, Event);
392 Py_END_ALLOW_THREADS
393
394 if (!ret)
395 return SetFromWindowsErr(0);
396 Py_RETURN_NONE;
397}
398
Guido van Rossum90fb9142013-10-30 14:44:05 -0700399/*
400 * Event functions -- currently only used by tests
401 */
402
Zackery Spytz9650fe02020-07-10 11:43:37 -0600403/*[clinic input]
404_overlapped.CreateEvent
405
406 EventAttributes: object
407 ManualReset: BOOL
408 InitialState: BOOL
409 Name: Py_UNICODE(accept={str, NoneType})
410 /
411
412Create an event.
413
414EventAttributes must be None.
415[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700416
417static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600418_overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
419 BOOL ManualReset, BOOL InitialState,
420 const Py_UNICODE *Name)
421/*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700422{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700423 HANDLE Event;
424
Guido van Rossum90fb9142013-10-30 14:44:05 -0700425 if (EventAttributes != Py_None) {
426 PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
427 return NULL;
428 }
429
430 Py_BEGIN_ALLOW_THREADS
431 Event = CreateEventW(NULL, ManualReset, InitialState, Name);
432 Py_END_ALLOW_THREADS
433
434 if (Event == NULL)
435 return SetFromWindowsErr(0);
436 return Py_BuildValue(F_HANDLE, Event);
437}
438
Zackery Spytz9650fe02020-07-10 11:43:37 -0600439/*[clinic input]
440_overlapped.SetEvent
441
442 Handle: HANDLE
443 /
444
445Set event.
446[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700447
448static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600449_overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
450/*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700451{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700452 BOOL ret;
453
Guido van Rossum90fb9142013-10-30 14:44:05 -0700454 Py_BEGIN_ALLOW_THREADS
455 ret = SetEvent(Handle);
456 Py_END_ALLOW_THREADS
457
458 if (!ret)
459 return SetFromWindowsErr(0);
460 Py_RETURN_NONE;
461}
462
Zackery Spytz9650fe02020-07-10 11:43:37 -0600463/*[clinic input]
464_overlapped.ResetEvent
465
466 Handle: HANDLE
467 /
468
469Reset event.
470[clinic start generated code]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700471
472static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600473_overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
474/*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
Guido van Rossum90fb9142013-10-30 14:44:05 -0700475{
Guido van Rossum90fb9142013-10-30 14:44:05 -0700476 BOOL ret;
477
Guido van Rossum90fb9142013-10-30 14:44:05 -0700478 Py_BEGIN_ALLOW_THREADS
479 ret = ResetEvent(Handle);
480 Py_END_ALLOW_THREADS
481
482 if (!ret)
483 return SetFromWindowsErr(0);
484 Py_RETURN_NONE;
485}
486
487/*
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700488 * Bind socket handle to local port without doing slow getaddrinfo()
489 */
490
Zackery Spytz9650fe02020-07-10 11:43:37 -0600491/*[clinic input]
492_overlapped.BindLocal
493
494 handle as Socket: HANDLE
495 family as Family: int
496 /
497
498Bind a socket handle to an arbitrary local port.
499
500family should be AF_INET or AF_INET6.
501[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700502
503static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600504_overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
505/*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700506{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700507 BOOL ret;
508
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700509 if (Family == AF_INET) {
510 struct sockaddr_in addr;
511 memset(&addr, 0, sizeof(addr));
512 addr.sin_family = AF_INET;
513 addr.sin_port = 0;
514 addr.sin_addr.S_un.S_addr = INADDR_ANY;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600515 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
516 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700517 } else if (Family == AF_INET6) {
518 struct sockaddr_in6 addr;
519 memset(&addr, 0, sizeof(addr));
520 addr.sin6_family = AF_INET6;
521 addr.sin6_port = 0;
522 addr.sin6_addr = in6addr_any;
Zackery Spytz9650fe02020-07-10 11:43:37 -0600523 ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
524 != SOCKET_ERROR;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700525 } else {
526 PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
527 return NULL;
528 }
529
530 if (!ret)
531 return SetFromWindowsErr(WSAGetLastError());
532 Py_RETURN_NONE;
533}
534
535/*
536 * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
537 */
538
Zackery Spytz9650fe02020-07-10 11:43:37 -0600539/*[clinic input]
540_overlapped.FormatMessage
541
542 error_code as code: DWORD
543 /
544
545Return error message for an error code.
546[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700547
548static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600549_overlapped_FormatMessage_impl(PyObject *module, DWORD code)
550/*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700551{
Zackery Spytz9650fe02020-07-10 11:43:37 -0600552 DWORD n;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700553 WCHAR *lpMsgBuf;
554 PyObject *res;
555
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700556 n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
Zackery Spytza6563652019-09-09 03:20:39 -0600557 FORMAT_MESSAGE_FROM_SYSTEM |
558 FORMAT_MESSAGE_IGNORE_INSERTS,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700559 NULL,
560 code,
561 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
562 (LPWSTR) &lpMsgBuf,
563 0,
564 NULL);
565 if (n) {
566 while (iswspace(lpMsgBuf[n-1]))
567 --n;
568 lpMsgBuf[n] = L'\0';
569 res = Py_BuildValue("u", lpMsgBuf);
570 } else {
571 res = PyUnicode_FromFormat("unknown error code %u", code);
572 }
573 LocalFree(lpMsgBuf);
574 return res;
575}
576
577
578/*
579 * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
580 */
581
582static void
583mark_as_completed(OVERLAPPED *ov)
584{
585 ov->Internal = 0;
586 if (ov->hEvent != NULL)
587 SetEvent(ov->hEvent);
588}
589
590/*
591 * A Python object wrapping an OVERLAPPED structure and other useful data
592 * for overlapped I/O
593 */
594
Zackery Spytz9650fe02020-07-10 11:43:37 -0600595/*[clinic input]
596@classmethod
597_overlapped.Overlapped.__new__
598
599 event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
600
601OVERLAPPED structure wrapper.
602[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700603
604static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600605_overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
606/*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700607{
608 OverlappedObject *self;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700609
610 if (event == INVALID_HANDLE_VALUE) {
611 event = CreateEvent(NULL, TRUE, FALSE, NULL);
612 if (event == NULL)
613 return SetFromWindowsErr(0);
614 }
615
616 self = PyObject_New(OverlappedObject, type);
617 if (self == NULL) {
618 if (event != NULL)
619 CloseHandle(event);
620 return NULL;
621 }
622
623 self->handle = NULL;
624 self->error = 0;
625 self->type = TYPE_NONE;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200626 self->allocated_buffer = NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700627 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200628 memset(&self->user_buffer, 0, sizeof(Py_buffer));
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700629 if (event)
630 self->overlapped.hEvent = event;
631 return (PyObject *)self;
632}
633
Victor Stinner54850852019-01-11 14:35:14 +0100634
635/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
636 buffers while overlapped are still running, to prevent a crash. */
637static int
638Overlapped_clear(OverlappedObject *self)
639{
640 switch (self->type) {
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300641 case TYPE_READ:
642 case TYPE_ACCEPT: {
643 Py_CLEAR(self->allocated_buffer);
644 break;
Victor Stinner54850852019-01-11 14:35:14 +0100645 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300646 case TYPE_READ_FROM: {
647 // An initial call to WSARecvFrom will only allocate the buffer.
648 // The result tuple of (message, address) is only
649 // allocated _after_ a message has been received.
650 if(self->read_from.result) {
651 // We've received a message, free the result tuple.
652 Py_CLEAR(self->read_from.result);
653 }
654 if(self->read_from.allocated_buffer) {
655 Py_CLEAR(self->read_from.allocated_buffer);
656 }
657 break;
658 }
659 case TYPE_WRITE:
660 case TYPE_WRITE_TO:
661 case TYPE_READINTO: {
662 if (self->user_buffer.obj) {
663 PyBuffer_Release(&self->user_buffer);
664 }
665 break;
666 }
Victor Stinner54850852019-01-11 14:35:14 +0100667 }
668 self->type = TYPE_NOT_STARTED;
669 return 0;
670}
671
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700672static void
673Overlapped_dealloc(OverlappedObject *self)
674{
675 DWORD bytes;
676 DWORD olderr = GetLastError();
677 BOOL wait = FALSE;
678 BOOL ret;
679
680 if (!HasOverlappedIoCompleted(&self->overlapped) &&
681 self->type != TYPE_NOT_STARTED)
682 {
683 if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
684 wait = TRUE;
685
686 Py_BEGIN_ALLOW_THREADS
687 ret = GetOverlappedResult(self->handle, &self->overlapped,
688 &bytes, wait);
689 Py_END_ALLOW_THREADS
690
691 switch (ret ? ERROR_SUCCESS : GetLastError()) {
692 case ERROR_SUCCESS:
693 case ERROR_NOT_FOUND:
694 case ERROR_OPERATION_ABORTED:
695 break;
696 default:
697 PyErr_Format(
698 PyExc_RuntimeError,
699 "%R still has pending operation at "
700 "deallocation, the process may crash", self);
701 PyErr_WriteUnraisable(NULL);
702 }
703 }
704
Victor Stinner54850852019-01-11 14:35:14 +0100705 if (self->overlapped.hEvent != NULL) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700706 CloseHandle(self->overlapped.hEvent);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700707 }
Victor Stinner54850852019-01-11 14:35:14 +0100708
709 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700710 PyObject_Del(self);
711 SetLastError(olderr);
712}
713
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300714
715/* Convert IPv4 sockaddr to a Python str. */
716
717static PyObject *
718make_ipv4_addr(const struct sockaddr_in *addr)
719{
720 char buf[INET_ADDRSTRLEN];
721 if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
722 PyErr_SetFromErrno(PyExc_OSError);
723 return NULL;
724 }
725 return PyUnicode_FromString(buf);
726}
727
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300728/* Convert IPv6 sockaddr to a Python str. */
729
730static PyObject *
731make_ipv6_addr(const struct sockaddr_in6 *addr)
732{
733 char buf[INET6_ADDRSTRLEN];
734 if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
735 PyErr_SetFromErrno(PyExc_OSError);
736 return NULL;
737 }
738 return PyUnicode_FromString(buf);
739}
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300740
741static PyObject*
742unparse_address(LPSOCKADDR Address, DWORD Length)
743{
744 /* The function is adopted from mocketmodule.c makesockaddr()*/
745
746 switch(Address->sa_family) {
747 case AF_INET: {
748 const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
749 PyObject *addrobj = make_ipv4_addr(a);
750 PyObject *ret = NULL;
751 if (addrobj) {
752 ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
753 Py_DECREF(addrobj);
754 }
755 return ret;
756 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300757 case AF_INET6: {
758 const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
759 PyObject *addrobj = make_ipv6_addr(a);
760 PyObject *ret = NULL;
761 if (addrobj) {
762 ret = Py_BuildValue("OiII",
763 addrobj,
764 ntohs(a->sin6_port),
765 ntohl(a->sin6_flowinfo),
766 a->sin6_scope_id);
767 Py_DECREF(addrobj);
768 }
769 return ret;
770 }
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300771 default: {
Kjell Braden442634c2020-05-18 08:21:30 +0200772 PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
773 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300774 }
775 }
776}
777
Zackery Spytz9650fe02020-07-10 11:43:37 -0600778/*[clinic input]
779_overlapped.Overlapped.cancel
780
781Cancel overlapped operation.
782[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700783
784static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600785_overlapped_Overlapped_cancel_impl(OverlappedObject *self)
786/*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700787{
788 BOOL ret = TRUE;
789
790 if (self->type == TYPE_NOT_STARTED
791 || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
792 Py_RETURN_NONE;
793
794 if (!HasOverlappedIoCompleted(&self->overlapped)) {
795 Py_BEGIN_ALLOW_THREADS
796 if (Py_CancelIoEx)
797 ret = Py_CancelIoEx(self->handle, &self->overlapped);
798 else
799 ret = CancelIo(self->handle);
800 Py_END_ALLOW_THREADS
801 }
802
803 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
804 if (!ret && GetLastError() != ERROR_NOT_FOUND)
805 return SetFromWindowsErr(0);
806 Py_RETURN_NONE;
807}
808
Zackery Spytz9650fe02020-07-10 11:43:37 -0600809/*[clinic input]
810_overlapped.Overlapped.getresult
811
812 wait: BOOL(c_default='FALSE') = False
813 /
814
815Retrieve result of operation.
816
817If wait is true then it blocks until the operation is finished. If wait
818is false and the operation is still pending then an error is raised.
819[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700820
821static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600822_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
823/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700824{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700825 DWORD transferred = 0;
826 BOOL ret;
827 DWORD err;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300828 PyObject *addr;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700829
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700830 if (self->type == TYPE_NONE) {
831 PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
832 return NULL;
833 }
834
835 if (self->type == TYPE_NOT_STARTED) {
836 PyErr_SetString(PyExc_ValueError, "operation failed to start");
837 return NULL;
838 }
839
840 Py_BEGIN_ALLOW_THREADS
841 ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
842 wait);
843 Py_END_ALLOW_THREADS
844
845 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
846 switch (err) {
847 case ERROR_SUCCESS:
848 case ERROR_MORE_DATA:
849 break;
850 case ERROR_BROKEN_PIPE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300851 if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700852 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300853 }
854 else if (self->type == TYPE_READ_FROM &&
855 (self->read_from.result != NULL ||
856 self->read_from.allocated_buffer != NULL))
857 {
858 break;
859 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700860 /* fall through */
861 default:
862 return SetFromWindowsErr(err);
863 }
864
865 switch (self->type) {
866 case TYPE_READ:
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200867 assert(PyBytes_CheckExact(self->allocated_buffer));
868 if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
869 _PyBytes_Resize(&self->allocated_buffer, transferred))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700870 return NULL;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300871
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200872 Py_INCREF(self->allocated_buffer);
873 return self->allocated_buffer;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +0300874 case TYPE_READ_FROM:
875 assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
876
877 if (transferred != PyBytes_GET_SIZE(
878 self->read_from.allocated_buffer) &&
879 _PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
880 {
881 return NULL;
882 }
883
884 // unparse the address
885 addr = unparse_address((SOCKADDR*)&self->read_from.address,
886 self->read_from.address_length);
887
888 if (addr == NULL) {
889 return NULL;
890 }
891
892 // The result is a two item tuple: (message, address)
893 self->read_from.result = PyTuple_New(2);
894 if (self->read_from.result == NULL) {
895 Py_CLEAR(addr);
896 return NULL;
897 }
898
899 // first item: message
900 Py_INCREF(self->read_from.allocated_buffer);
901 PyTuple_SET_ITEM(self->read_from.result, 0,
902 self->read_from.allocated_buffer);
903 // second item: address
904 PyTuple_SET_ITEM(self->read_from.result, 1, addr);
905
906 Py_INCREF(self->read_from.result);
907 return self->read_from.result;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700908 default:
909 return PyLong_FromUnsignedLong((unsigned long) transferred);
910 }
911}
912
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200913static PyObject *
914do_ReadFile(OverlappedObject *self, HANDLE handle,
915 char *bufstart, DWORD buflen)
916{
917 DWORD nread;
918 int ret;
919 DWORD err;
920
921 Py_BEGIN_ALLOW_THREADS
922 ret = ReadFile(handle, bufstart, buflen, &nread,
923 &self->overlapped);
924 Py_END_ALLOW_THREADS
925
926 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
927 switch (err) {
928 case ERROR_BROKEN_PIPE:
929 mark_as_completed(&self->overlapped);
930 return SetFromWindowsErr(err);
931 case ERROR_SUCCESS:
932 case ERROR_MORE_DATA:
933 case ERROR_IO_PENDING:
934 Py_RETURN_NONE;
935 default:
Victor Stinner54850852019-01-11 14:35:14 +0100936 Overlapped_clear(self);
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200937 return SetFromWindowsErr(err);
938 }
939}
940
Zackery Spytz9650fe02020-07-10 11:43:37 -0600941/*[clinic input]
942_overlapped.Overlapped.ReadFile
943
944 handle: HANDLE
945 size: DWORD
946 /
947
948Start overlapped read.
949[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700950
951static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600952_overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
953 DWORD size)
954/*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700955{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700956 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700957
Guido van Rossum27b7c7e2013-10-17 13:40:50 -0700958 if (self->type != TYPE_NONE) {
959 PyErr_SetString(PyExc_ValueError, "operation already attempted");
960 return NULL;
961 }
962
963#if SIZEOF_SIZE_T <= SIZEOF_LONG
964 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
965#endif
966 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
967 if (buf == NULL)
968 return NULL;
969
970 self->type = TYPE_READ;
971 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200972 self->allocated_buffer = buf;
973
974 return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
975}
976
Zackery Spytz9650fe02020-07-10 11:43:37 -0600977/*[clinic input]
978_overlapped.Overlapped.ReadFileInto
979
980 handle: HANDLE
981 buf as bufobj: object
982 /
983
984Start overlapped receive.
985[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200986
987static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -0600988_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
989 HANDLE handle, PyObject *bufobj)
990/*[clinic end generated code: output=1e9e712e742e5b2a input=16f6cc268d1d0387]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200991{
Antoine Pitrou525f40d2017-10-19 21:46:40 +0200992 if (self->type != TYPE_NONE) {
993 PyErr_SetString(PyExc_ValueError, "operation already attempted");
994 return NULL;
995 }
996
997 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
998 return NULL;
999
1000#if SIZEOF_SIZE_T > SIZEOF_LONG
1001 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1002 PyBuffer_Release(&self->user_buffer);
1003 PyErr_SetString(PyExc_ValueError, "buffer too large");
1004 return NULL;
1005 }
1006#endif
1007
1008 self->type = TYPE_READINTO;
1009 self->handle = handle;
1010
1011 return do_ReadFile(self, handle, self->user_buffer.buf,
1012 (DWORD)self->user_buffer.len);
1013}
1014
1015static PyObject *
1016do_WSARecv(OverlappedObject *self, HANDLE handle,
1017 char *bufstart, DWORD buflen, DWORD flags)
1018{
1019 DWORD nread;
1020 WSABUF wsabuf;
1021 int ret;
1022 DWORD err;
Serhiy Storchakabdf42982017-10-26 16:59:40 +03001023
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001024 wsabuf.buf = bufstart;
1025 wsabuf.len = buflen;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001026
1027 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001028 ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1029 &self->overlapped, NULL);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001030 Py_END_ALLOW_THREADS
1031
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001032 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001033 switch (err) {
1034 case ERROR_BROKEN_PIPE:
1035 mark_as_completed(&self->overlapped);
Victor Stinner41063d22015-01-26 22:30:49 +01001036 return SetFromWindowsErr(err);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001037 case ERROR_SUCCESS:
1038 case ERROR_MORE_DATA:
1039 case ERROR_IO_PENDING:
1040 Py_RETURN_NONE;
1041 default:
Victor Stinner54850852019-01-11 14:35:14 +01001042 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001043 return SetFromWindowsErr(err);
1044 }
1045}
1046
Zackery Spytz9650fe02020-07-10 11:43:37 -06001047/*[clinic input]
1048_overlapped.Overlapped.WSARecv
1049
1050 handle: HANDLE
1051 size: DWORD
1052 flags: DWORD = 0
1053 /
1054
1055Start overlapped receive.
1056[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001057
1058static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001059_overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
1060 DWORD size, DWORD flags)
1061/*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001062{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001063 PyObject *buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001064
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001065 if (self->type != TYPE_NONE) {
1066 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1067 return NULL;
1068 }
1069
1070#if SIZEOF_SIZE_T <= SIZEOF_LONG
1071 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1072#endif
1073 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1074 if (buf == NULL)
1075 return NULL;
1076
1077 self->type = TYPE_READ;
1078 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001079 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001080
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001081 return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
1082}
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001083
Zackery Spytz9650fe02020-07-10 11:43:37 -06001084/*[clinic input]
1085_overlapped.Overlapped.WSARecvInto
1086
1087 handle: HANDLE
1088 buf as bufobj: object
1089 flags: DWORD
1090 /
1091
1092Start overlapped receive.
1093[clinic start generated code]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001094
1095static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001096_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
1097 HANDLE handle, PyObject *bufobj,
1098 DWORD flags)
1099/*[clinic end generated code: output=9a438abc436fe87c input=4f87c38fc381d525]*/
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001100{
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001101 if (self->type != TYPE_NONE) {
1102 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1103 return NULL;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001104 }
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001105
1106 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
1107 return NULL;
1108
1109#if SIZEOF_SIZE_T > SIZEOF_LONG
1110 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1111 PyBuffer_Release(&self->user_buffer);
1112 PyErr_SetString(PyExc_ValueError, "buffer too large");
1113 return NULL;
1114 }
1115#endif
1116
1117 self->type = TYPE_READINTO;
1118 self->handle = handle;
1119
1120 return do_WSARecv(self, handle, self->user_buffer.buf,
1121 (DWORD)self->user_buffer.len, flags);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001122}
1123
Zackery Spytz9650fe02020-07-10 11:43:37 -06001124/*[clinic input]
1125_overlapped.Overlapped.WriteFile
1126
1127 handle: HANDLE
1128 buf as bufobj: object
1129 /
1130
1131Start overlapped write.
1132[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001133
1134static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001135_overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
1136 PyObject *bufobj)
1137/*[clinic end generated code: output=c376230b6120d877 input=b8d9a7608d8a1e72]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001138{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001139 DWORD written;
1140 BOOL ret;
1141 DWORD err;
1142
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001143 if (self->type != TYPE_NONE) {
1144 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1145 return NULL;
1146 }
1147
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001148 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001149 return NULL;
1150
1151#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001152 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1153 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001154 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001155 return NULL;
1156 }
1157#endif
1158
1159 self->type = TYPE_WRITE;
1160 self->handle = handle;
1161
1162 Py_BEGIN_ALLOW_THREADS
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001163 ret = WriteFile(handle, self->user_buffer.buf,
1164 (DWORD)self->user_buffer.len,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001165 &written, &self->overlapped);
1166 Py_END_ALLOW_THREADS
1167
1168 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1169 switch (err) {
1170 case ERROR_SUCCESS:
1171 case ERROR_IO_PENDING:
1172 Py_RETURN_NONE;
1173 default:
Victor Stinner54850852019-01-11 14:35:14 +01001174 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001175 return SetFromWindowsErr(err);
1176 }
1177}
1178
Zackery Spytz9650fe02020-07-10 11:43:37 -06001179/*[clinic input]
1180_overlapped.Overlapped.WSASend
1181
1182 handle: HANDLE
1183 buf as bufobj: object
1184 flags: DWORD
1185 /
1186
1187Start overlapped send.
1188[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001189
1190static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001191_overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
1192 PyObject *bufobj, DWORD flags)
1193/*[clinic end generated code: output=316031c7467040cc input=932e7cba6d18f708]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001194{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001195 DWORD written;
1196 WSABUF wsabuf;
1197 int ret;
1198 DWORD err;
1199
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001200 if (self->type != TYPE_NONE) {
1201 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1202 return NULL;
1203 }
1204
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001205 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001206 return NULL;
1207
1208#if SIZEOF_SIZE_T > SIZEOF_LONG
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001209 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1210 PyBuffer_Release(&self->user_buffer);
Oren Milmand83c23b2017-08-15 19:04:18 +03001211 PyErr_SetString(PyExc_ValueError, "buffer too large");
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001212 return NULL;
1213 }
1214#endif
1215
1216 self->type = TYPE_WRITE;
1217 self->handle = handle;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001218 wsabuf.len = (DWORD)self->user_buffer.len;
1219 wsabuf.buf = self->user_buffer.buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001220
1221 Py_BEGIN_ALLOW_THREADS
1222 ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
1223 &self->overlapped, NULL);
1224 Py_END_ALLOW_THREADS
1225
1226 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1227 switch (err) {
1228 case ERROR_SUCCESS:
1229 case ERROR_IO_PENDING:
1230 Py_RETURN_NONE;
1231 default:
Victor Stinner54850852019-01-11 14:35:14 +01001232 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001233 return SetFromWindowsErr(err);
1234 }
1235}
1236
Zackery Spytz9650fe02020-07-10 11:43:37 -06001237/*[clinic input]
1238_overlapped.Overlapped.AcceptEx
1239
1240 listen_handle as ListenSocket: HANDLE
1241 accept_handle as AcceptSocket: HANDLE
1242 /
1243
1244Start overlapped wait for client to connect.
1245[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001246
1247static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001248_overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
1249 HANDLE ListenSocket,
1250 HANDLE AcceptSocket)
1251/*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001252{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001253 DWORD BytesReceived;
1254 DWORD size;
1255 PyObject *buf;
1256 BOOL ret;
1257 DWORD err;
1258
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001259 if (self->type != TYPE_NONE) {
1260 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1261 return NULL;
1262 }
1263
1264 size = sizeof(struct sockaddr_in6) + 16;
1265 buf = PyBytes_FromStringAndSize(NULL, size*2);
1266 if (!buf)
1267 return NULL;
1268
1269 self->type = TYPE_ACCEPT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001270 self->handle = ListenSocket;
Antoine Pitrou525f40d2017-10-19 21:46:40 +02001271 self->allocated_buffer = buf;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001272
1273 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001274 ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
1275 PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
1276 &self->overlapped);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001277 Py_END_ALLOW_THREADS
1278
1279 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1280 switch (err) {
1281 case ERROR_SUCCESS:
1282 case ERROR_IO_PENDING:
1283 Py_RETURN_NONE;
1284 default:
Victor Stinner54850852019-01-11 14:35:14 +01001285 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001286 return SetFromWindowsErr(err);
1287 }
1288}
1289
1290
1291static int
1292parse_address(PyObject *obj, SOCKADDR *Address, int Length)
1293{
Steve Dowercc16be82016-09-08 10:35:16 -07001294 Py_UNICODE *Host;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001295 unsigned short Port;
1296 unsigned long FlowInfo;
1297 unsigned long ScopeId;
1298
1299 memset(Address, 0, Length);
1300
Steve Dowercc16be82016-09-08 10:35:16 -07001301 if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001302 {
1303 Address->sa_family = AF_INET;
Steve Dowercc16be82016-09-08 10:35:16 -07001304 if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001305 SetFromWindowsErr(WSAGetLastError());
1306 return -1;
1307 }
1308 ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
1309 return Length;
1310 }
Oren Milman1d1d3e92017-08-20 18:35:36 +03001311 else if (PyArg_ParseTuple(obj,
1312 "uHkk;ConnectEx(): illegal address_as_bytes "
1313 "argument", &Host, &Port, &FlowInfo, &ScopeId))
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001314 {
1315 PyErr_Clear();
1316 Address->sa_family = AF_INET6;
Steve Dowercc16be82016-09-08 10:35:16 -07001317 if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001318 SetFromWindowsErr(WSAGetLastError());
1319 return -1;
1320 }
1321 ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1322 ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1323 ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1324 return Length;
1325 }
1326
1327 return -1;
1328}
1329
Zackery Spytz9650fe02020-07-10 11:43:37 -06001330/*[clinic input]
1331_overlapped.Overlapped.ConnectEx
1332
1333 client_handle as ConnectSocket: HANDLE
1334 address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
1335 /
1336
1337Start overlapped connect.
1338
1339client_handle should be unbound.
1340[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001341
1342static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001343_overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
1344 HANDLE ConnectSocket,
1345 PyObject *AddressObj)
1346/*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001347{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001348 char AddressBuf[sizeof(struct sockaddr_in6)];
1349 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1350 int Length;
1351 BOOL ret;
1352 DWORD err;
1353
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001354 if (self->type != TYPE_NONE) {
1355 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1356 return NULL;
1357 }
1358
1359 Length = sizeof(AddressBuf);
1360 Length = parse_address(AddressObj, Address, Length);
1361 if (Length < 0)
1362 return NULL;
1363
1364 self->type = TYPE_CONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001365 self->handle = ConnectSocket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001366
1367 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001368 ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001369 NULL, 0, NULL, &self->overlapped);
1370 Py_END_ALLOW_THREADS
1371
1372 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1373 switch (err) {
1374 case ERROR_SUCCESS:
1375 case ERROR_IO_PENDING:
1376 Py_RETURN_NONE;
1377 default:
Victor Stinner54850852019-01-11 14:35:14 +01001378 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001379 return SetFromWindowsErr(err);
1380 }
1381}
1382
Zackery Spytz9650fe02020-07-10 11:43:37 -06001383/*[clinic input]
1384_overlapped.Overlapped.DisconnectEx
1385
1386 handle as Socket: HANDLE
1387 flags: DWORD
1388 /
1389
1390[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001391
1392static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001393_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
1394 HANDLE Socket, DWORD flags)
1395/*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001396{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001397 BOOL ret;
1398 DWORD err;
1399
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001400 if (self->type != TYPE_NONE) {
1401 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1402 return NULL;
1403 }
1404
1405 self->type = TYPE_DISCONNECT;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001406 self->handle = Socket;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001407
1408 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001409 ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001410 Py_END_ALLOW_THREADS
1411
1412 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1413 switch (err) {
1414 case ERROR_SUCCESS:
1415 case ERROR_IO_PENDING:
1416 Py_RETURN_NONE;
1417 default:
Victor Stinner54850852019-01-11 14:35:14 +01001418 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001419 return SetFromWindowsErr(err);
1420 }
1421}
1422
Zackery Spytz9650fe02020-07-10 11:43:37 -06001423/*[clinic input]
1424_overlapped.Overlapped.TransmitFile
1425
1426 socket as Socket: HANDLE
1427 file as File: HANDLE
1428 offset: DWORD
1429 offset_high: DWORD
1430 count_to_write: DWORD
1431 count_per_send: DWORD
1432 flags: DWORD
1433 /
1434
1435Transmit file data over a connected socket.
1436[clinic start generated code]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001437
1438static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001439_overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
1440 HANDLE Socket, HANDLE File,
1441 DWORD offset, DWORD offset_high,
1442 DWORD count_to_write,
1443 DWORD count_per_send, DWORD flags)
1444/*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001445{
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001446 BOOL ret;
1447 DWORD err;
1448
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001449 if (self->type != TYPE_NONE) {
1450 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1451 return NULL;
1452 }
1453
1454 self->type = TYPE_TRANSMIT_FILE;
Zackery Spytz9650fe02020-07-10 11:43:37 -06001455 self->handle = Socket;
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001456 self->overlapped.Offset = offset;
1457 self->overlapped.OffsetHigh = offset_high;
1458
1459 Py_BEGIN_ALLOW_THREADS
Zackery Spytz9650fe02020-07-10 11:43:37 -06001460 ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
1461 count_per_send, &self->overlapped, NULL, flags);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001462 Py_END_ALLOW_THREADS
1463
1464 self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1465 switch (err) {
1466 case ERROR_SUCCESS:
1467 case ERROR_IO_PENDING:
1468 Py_RETURN_NONE;
1469 default:
Victor Stinner54850852019-01-11 14:35:14 +01001470 Overlapped_clear(self);
Andrew Svetlova19fb3c2018-02-25 19:32:14 +03001471 return SetFromWindowsErr(err);
1472 }
1473}
1474
Zackery Spytz9650fe02020-07-10 11:43:37 -06001475/*[clinic input]
1476_overlapped.Overlapped.ConnectNamedPipe
1477
1478 handle as Pipe: HANDLE
1479 /
1480
1481Start overlapped wait for a client to connect.
1482[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001483
1484static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001485_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
1486 HANDLE Pipe)
1487/*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001488{
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001489 BOOL ret;
1490 DWORD err;
1491
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001492 if (self->type != TYPE_NONE) {
1493 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1494 return NULL;
1495 }
1496
1497 self->type = TYPE_CONNECT_NAMED_PIPE;
1498 self->handle = Pipe;
1499
1500 Py_BEGIN_ALLOW_THREADS
1501 ret = ConnectNamedPipe(Pipe, &self->overlapped);
1502 Py_END_ALLOW_THREADS
1503
1504 self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1505 switch (err) {
1506 case ERROR_PIPE_CONNECTED:
1507 mark_as_completed(&self->overlapped);
Victor Stinner2b77c542015-01-22 23:50:03 +01001508 Py_RETURN_TRUE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001509 case ERROR_SUCCESS:
1510 case ERROR_IO_PENDING:
Victor Stinner2b77c542015-01-22 23:50:03 +01001511 Py_RETURN_FALSE;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001512 default:
Victor Stinner54850852019-01-11 14:35:14 +01001513 Overlapped_clear(self);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001514 return SetFromWindowsErr(err);
1515 }
1516}
1517
Zackery Spytz9650fe02020-07-10 11:43:37 -06001518/*[clinic input]
1519_overlapped.Overlapped.ConnectPipe
1520
1521 addr as Address: Py_UNICODE
1522 /
1523
1524Connect to the pipe for asynchronous I/O (overlapped).
1525[clinic start generated code]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001526
1527static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001528_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
1529 const Py_UNICODE *Address)
1530/*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001531{
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001532 HANDLE PipeHandle;
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001533
Victor Stinner498b1f62015-01-26 22:43:39 +01001534 Py_BEGIN_ALLOW_THREADS
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001535 PipeHandle = CreateFileW(Address,
1536 GENERIC_READ | GENERIC_WRITE,
1537 0, NULL, OPEN_EXISTING,
1538 FILE_FLAG_OVERLAPPED, NULL);
Victor Stinner498b1f62015-01-26 22:43:39 +01001539 Py_END_ALLOW_THREADS
1540
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001541 if (PipeHandle == INVALID_HANDLE_VALUE)
1542 return SetFromWindowsErr(0);
1543 return Py_BuildValue(F_HANDLE, PipeHandle);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001544}
1545
1546static PyObject*
1547Overlapped_getaddress(OverlappedObject *self)
1548{
1549 return PyLong_FromVoidPtr(&self->overlapped);
1550}
1551
1552static PyObject*
1553Overlapped_getpending(OverlappedObject *self)
1554{
1555 return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1556 self->type != TYPE_NOT_STARTED);
1557}
1558
Victor Stinner54850852019-01-11 14:35:14 +01001559static int
1560Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
1561{
1562 switch (self->type) {
1563 case TYPE_READ:
1564 case TYPE_ACCEPT:
1565 Py_VISIT(self->allocated_buffer);
1566 break;
1567 case TYPE_WRITE:
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001568 case TYPE_WRITE_TO:
Victor Stinner54850852019-01-11 14:35:14 +01001569 case TYPE_READINTO:
1570 if (self->user_buffer.obj) {
1571 Py_VISIT(&self->user_buffer.obj);
1572 }
1573 break;
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001574 case TYPE_READ_FROM:
Hai Shi47a23fc2020-06-07 20:05:36 +08001575 Py_VISIT(self->read_from.result);
1576 Py_VISIT(self->read_from.allocated_buffer);
Victor Stinner54850852019-01-11 14:35:14 +01001577 }
1578 return 0;
1579}
1580
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001581// UDP functions
1582
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001583/*
1584 * Note: WSAConnect does not support Overlapped I/O so this function should
1585 * _only_ be used for connectionless sockets (UDP).
1586 */
Zackery Spytz9650fe02020-07-10 11:43:37 -06001587
1588/*[clinic input]
1589_overlapped.WSAConnect
1590
1591 client_handle as ConnectSocket: HANDLE
1592 address_as_bytes as AddressObj: object
1593 /
1594
1595Bind a remote address to a connectionless (UDP) socket.
1596[clinic start generated code]*/
1597
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001598static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001599_overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
1600 PyObject *AddressObj)
1601/*[clinic end generated code: output=ea0b4391e94dad63 input=169f8075e9ae7fa4]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001602{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001603 char AddressBuf[sizeof(struct sockaddr_in6)];
1604 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1605 int Length;
1606 int err;
1607
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001608 Length = sizeof(AddressBuf);
1609 Length = parse_address(AddressObj, Address, Length);
1610 if (Length < 0) {
1611 return NULL;
1612 }
1613
1614 Py_BEGIN_ALLOW_THREADS
1615 // WSAConnect does not support overlapped I/O so this call will
1616 // successfully complete immediately.
Zackery Spytz9650fe02020-07-10 11:43:37 -06001617 err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001618 NULL, NULL, NULL, NULL);
1619 Py_END_ALLOW_THREADS
1620
1621 if (err == 0) {
1622 Py_RETURN_NONE;
1623 }
1624 else {
1625 return SetFromWindowsErr(WSAGetLastError());
1626 }
1627}
1628
Zackery Spytz9650fe02020-07-10 11:43:37 -06001629/*[clinic input]
1630_overlapped.Overlapped.WSASendTo
1631
1632 handle: HANDLE
1633 buf as bufobj: object
1634 flags: DWORD
1635 address_as_bytes as AddressObj: object
1636 /
1637
1638Start overlapped sendto over a connectionless (UDP) socket.
1639[clinic start generated code]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001640
1641static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001642_overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
1643 PyObject *bufobj, DWORD flags,
1644 PyObject *AddressObj)
1645/*[clinic end generated code: output=fe0ff55eb60d65e1 input=f709e6ecebd9bc18]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001646{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001647 char AddressBuf[sizeof(struct sockaddr_in6)];
1648 SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1649 int AddressLength;
1650 DWORD written;
1651 WSABUF wsabuf;
1652 int ret;
1653 DWORD err;
1654
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001655 // Parse the "to" address
1656 AddressLength = sizeof(AddressBuf);
1657 AddressLength = parse_address(AddressObj, Address, AddressLength);
1658 if (AddressLength < 0) {
1659 return NULL;
1660 }
1661
1662 if (self->type != TYPE_NONE) {
1663 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1664 return NULL;
1665 }
1666
1667 if (!PyArg_Parse(bufobj, "y*", &self->user_buffer)) {
1668 return NULL;
1669 }
1670
1671#if SIZEOF_SIZE_T > SIZEOF_LONG
1672 if (self->user_buffer.len > (Py_ssize_t)ULONG_MAX) {
1673 PyBuffer_Release(&self->user_buffer);
1674 PyErr_SetString(PyExc_ValueError, "buffer too large");
1675 return NULL;
1676 }
1677#endif
1678
1679 self->type = TYPE_WRITE_TO;
1680 self->handle = handle;
1681 wsabuf.len = (DWORD)self->user_buffer.len;
1682 wsabuf.buf = self->user_buffer.buf;
1683
1684 Py_BEGIN_ALLOW_THREADS
1685 ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
1686 Address, AddressLength, &self->overlapped, NULL);
1687 Py_END_ALLOW_THREADS
1688
1689 self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
1690 ERROR_SUCCESS);
1691
1692 switch(err) {
1693 case ERROR_SUCCESS:
1694 case ERROR_IO_PENDING:
1695 Py_RETURN_NONE;
1696 default:
1697 self->type = TYPE_NOT_STARTED;
1698 return SetFromWindowsErr(err);
1699 }
1700}
1701
1702
1703
1704PyDoc_STRVAR(
1705 Overlapped_WSARecvFrom_doc,
1706 "RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
1707 "Start overlapped receive");
1708
Zackery Spytz9650fe02020-07-10 11:43:37 -06001709/*[clinic input]
1710_overlapped.Overlapped.WSARecvFrom
1711
1712 handle: HANDLE
1713 size: DWORD
1714 flags: DWORD = 0
1715 /
1716
1717Start overlapped receive.
1718[clinic start generated code]*/
1719
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001720static PyObject *
Zackery Spytz9650fe02020-07-10 11:43:37 -06001721_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
1722 HANDLE handle, DWORD size,
1723 DWORD flags)
1724/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001725{
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001726 DWORD nread;
1727 PyObject *buf;
1728 WSABUF wsabuf;
1729 int ret;
1730 DWORD err;
1731
Andrew Svetlovbafd4b52019-05-28 12:52:15 +03001732 if (self->type != TYPE_NONE) {
1733 PyErr_SetString(PyExc_ValueError, "operation already attempted");
1734 return NULL;
1735 }
1736
1737#if SIZEOF_SIZE_T <= SIZEOF_LONG
1738 size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
1739#endif
1740 buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
1741 if (buf == NULL) {
1742 return NULL;
1743 }
1744
1745 wsabuf.len = size;
1746 wsabuf.buf = PyBytes_AS_STRING(buf);
1747
1748 self->type = TYPE_READ_FROM;
1749 self->handle = handle;
1750 self->read_from.allocated_buffer = buf;
1751 memset(&self->read_from.address, 0, sizeof(self->read_from.address));
1752 self->read_from.address_length = sizeof(self->read_from.address);
1753
1754 Py_BEGIN_ALLOW_THREADS
1755 ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
1756 (SOCKADDR*)&self->read_from.address,
1757 &self->read_from.address_length,
1758 &self->overlapped, NULL);
1759 Py_END_ALLOW_THREADS
1760
1761 self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
1762
1763 switch(err) {
1764 case ERROR_BROKEN_PIPE:
1765 mark_as_completed(&self->overlapped);
1766 return SetFromWindowsErr(err);
1767 case ERROR_SUCCESS:
1768 case ERROR_MORE_DATA:
1769 case ERROR_IO_PENDING:
1770 Py_RETURN_NONE;
1771 default:
1772 self->type = TYPE_NOT_STARTED;
1773 return SetFromWindowsErr(err);
1774 }
1775}
1776
Zackery Spytz9650fe02020-07-10 11:43:37 -06001777#include "clinic/overlapped.c.h"
Victor Stinner54850852019-01-11 14:35:14 +01001778
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001779static PyMethodDef Overlapped_methods[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001780 _OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
1781 _OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
1782 _OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
1783 _OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
1784 _OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
1785 _OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
1786 _OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
1787 _OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
1788 _OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
1789 _OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
1790 _OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
1791 _OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
1792 _OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
1793 _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
1794 _OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001795 {NULL}
1796};
1797
1798static PyMemberDef Overlapped_members[] = {
1799 {"error", T_ULONG,
1800 offsetof(OverlappedObject, error),
1801 READONLY, "Error from last operation"},
1802 {"event", T_HANDLE,
1803 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1804 READONLY, "Overlapped event handle"},
1805 {NULL}
1806};
1807
1808static PyGetSetDef Overlapped_getsets[] = {
1809 {"address", (getter)Overlapped_getaddress, NULL,
1810 "Address of overlapped structure"},
1811 {"pending", (getter)Overlapped_getpending, NULL,
1812 "Whether the operation is pending"},
1813 {NULL},
1814};
1815
1816PyTypeObject OverlappedType = {
1817 PyVarObject_HEAD_INIT(NULL, 0)
1818 /* tp_name */ "_overlapped.Overlapped",
1819 /* tp_basicsize */ sizeof(OverlappedObject),
1820 /* tp_itemsize */ 0,
1821 /* tp_dealloc */ (destructor) Overlapped_dealloc,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001822 /* tp_vectorcall_offset */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001823 /* tp_getattr */ 0,
1824 /* tp_setattr */ 0,
Jeroen Demeyer530f5062019-05-31 04:13:39 +02001825 /* tp_as_async */ 0,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001826 /* tp_repr */ 0,
1827 /* tp_as_number */ 0,
1828 /* tp_as_sequence */ 0,
1829 /* tp_as_mapping */ 0,
1830 /* tp_hash */ 0,
1831 /* tp_call */ 0,
1832 /* tp_str */ 0,
1833 /* tp_getattro */ 0,
1834 /* tp_setattro */ 0,
1835 /* tp_as_buffer */ 0,
1836 /* tp_flags */ Py_TPFLAGS_DEFAULT,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001837 /* tp_doc */ _overlapped_Overlapped__doc__,
Victor Stinner54850852019-01-11 14:35:14 +01001838 /* tp_traverse */ (traverseproc)Overlapped_traverse,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001839 /* tp_clear */ 0,
1840 /* tp_richcompare */ 0,
1841 /* tp_weaklistoffset */ 0,
1842 /* tp_iter */ 0,
1843 /* tp_iternext */ 0,
1844 /* tp_methods */ Overlapped_methods,
1845 /* tp_members */ Overlapped_members,
1846 /* tp_getset */ Overlapped_getsets,
1847 /* tp_base */ 0,
1848 /* tp_dict */ 0,
1849 /* tp_descr_get */ 0,
1850 /* tp_descr_set */ 0,
1851 /* tp_dictoffset */ 0,
1852 /* tp_init */ 0,
1853 /* tp_alloc */ 0,
Zackery Spytz9650fe02020-07-10 11:43:37 -06001854 /* tp_new */ _overlapped_Overlapped,
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001855};
1856
1857static PyMethodDef overlapped_functions[] = {
Zackery Spytz9650fe02020-07-10 11:43:37 -06001858 _OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
1859 _OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
1860 _OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
1861 _OVERLAPPED_FORMATMESSAGE_METHODDEF
1862 _OVERLAPPED_BINDLOCAL_METHODDEF
1863 _OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
1864 _OVERLAPPED_UNREGISTERWAIT_METHODDEF
1865 _OVERLAPPED_UNREGISTERWAITEX_METHODDEF
1866 _OVERLAPPED_CREATEEVENT_METHODDEF
1867 _OVERLAPPED_SETEVENT_METHODDEF
1868 _OVERLAPPED_RESETEVENT_METHODDEF
1869 _OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
1870 _OVERLAPPED_WSACONNECT_METHODDEF
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001871 {NULL}
1872};
1873
1874static struct PyModuleDef overlapped_module = {
1875 PyModuleDef_HEAD_INIT,
1876 "_overlapped",
1877 NULL,
1878 -1,
1879 overlapped_functions,
1880 NULL,
1881 NULL,
1882 NULL,
1883 NULL
1884};
1885
1886#define WINAPI_CONSTANT(fmt, con) \
1887 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1888
1889PyMODINIT_FUNC
1890PyInit__overlapped(void)
1891{
1892 PyObject *m, *d;
1893
1894 /* Ensure WSAStartup() called before initializing function pointers */
1895 m = PyImport_ImportModule("_socket");
1896 if (!m)
1897 return NULL;
1898 Py_DECREF(m);
1899
1900 if (initialize_function_pointers() < 0)
1901 return NULL;
1902
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001903 m = PyModule_Create(&overlapped_module);
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001904 if (PyModule_AddType(m, &OverlappedType) < 0) {
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001905 return NULL;
Dong-hee Na37fcbb62020-03-25 07:08:51 +09001906 }
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001907
1908 d = PyModule_GetDict(m);
1909
1910 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1911 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Andrew Svetlov7c684072018-01-27 21:22:47 +02001912 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001913 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
Victor Stinner7ffa2c52015-01-22 22:55:08 +01001914 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
Guido van Rossum27b7c7e2013-10-17 13:40:50 -07001915 WINAPI_CONSTANT(F_DWORD, INFINITE);
1916 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1917 WINAPI_CONSTANT(F_HANDLE, NULL);
1918 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1919 WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1920 WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1921
1922 return m;
1923}