• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Support for overlapped IO
3  *
4  * Some code borrowed from Modules/_winapi.c of CPython
5  */
6 
7 /* XXX check overflow and DWORD <-> Py_ssize_t conversions
8    Check itemsize */
9 
10 #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