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