ยปCore Development>Code coverage>Modules/overlapped.c

Python code coverage for Modules/overlapped.c

#countcontent
1n/a/*
2n/a * Support for overlapped IO
3n/a *
4n/a * Some code borrowed from Modules/_winapi.c of CPython
5n/a */
6n/a
7n/a/* XXX check overflow and DWORD <-> Py_ssize_t conversions
8n/a Check itemsize */
9n/a
10n/a#include "Python.h"
11n/a#include "structmember.h"
12n/a
13n/a#define WINDOWS_LEAN_AND_MEAN
14n/a#include <winsock2.h>
15n/a#include <ws2tcpip.h>
16n/a#include <mswsock.h>
17n/a
18n/a#if defined(MS_WIN32) && !defined(MS_WIN64)
19n/a# define F_POINTER "k"
20n/a# define T_POINTER T_ULONG
21n/a#else
22n/a# define F_POINTER "K"
23n/a# define T_POINTER T_ULONGLONG
24n/a#endif
25n/a
26n/a/* Compatibility with Python 3.3 */
27n/a#if PY_VERSION_HEX < 0x03040000
28n/a# define PyMem_RawMalloc PyMem_Malloc
29n/a# define PyMem_RawFree PyMem_Free
30n/a#endif
31n/a
32n/a#define F_HANDLE F_POINTER
33n/a#define F_ULONG_PTR F_POINTER
34n/a#define F_DWORD "k"
35n/a#define F_BOOL "i"
36n/a#define F_UINT "I"
37n/a
38n/a#define T_HANDLE T_POINTER
39n/a
40n/aenum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_WRITE, TYPE_ACCEPT,
41n/a TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
42n/a TYPE_WAIT_NAMED_PIPE_AND_CONNECT};
43n/a
44n/atypedef struct {
45n/a PyObject_HEAD
46n/a OVERLAPPED overlapped;
47n/a /* For convenience, we store the file handle too */
48n/a HANDLE handle;
49n/a /* Error returned by last method call */
50n/a DWORD error;
51n/a /* Type of operation */
52n/a DWORD type;
53n/a union {
54n/a /* Buffer used for reading: TYPE_READ and TYPE_ACCEPT */
55n/a PyObject *read_buffer;
56n/a /* Buffer used for writing: TYPE_WRITE */
57n/a Py_buffer write_buffer;
58n/a };
59n/a} OverlappedObject;
60n/a
61n/a/*
62n/a * Map Windows error codes to subclasses of OSError
63n/a */
64n/a
65n/astatic PyObject *
66n/aSetFromWindowsErr(DWORD err)
67n/a{
68n/a PyObject *exception_type;
69n/a
70n/a if (err == 0)
71n/a err = GetLastError();
72n/a switch (err) {
73n/a case ERROR_CONNECTION_REFUSED:
74n/a exception_type = PyExc_ConnectionRefusedError;
75n/a break;
76n/a case ERROR_CONNECTION_ABORTED:
77n/a exception_type = PyExc_ConnectionAbortedError;
78n/a break;
79n/a default:
80n/a exception_type = PyExc_OSError;
81n/a }
82n/a return PyErr_SetExcFromWindowsErr(exception_type, err);
83n/a}
84n/a
85n/a/*
86n/a * Some functions should be loaded at runtime
87n/a */
88n/a
89n/astatic LPFN_ACCEPTEX Py_AcceptEx = NULL;
90n/astatic LPFN_CONNECTEX Py_ConnectEx = NULL;
91n/astatic LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
92n/astatic BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
93n/a
94n/a#define GET_WSA_POINTER(s, x) \
95n/a (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
96n/a &Guid##x, sizeof(Guid##x), &Py_##x, \
97n/a sizeof(Py_##x), &dwBytes, NULL, NULL))
98n/a
99n/astatic int
100n/ainitialize_function_pointers(void)
101n/a{
102n/a GUID GuidAcceptEx = WSAID_ACCEPTEX;
103n/a GUID GuidConnectEx = WSAID_CONNECTEX;
104n/a GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
105n/a HINSTANCE hKernel32;
106n/a SOCKET s;
107n/a DWORD dwBytes;
108n/a
109n/a s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
110n/a if (s == INVALID_SOCKET) {
111n/a SetFromWindowsErr(WSAGetLastError());
112n/a return -1;
113n/a }
114n/a
115n/a if (!GET_WSA_POINTER(s, AcceptEx) ||
116n/a !GET_WSA_POINTER(s, ConnectEx) ||
117n/a !GET_WSA_POINTER(s, DisconnectEx))
118n/a {
119n/a closesocket(s);
120n/a SetFromWindowsErr(WSAGetLastError());
121n/a return -1;
122n/a }
123n/a
124n/a closesocket(s);
125n/a
126n/a /* On WinXP we will have Py_CancelIoEx == NULL */
127n/a hKernel32 = GetModuleHandle("KERNEL32");
128n/a *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
129n/a return 0;
130n/a}
131n/a
132n/a/*
133n/a * Completion port stuff
134n/a */
135n/a
136n/aPyDoc_STRVAR(
137n/a CreateIoCompletionPort_doc,
138n/a "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
139n/a "Create a completion port or register a handle with a port.");
140n/a
141n/astatic PyObject *
142n/aoverlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
143n/a{
144n/a HANDLE FileHandle;
145n/a HANDLE ExistingCompletionPort;
146n/a ULONG_PTR CompletionKey;
147n/a DWORD NumberOfConcurrentThreads;
148n/a HANDLE ret;
149n/a
150n/a if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
151n/a &FileHandle, &ExistingCompletionPort, &CompletionKey,
152n/a &NumberOfConcurrentThreads))
153n/a return NULL;
154n/a
155n/a Py_BEGIN_ALLOW_THREADS
156n/a ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
157n/a CompletionKey, NumberOfConcurrentThreads);
158n/a Py_END_ALLOW_THREADS
159n/a
160n/a if (ret == NULL)
161n/a return SetFromWindowsErr(0);
162n/a return Py_BuildValue(F_HANDLE, ret);
163n/a}
164n/a
165n/aPyDoc_STRVAR(
166n/a GetQueuedCompletionStatus_doc,
167n/a "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
168n/a "Get a message from completion port. Wait for up to msecs milliseconds.");
169n/a
170n/astatic PyObject *
171n/aoverlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
172n/a{
173n/a HANDLE CompletionPort = NULL;
174n/a DWORD NumberOfBytes = 0;
175n/a ULONG_PTR CompletionKey = 0;
176n/a OVERLAPPED *Overlapped = NULL;
177n/a DWORD Milliseconds;
178n/a DWORD err;
179n/a BOOL ret;
180n/a
181n/a if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
182n/a &CompletionPort, &Milliseconds))
183n/a return NULL;
184n/a
185n/a Py_BEGIN_ALLOW_THREADS
186n/a ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
187n/a &CompletionKey, &Overlapped, Milliseconds);
188n/a Py_END_ALLOW_THREADS
189n/a
190n/a err = ret ? ERROR_SUCCESS : GetLastError();
191n/a if (Overlapped == NULL) {
192n/a if (err == WAIT_TIMEOUT)
193n/a Py_RETURN_NONE;
194n/a else
195n/a return SetFromWindowsErr(err);
196n/a }
197n/a return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
198n/a err, NumberOfBytes, CompletionKey, Overlapped);
199n/a}
200n/a
201n/aPyDoc_STRVAR(
202n/a PostQueuedCompletionStatus_doc,
203n/a "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
204n/a "Post a message to completion port.");
205n/a
206n/astatic PyObject *
207n/aoverlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
208n/a{
209n/a HANDLE CompletionPort;
210n/a DWORD NumberOfBytes;
211n/a ULONG_PTR CompletionKey;
212n/a OVERLAPPED *Overlapped;
213n/a BOOL ret;
214n/a
215n/a if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
216n/a &CompletionPort, &NumberOfBytes, &CompletionKey,
217n/a &Overlapped))
218n/a return NULL;
219n/a
220n/a Py_BEGIN_ALLOW_THREADS
221n/a ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
222n/a CompletionKey, Overlapped);
223n/a Py_END_ALLOW_THREADS
224n/a
225n/a if (!ret)
226n/a return SetFromWindowsErr(0);
227n/a Py_RETURN_NONE;
228n/a}
229n/a
230n/a/*
231n/a * Wait for a handle
232n/a */
233n/a
234n/astruct PostCallbackData {
235n/a HANDLE CompletionPort;
236n/a LPOVERLAPPED Overlapped;
237n/a};
238n/a
239n/astatic VOID CALLBACK
240n/aPostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
241n/a{
242n/a struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
243n/a
244n/a PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
245n/a 0, p->Overlapped);
246n/a /* ignore possible error! */
247n/a PyMem_RawFree(p);
248n/a}
249n/a
250n/aPyDoc_STRVAR(
251n/a RegisterWaitWithQueue_doc,
252n/a "RegisterWaitWithQueue(Object, CompletionPort, Overlapped, Timeout)\n"
253n/a " -> WaitHandle\n\n"
254n/a "Register wait for Object; when complete CompletionPort is notified.\n");
255n/a
256n/astatic PyObject *
257n/aoverlapped_RegisterWaitWithQueue(PyObject *self, PyObject *args)
258n/a{
259n/a HANDLE NewWaitObject;
260n/a HANDLE Object;
261n/a ULONG Milliseconds;
262n/a struct PostCallbackData data, *pdata;
263n/a
264n/a if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_POINTER F_DWORD,
265n/a &Object,
266n/a &data.CompletionPort,
267n/a &data.Overlapped,
268n/a &Milliseconds))
269n/a return NULL;
270n/a
271n/a /* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
272n/a PostToQueueCallback() will call PyMem_Free() from a new C thread
273n/a which doesn't hold the GIL. */
274n/a pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
275n/a if (pdata == NULL)
276n/a return SetFromWindowsErr(0);
277n/a
278n/a *pdata = data;
279n/a
280n/a if (!RegisterWaitForSingleObject(
281n/a &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
282n/a pdata, Milliseconds,
283n/a WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
284n/a {
285n/a PyMem_RawFree(pdata);
286n/a return SetFromWindowsErr(0);
287n/a }
288n/a
289n/a return Py_BuildValue(F_HANDLE, NewWaitObject);
290n/a}
291n/a
292n/aPyDoc_STRVAR(
293n/a UnregisterWait_doc,
294n/a "UnregisterWait(WaitHandle) -> None\n\n"
295n/a "Unregister wait handle.\n");
296n/a
297n/astatic PyObject *
298n/aoverlapped_UnregisterWait(PyObject *self, PyObject *args)
299n/a{
300n/a HANDLE WaitHandle;
301n/a BOOL ret;
302n/a
303n/a if (!PyArg_ParseTuple(args, F_HANDLE, &WaitHandle))
304n/a return NULL;
305n/a
306n/a Py_BEGIN_ALLOW_THREADS
307n/a ret = UnregisterWait(WaitHandle);
308n/a Py_END_ALLOW_THREADS
309n/a
310n/a if (!ret)
311n/a return SetFromWindowsErr(0);
312n/a Py_RETURN_NONE;
313n/a}
314n/a
315n/aPyDoc_STRVAR(
316n/a UnregisterWaitEx_doc,
317n/a "UnregisterWaitEx(WaitHandle, Event) -> None\n\n"
318n/a "Unregister wait handle.\n");
319n/a
320n/astatic PyObject *
321n/aoverlapped_UnregisterWaitEx(PyObject *self, PyObject *args)
322n/a{
323n/a HANDLE WaitHandle, Event;
324n/a BOOL ret;
325n/a
326n/a if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &WaitHandle, &Event))
327n/a return NULL;
328n/a
329n/a Py_BEGIN_ALLOW_THREADS
330n/a ret = UnregisterWaitEx(WaitHandle, Event);
331n/a Py_END_ALLOW_THREADS
332n/a
333n/a if (!ret)
334n/a return SetFromWindowsErr(0);
335n/a Py_RETURN_NONE;
336n/a}
337n/a
338n/a/*
339n/a * Event functions -- currently only used by tests
340n/a */
341n/a
342n/aPyDoc_STRVAR(
343n/a CreateEvent_doc,
344n/a "CreateEvent(EventAttributes, ManualReset, InitialState, Name)"
345n/a " -> Handle\n\n"
346n/a "Create an event. EventAttributes must be None.\n");
347n/a
348n/astatic PyObject *
349n/aoverlapped_CreateEvent(PyObject *self, PyObject *args)
350n/a{
351n/a PyObject *EventAttributes;
352n/a BOOL ManualReset;
353n/a BOOL InitialState;
354n/a Py_UNICODE *Name;
355n/a HANDLE Event;
356n/a
357n/a if (!PyArg_ParseTuple(args, "O" F_BOOL F_BOOL "Z",
358n/a &EventAttributes, &ManualReset,
359n/a &InitialState, &Name))
360n/a return NULL;
361n/a
362n/a if (EventAttributes != Py_None) {
363n/a PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
364n/a return NULL;
365n/a }
366n/a
367n/a Py_BEGIN_ALLOW_THREADS
368n/a Event = CreateEventW(NULL, ManualReset, InitialState, Name);
369n/a Py_END_ALLOW_THREADS
370n/a
371n/a if (Event == NULL)
372n/a return SetFromWindowsErr(0);
373n/a return Py_BuildValue(F_HANDLE, Event);
374n/a}
375n/a
376n/aPyDoc_STRVAR(
377n/a SetEvent_doc,
378n/a "SetEvent(Handle) -> None\n\n"
379n/a "Set event.\n");
380n/a
381n/astatic PyObject *
382n/aoverlapped_SetEvent(PyObject *self, PyObject *args)
383n/a{
384n/a HANDLE Handle;
385n/a BOOL ret;
386n/a
387n/a if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
388n/a return NULL;
389n/a
390n/a Py_BEGIN_ALLOW_THREADS
391n/a ret = SetEvent(Handle);
392n/a Py_END_ALLOW_THREADS
393n/a
394n/a if (!ret)
395n/a return SetFromWindowsErr(0);
396n/a Py_RETURN_NONE;
397n/a}
398n/a
399n/aPyDoc_STRVAR(
400n/a ResetEvent_doc,
401n/a "ResetEvent(Handle) -> None\n\n"
402n/a "Reset event.\n");
403n/a
404n/astatic PyObject *
405n/aoverlapped_ResetEvent(PyObject *self, PyObject *args)
406n/a{
407n/a HANDLE Handle;
408n/a BOOL ret;
409n/a
410n/a if (!PyArg_ParseTuple(args, F_HANDLE, &Handle))
411n/a return NULL;
412n/a
413n/a Py_BEGIN_ALLOW_THREADS
414n/a ret = ResetEvent(Handle);
415n/a Py_END_ALLOW_THREADS
416n/a
417n/a if (!ret)
418n/a return SetFromWindowsErr(0);
419n/a Py_RETURN_NONE;
420n/a}
421n/a
422n/a/*
423n/a * Bind socket handle to local port without doing slow getaddrinfo()
424n/a */
425n/a
426n/aPyDoc_STRVAR(
427n/a BindLocal_doc,
428n/a "BindLocal(handle, family) -> None\n\n"
429n/a "Bind a socket handle to an arbitrary local port.\n"
430n/a "family should AF_INET or AF_INET6.\n");
431n/a
432n/astatic PyObject *
433n/aoverlapped_BindLocal(PyObject *self, PyObject *args)
434n/a{
435n/a SOCKET Socket;
436n/a int Family;
437n/a BOOL ret;
438n/a
439n/a if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &Family))
440n/a return NULL;
441n/a
442n/a if (Family == AF_INET) {
443n/a struct sockaddr_in addr;
444n/a memset(&addr, 0, sizeof(addr));
445n/a addr.sin_family = AF_INET;
446n/a addr.sin_port = 0;
447n/a addr.sin_addr.S_un.S_addr = INADDR_ANY;
448n/a ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
449n/a } else if (Family == AF_INET6) {
450n/a struct sockaddr_in6 addr;
451n/a memset(&addr, 0, sizeof(addr));
452n/a addr.sin6_family = AF_INET6;
453n/a addr.sin6_port = 0;
454n/a addr.sin6_addr = in6addr_any;
455n/a ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
456n/a } else {
457n/a PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
458n/a return NULL;
459n/a }
460n/a
461n/a if (!ret)
462n/a return SetFromWindowsErr(WSAGetLastError());
463n/a Py_RETURN_NONE;
464n/a}
465n/a
466n/a/*
467n/a * Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
468n/a */
469n/a
470n/aPyDoc_STRVAR(
471n/a FormatMessage_doc,
472n/a "FormatMessage(error_code) -> error_message\n\n"
473n/a "Return error message for an error code.");
474n/a
475n/astatic PyObject *
476n/aoverlapped_FormatMessage(PyObject *ignore, PyObject *args)
477n/a{
478n/a DWORD code, n;
479n/a WCHAR *lpMsgBuf;
480n/a PyObject *res;
481n/a
482n/a if (!PyArg_ParseTuple(args, F_DWORD, &code))
483n/a return NULL;
484n/a
485n/a n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
486n/a FORMAT_MESSAGE_FROM_SYSTEM,
487n/a NULL,
488n/a code,
489n/a MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
490n/a (LPWSTR) &lpMsgBuf,
491n/a 0,
492n/a NULL);
493n/a if (n) {
494n/a while (iswspace(lpMsgBuf[n-1]))
495n/a --n;
496n/a lpMsgBuf[n] = L'\0';
497n/a res = Py_BuildValue("u", lpMsgBuf);
498n/a } else {
499n/a res = PyUnicode_FromFormat("unknown error code %u", code);
500n/a }
501n/a LocalFree(lpMsgBuf);
502n/a return res;
503n/a}
504n/a
505n/a
506n/a/*
507n/a * Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
508n/a */
509n/a
510n/astatic void
511n/amark_as_completed(OVERLAPPED *ov)
512n/a{
513n/a ov->Internal = 0;
514n/a if (ov->hEvent != NULL)
515n/a SetEvent(ov->hEvent);
516n/a}
517n/a
518n/a/*
519n/a * A Python object wrapping an OVERLAPPED structure and other useful data
520n/a * for overlapped I/O
521n/a */
522n/a
523n/aPyDoc_STRVAR(
524n/a Overlapped_doc,
525n/a "Overlapped object");
526n/a
527n/astatic PyObject *
528n/aOverlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
529n/a{
530n/a OverlappedObject *self;
531n/a HANDLE event = INVALID_HANDLE_VALUE;
532n/a static char *kwlist[] = {"event", NULL};
533n/a
534n/a if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
535n/a return NULL;
536n/a
537n/a if (event == INVALID_HANDLE_VALUE) {
538n/a event = CreateEvent(NULL, TRUE, FALSE, NULL);
539n/a if (event == NULL)
540n/a return SetFromWindowsErr(0);
541n/a }
542n/a
543n/a self = PyObject_New(OverlappedObject, type);
544n/a if (self == NULL) {
545n/a if (event != NULL)
546n/a CloseHandle(event);
547n/a return NULL;
548n/a }
549n/a
550n/a self->handle = NULL;
551n/a self->error = 0;
552n/a self->type = TYPE_NONE;
553n/a self->read_buffer = NULL;
554n/a memset(&self->overlapped, 0, sizeof(OVERLAPPED));
555n/a memset(&self->write_buffer, 0, sizeof(Py_buffer));
556n/a if (event)
557n/a self->overlapped.hEvent = event;
558n/a return (PyObject *)self;
559n/a}
560n/a
561n/astatic void
562n/aOverlapped_dealloc(OverlappedObject *self)
563n/a{
564n/a DWORD bytes;
565n/a DWORD olderr = GetLastError();
566n/a BOOL wait = FALSE;
567n/a BOOL ret;
568n/a
569n/a if (!HasOverlappedIoCompleted(&self->overlapped) &&
570n/a self->type != TYPE_NOT_STARTED)
571n/a {
572n/a if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
573n/a wait = TRUE;
574n/a
575n/a Py_BEGIN_ALLOW_THREADS
576n/a ret = GetOverlappedResult(self->handle, &self->overlapped,
577n/a &bytes, wait);
578n/a Py_END_ALLOW_THREADS
579n/a
580n/a switch (ret ? ERROR_SUCCESS : GetLastError()) {
581n/a case ERROR_SUCCESS:
582n/a case ERROR_NOT_FOUND:
583n/a case ERROR_OPERATION_ABORTED:
584n/a break;
585n/a default:
586n/a PyErr_Format(
587n/a PyExc_RuntimeError,
588n/a "%R still has pending operation at "
589n/a "deallocation, the process may crash", self);
590n/a PyErr_WriteUnraisable(NULL);
591n/a }
592n/a }
593n/a
594n/a if (self->overlapped.hEvent != NULL)
595n/a CloseHandle(self->overlapped.hEvent);
596n/a
597n/a switch (self->type) {
598n/a case TYPE_READ:
599n/a case TYPE_ACCEPT:
600n/a Py_CLEAR(self->read_buffer);
601n/a break;
602n/a case TYPE_WRITE:
603n/a if (self->write_buffer.obj)
604n/a PyBuffer_Release(&self->write_buffer);
605n/a break;
606n/a }
607n/a PyObject_Del(self);
608n/a SetLastError(olderr);
609n/a}
610n/a
611n/aPyDoc_STRVAR(
612n/a Overlapped_cancel_doc,
613n/a "cancel() -> None\n\n"
614n/a "Cancel overlapped operation");
615n/a
616n/astatic PyObject *
617n/aOverlapped_cancel(OverlappedObject *self)
618n/a{
619n/a BOOL ret = TRUE;
620n/a
621n/a if (self->type == TYPE_NOT_STARTED
622n/a || self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
623n/a Py_RETURN_NONE;
624n/a
625n/a if (!HasOverlappedIoCompleted(&self->overlapped)) {
626n/a Py_BEGIN_ALLOW_THREADS
627n/a if (Py_CancelIoEx)
628n/a ret = Py_CancelIoEx(self->handle, &self->overlapped);
629n/a else
630n/a ret = CancelIo(self->handle);
631n/a Py_END_ALLOW_THREADS
632n/a }
633n/a
634n/a /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
635n/a if (!ret && GetLastError() != ERROR_NOT_FOUND)
636n/a return SetFromWindowsErr(0);
637n/a Py_RETURN_NONE;
638n/a}
639n/a
640n/aPyDoc_STRVAR(
641n/a Overlapped_getresult_doc,
642n/a "getresult(wait=False) -> result\n\n"
643n/a "Retrieve result of operation. If wait is true then it blocks\n"
644n/a "until the operation is finished. If wait is false and the\n"
645n/a "operation is still pending then an error is raised.");
646n/a
647n/astatic PyObject *
648n/aOverlapped_getresult(OverlappedObject *self, PyObject *args)
649n/a{
650n/a BOOL wait = FALSE;
651n/a DWORD transferred = 0;
652n/a BOOL ret;
653n/a DWORD err;
654n/a
655n/a if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
656n/a return NULL;
657n/a
658n/a if (self->type == TYPE_NONE) {
659n/a PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
660n/a return NULL;
661n/a }
662n/a
663n/a if (self->type == TYPE_NOT_STARTED) {
664n/a PyErr_SetString(PyExc_ValueError, "operation failed to start");
665n/a return NULL;
666n/a }
667n/a
668n/a Py_BEGIN_ALLOW_THREADS
669n/a ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
670n/a wait);
671n/a Py_END_ALLOW_THREADS
672n/a
673n/a self->error = err = ret ? ERROR_SUCCESS : GetLastError();
674n/a switch (err) {
675n/a case ERROR_SUCCESS:
676n/a case ERROR_MORE_DATA:
677n/a break;
678n/a case ERROR_BROKEN_PIPE:
679n/a if ((self->type == TYPE_READ || self->type == TYPE_ACCEPT) && self->read_buffer != NULL)
680n/a break;
681n/a /* fall through */
682n/a default:
683n/a return SetFromWindowsErr(err);
684n/a }
685n/a
686n/a switch (self->type) {
687n/a case TYPE_READ:
688n/a assert(PyBytes_CheckExact(self->read_buffer));
689n/a if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
690n/a _PyBytes_Resize(&self->read_buffer, transferred))
691n/a return NULL;
692n/a Py_INCREF(self->read_buffer);
693n/a return self->read_buffer;
694n/a default:
695n/a return PyLong_FromUnsignedLong((unsigned long) transferred);
696n/a }
697n/a}
698n/a
699n/aPyDoc_STRVAR(
700n/a Overlapped_ReadFile_doc,
701n/a "ReadFile(handle, size) -> Overlapped[message]\n\n"
702n/a "Start overlapped read");
703n/a
704n/astatic PyObject *
705n/aOverlapped_ReadFile(OverlappedObject *self, PyObject *args)
706n/a{
707n/a HANDLE handle;
708n/a DWORD size;
709n/a DWORD nread;
710n/a PyObject *buf;
711n/a BOOL ret;
712n/a DWORD err;
713n/a
714n/a if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
715n/a return NULL;
716n/a
717n/a if (self->type != TYPE_NONE) {
718n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
719n/a return NULL;
720n/a }
721n/a
722n/a#if SIZEOF_SIZE_T <= SIZEOF_LONG
723n/a size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
724n/a#endif
725n/a buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
726n/a if (buf == NULL)
727n/a return NULL;
728n/a
729n/a self->type = TYPE_READ;
730n/a self->handle = handle;
731n/a self->read_buffer = buf;
732n/a
733n/a Py_BEGIN_ALLOW_THREADS
734n/a ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
735n/a &self->overlapped);
736n/a Py_END_ALLOW_THREADS
737n/a
738n/a self->error = err = ret ? ERROR_SUCCESS : GetLastError();
739n/a switch (err) {
740n/a case ERROR_BROKEN_PIPE:
741n/a mark_as_completed(&self->overlapped);
742n/a return SetFromWindowsErr(err);
743n/a case ERROR_SUCCESS:
744n/a case ERROR_MORE_DATA:
745n/a case ERROR_IO_PENDING:
746n/a Py_RETURN_NONE;
747n/a default:
748n/a self->type = TYPE_NOT_STARTED;
749n/a return SetFromWindowsErr(err);
750n/a }
751n/a}
752n/a
753n/aPyDoc_STRVAR(
754n/a Overlapped_WSARecv_doc,
755n/a "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
756n/a "Start overlapped receive");
757n/a
758n/astatic PyObject *
759n/aOverlapped_WSARecv(OverlappedObject *self, PyObject *args)
760n/a{
761n/a HANDLE handle;
762n/a DWORD size;
763n/a DWORD flags = 0;
764n/a DWORD nread;
765n/a PyObject *buf;
766n/a WSABUF wsabuf;
767n/a int ret;
768n/a DWORD err;
769n/a
770n/a if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD "|" F_DWORD,
771n/a &handle, &size, &flags))
772n/a return NULL;
773n/a
774n/a if (self->type != TYPE_NONE) {
775n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
776n/a return NULL;
777n/a }
778n/a
779n/a#if SIZEOF_SIZE_T <= SIZEOF_LONG
780n/a size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
781n/a#endif
782n/a buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
783n/a if (buf == NULL)
784n/a return NULL;
785n/a
786n/a self->type = TYPE_READ;
787n/a self->handle = handle;
788n/a self->read_buffer = buf;
789n/a wsabuf.len = size;
790n/a wsabuf.buf = PyBytes_AS_STRING(buf);
791n/a
792n/a Py_BEGIN_ALLOW_THREADS
793n/a ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
794n/a &self->overlapped, NULL);
795n/a Py_END_ALLOW_THREADS
796n/a
797n/a self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
798n/a switch (err) {
799n/a case ERROR_BROKEN_PIPE:
800n/a mark_as_completed(&self->overlapped);
801n/a return SetFromWindowsErr(err);
802n/a case ERROR_SUCCESS:
803n/a case ERROR_MORE_DATA:
804n/a case ERROR_IO_PENDING:
805n/a Py_RETURN_NONE;
806n/a default:
807n/a self->type = TYPE_NOT_STARTED;
808n/a return SetFromWindowsErr(err);
809n/a }
810n/a}
811n/a
812n/aPyDoc_STRVAR(
813n/a Overlapped_WriteFile_doc,
814n/a "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
815n/a "Start overlapped write");
816n/a
817n/astatic PyObject *
818n/aOverlapped_WriteFile(OverlappedObject *self, PyObject *args)
819n/a{
820n/a HANDLE handle;
821n/a PyObject *bufobj;
822n/a DWORD written;
823n/a BOOL ret;
824n/a DWORD err;
825n/a
826n/a if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
827n/a return NULL;
828n/a
829n/a if (self->type != TYPE_NONE) {
830n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
831n/a return NULL;
832n/a }
833n/a
834n/a if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
835n/a return NULL;
836n/a
837n/a#if SIZEOF_SIZE_T > SIZEOF_LONG
838n/a if (self->write_buffer.len > (Py_ssize_t)ULONG_MAX) {
839n/a PyBuffer_Release(&self->write_buffer);
840n/a PyErr_SetString(PyExc_ValueError, "buffer to large");
841n/a return NULL;
842n/a }
843n/a#endif
844n/a
845n/a self->type = TYPE_WRITE;
846n/a self->handle = handle;
847n/a
848n/a Py_BEGIN_ALLOW_THREADS
849n/a ret = WriteFile(handle, self->write_buffer.buf,
850n/a (DWORD)self->write_buffer.len,
851n/a &written, &self->overlapped);
852n/a Py_END_ALLOW_THREADS
853n/a
854n/a self->error = err = ret ? ERROR_SUCCESS : GetLastError();
855n/a switch (err) {
856n/a case ERROR_SUCCESS:
857n/a case ERROR_IO_PENDING:
858n/a Py_RETURN_NONE;
859n/a default:
860n/a self->type = TYPE_NOT_STARTED;
861n/a return SetFromWindowsErr(err);
862n/a }
863n/a}
864n/a
865n/aPyDoc_STRVAR(
866n/a Overlapped_WSASend_doc,
867n/a "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
868n/a "Start overlapped send");
869n/a
870n/astatic PyObject *
871n/aOverlapped_WSASend(OverlappedObject *self, PyObject *args)
872n/a{
873n/a HANDLE handle;
874n/a PyObject *bufobj;
875n/a DWORD flags;
876n/a DWORD written;
877n/a WSABUF wsabuf;
878n/a int ret;
879n/a DWORD err;
880n/a
881n/a if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
882n/a &handle, &bufobj, &flags))
883n/a return NULL;
884n/a
885n/a if (self->type != TYPE_NONE) {
886n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
887n/a return NULL;
888n/a }
889n/a
890n/a if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
891n/a return NULL;
892n/a
893n/a#if SIZEOF_SIZE_T > SIZEOF_LONG
894n/a if (self->write_buffer.len > (Py_ssize_t)ULONG_MAX) {
895n/a PyBuffer_Release(&self->write_buffer);
896n/a PyErr_SetString(PyExc_ValueError, "buffer to large");
897n/a return NULL;
898n/a }
899n/a#endif
900n/a
901n/a self->type = TYPE_WRITE;
902n/a self->handle = handle;
903n/a wsabuf.len = (DWORD)self->write_buffer.len;
904n/a wsabuf.buf = self->write_buffer.buf;
905n/a
906n/a Py_BEGIN_ALLOW_THREADS
907n/a ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
908n/a &self->overlapped, NULL);
909n/a Py_END_ALLOW_THREADS
910n/a
911n/a self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
912n/a switch (err) {
913n/a case ERROR_SUCCESS:
914n/a case ERROR_IO_PENDING:
915n/a Py_RETURN_NONE;
916n/a default:
917n/a self->type = TYPE_NOT_STARTED;
918n/a return SetFromWindowsErr(err);
919n/a }
920n/a}
921n/a
922n/aPyDoc_STRVAR(
923n/a Overlapped_AcceptEx_doc,
924n/a "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
925n/a "Start overlapped wait for client to connect");
926n/a
927n/astatic PyObject *
928n/aOverlapped_AcceptEx(OverlappedObject *self, PyObject *args)
929n/a{
930n/a SOCKET ListenSocket;
931n/a SOCKET AcceptSocket;
932n/a DWORD BytesReceived;
933n/a DWORD size;
934n/a PyObject *buf;
935n/a BOOL ret;
936n/a DWORD err;
937n/a
938n/a if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
939n/a &ListenSocket, &AcceptSocket))
940n/a return NULL;
941n/a
942n/a if (self->type != TYPE_NONE) {
943n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
944n/a return NULL;
945n/a }
946n/a
947n/a size = sizeof(struct sockaddr_in6) + 16;
948n/a buf = PyBytes_FromStringAndSize(NULL, size*2);
949n/a if (!buf)
950n/a return NULL;
951n/a
952n/a self->type = TYPE_ACCEPT;
953n/a self->handle = (HANDLE)ListenSocket;
954n/a self->read_buffer = buf;
955n/a
956n/a Py_BEGIN_ALLOW_THREADS
957n/a ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
958n/a 0, size, size, &BytesReceived, &self->overlapped);
959n/a Py_END_ALLOW_THREADS
960n/a
961n/a self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
962n/a switch (err) {
963n/a case ERROR_SUCCESS:
964n/a case ERROR_IO_PENDING:
965n/a Py_RETURN_NONE;
966n/a default:
967n/a self->type = TYPE_NOT_STARTED;
968n/a return SetFromWindowsErr(err);
969n/a }
970n/a}
971n/a
972n/a
973n/astatic int
974n/aparse_address(PyObject *obj, SOCKADDR *Address, int Length)
975n/a{
976n/a Py_UNICODE *Host;
977n/a unsigned short Port;
978n/a unsigned long FlowInfo;
979n/a unsigned long ScopeId;
980n/a
981n/a memset(Address, 0, Length);
982n/a
983n/a if (PyArg_ParseTuple(obj, "uH", &Host, &Port))
984n/a {
985n/a Address->sa_family = AF_INET;
986n/a if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
987n/a SetFromWindowsErr(WSAGetLastError());
988n/a return -1;
989n/a }
990n/a ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
991n/a return Length;
992n/a }
993n/a else if (PyArg_ParseTuple(obj, "uHkk", &Host, &Port, &FlowInfo, &ScopeId))
994n/a {
995n/a PyErr_Clear();
996n/a Address->sa_family = AF_INET6;
997n/a if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
998n/a SetFromWindowsErr(WSAGetLastError());
999n/a return -1;
1000n/a }
1001n/a ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
1002n/a ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
1003n/a ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
1004n/a return Length;
1005n/a }
1006n/a
1007n/a return -1;
1008n/a}
1009n/a
1010n/a
1011n/aPyDoc_STRVAR(
1012n/a Overlapped_ConnectEx_doc,
1013n/a "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
1014n/a "Start overlapped connect. client_handle should be unbound.");
1015n/a
1016n/astatic PyObject *
1017n/aOverlapped_ConnectEx(OverlappedObject *self, PyObject *args)
1018n/a{
1019n/a SOCKET ConnectSocket;
1020n/a PyObject *AddressObj;
1021n/a char AddressBuf[sizeof(struct sockaddr_in6)];
1022n/a SOCKADDR *Address = (SOCKADDR*)AddressBuf;
1023n/a int Length;
1024n/a BOOL ret;
1025n/a DWORD err;
1026n/a
1027n/a if (!PyArg_ParseTuple(args, F_HANDLE "O", &ConnectSocket, &AddressObj))
1028n/a return NULL;
1029n/a
1030n/a if (self->type != TYPE_NONE) {
1031n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
1032n/a return NULL;
1033n/a }
1034n/a
1035n/a Length = sizeof(AddressBuf);
1036n/a Length = parse_address(AddressObj, Address, Length);
1037n/a if (Length < 0)
1038n/a return NULL;
1039n/a
1040n/a self->type = TYPE_CONNECT;
1041n/a self->handle = (HANDLE)ConnectSocket;
1042n/a
1043n/a Py_BEGIN_ALLOW_THREADS
1044n/a ret = Py_ConnectEx(ConnectSocket, Address, Length,
1045n/a NULL, 0, NULL, &self->overlapped);
1046n/a Py_END_ALLOW_THREADS
1047n/a
1048n/a self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1049n/a switch (err) {
1050n/a case ERROR_SUCCESS:
1051n/a case ERROR_IO_PENDING:
1052n/a Py_RETURN_NONE;
1053n/a default:
1054n/a self->type = TYPE_NOT_STARTED;
1055n/a return SetFromWindowsErr(err);
1056n/a }
1057n/a}
1058n/a
1059n/aPyDoc_STRVAR(
1060n/a Overlapped_DisconnectEx_doc,
1061n/a "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
1062n/a "Start overlapped connect. client_handle should be unbound.");
1063n/a
1064n/astatic PyObject *
1065n/aOverlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
1066n/a{
1067n/a SOCKET Socket;
1068n/a DWORD flags;
1069n/a BOOL ret;
1070n/a DWORD err;
1071n/a
1072n/a if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
1073n/a return NULL;
1074n/a
1075n/a if (self->type != TYPE_NONE) {
1076n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
1077n/a return NULL;
1078n/a }
1079n/a
1080n/a self->type = TYPE_DISCONNECT;
1081n/a self->handle = (HANDLE)Socket;
1082n/a
1083n/a Py_BEGIN_ALLOW_THREADS
1084n/a ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
1085n/a Py_END_ALLOW_THREADS
1086n/a
1087n/a self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
1088n/a switch (err) {
1089n/a case ERROR_SUCCESS:
1090n/a case ERROR_IO_PENDING:
1091n/a Py_RETURN_NONE;
1092n/a default:
1093n/a self->type = TYPE_NOT_STARTED;
1094n/a return SetFromWindowsErr(err);
1095n/a }
1096n/a}
1097n/a
1098n/aPyDoc_STRVAR(
1099n/a Overlapped_ConnectNamedPipe_doc,
1100n/a "ConnectNamedPipe(handle) -> Overlapped[None]\n\n"
1101n/a "Start overlapped wait for a client to connect.");
1102n/a
1103n/astatic PyObject *
1104n/aOverlapped_ConnectNamedPipe(OverlappedObject *self, PyObject *args)
1105n/a{
1106n/a HANDLE Pipe;
1107n/a BOOL ret;
1108n/a DWORD err;
1109n/a
1110n/a if (!PyArg_ParseTuple(args, F_HANDLE, &Pipe))
1111n/a return NULL;
1112n/a
1113n/a if (self->type != TYPE_NONE) {
1114n/a PyErr_SetString(PyExc_ValueError, "operation already attempted");
1115n/a return NULL;
1116n/a }
1117n/a
1118n/a self->type = TYPE_CONNECT_NAMED_PIPE;
1119n/a self->handle = Pipe;
1120n/a
1121n/a Py_BEGIN_ALLOW_THREADS
1122n/a ret = ConnectNamedPipe(Pipe, &self->overlapped);
1123n/a Py_END_ALLOW_THREADS
1124n/a
1125n/a self->error = err = ret ? ERROR_SUCCESS : GetLastError();
1126n/a switch (err) {
1127n/a case ERROR_PIPE_CONNECTED:
1128n/a mark_as_completed(&self->overlapped);
1129n/a Py_RETURN_TRUE;
1130n/a case ERROR_SUCCESS:
1131n/a case ERROR_IO_PENDING:
1132n/a Py_RETURN_FALSE;
1133n/a default:
1134n/a self->type = TYPE_NOT_STARTED;
1135n/a return SetFromWindowsErr(err);
1136n/a }
1137n/a}
1138n/a
1139n/aPyDoc_STRVAR(
1140n/a ConnectPipe_doc,
1141n/a "ConnectPipe(addr) -> pipe_handle\n\n"
1142n/a "Connect to the pipe for asynchronous I/O (overlapped).");
1143n/a
1144n/astatic PyObject *
1145n/aConnectPipe(OverlappedObject *self, PyObject *args)
1146n/a{
1147n/a PyObject *AddressObj;
1148n/a wchar_t *Address;
1149n/a HANDLE PipeHandle;
1150n/a
1151n/a if (!PyArg_ParseTuple(args, "U", &AddressObj))
1152n/a return NULL;
1153n/a
1154n/a Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1155n/a if (Address == NULL)
1156n/a return NULL;
1157n/a
1158n/a Py_BEGIN_ALLOW_THREADS
1159n/a PipeHandle = CreateFileW(Address,
1160n/a GENERIC_READ | GENERIC_WRITE,
1161n/a 0, NULL, OPEN_EXISTING,
1162n/a FILE_FLAG_OVERLAPPED, NULL);
1163n/a Py_END_ALLOW_THREADS
1164n/a
1165n/a PyMem_Free(Address);
1166n/a if (PipeHandle == INVALID_HANDLE_VALUE)
1167n/a return SetFromWindowsErr(0);
1168n/a return Py_BuildValue(F_HANDLE, PipeHandle);
1169n/a}
1170n/a
1171n/astatic PyObject*
1172n/aOverlapped_getaddress(OverlappedObject *self)
1173n/a{
1174n/a return PyLong_FromVoidPtr(&self->overlapped);
1175n/a}
1176n/a
1177n/astatic PyObject*
1178n/aOverlapped_getpending(OverlappedObject *self)
1179n/a{
1180n/a return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
1181n/a self->type != TYPE_NOT_STARTED);
1182n/a}
1183n/a
1184n/astatic PyMethodDef Overlapped_methods[] = {
1185n/a {"getresult", (PyCFunction) Overlapped_getresult,
1186n/a METH_VARARGS, Overlapped_getresult_doc},
1187n/a {"cancel", (PyCFunction) Overlapped_cancel,
1188n/a METH_NOARGS, Overlapped_cancel_doc},
1189n/a {"ReadFile", (PyCFunction) Overlapped_ReadFile,
1190n/a METH_VARARGS, Overlapped_ReadFile_doc},
1191n/a {"WSARecv", (PyCFunction) Overlapped_WSARecv,
1192n/a METH_VARARGS, Overlapped_WSARecv_doc},
1193n/a {"WriteFile", (PyCFunction) Overlapped_WriteFile,
1194n/a METH_VARARGS, Overlapped_WriteFile_doc},
1195n/a {"WSASend", (PyCFunction) Overlapped_WSASend,
1196n/a METH_VARARGS, Overlapped_WSASend_doc},
1197n/a {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
1198n/a METH_VARARGS, Overlapped_AcceptEx_doc},
1199n/a {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
1200n/a METH_VARARGS, Overlapped_ConnectEx_doc},
1201n/a {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
1202n/a METH_VARARGS, Overlapped_DisconnectEx_doc},
1203n/a {"ConnectNamedPipe", (PyCFunction) Overlapped_ConnectNamedPipe,
1204n/a METH_VARARGS, Overlapped_ConnectNamedPipe_doc},
1205n/a {NULL}
1206n/a};
1207n/a
1208n/astatic PyMemberDef Overlapped_members[] = {
1209n/a {"error", T_ULONG,
1210n/a offsetof(OverlappedObject, error),
1211n/a READONLY, "Error from last operation"},
1212n/a {"event", T_HANDLE,
1213n/a offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
1214n/a READONLY, "Overlapped event handle"},
1215n/a {NULL}
1216n/a};
1217n/a
1218n/astatic PyGetSetDef Overlapped_getsets[] = {
1219n/a {"address", (getter)Overlapped_getaddress, NULL,
1220n/a "Address of overlapped structure"},
1221n/a {"pending", (getter)Overlapped_getpending, NULL,
1222n/a "Whether the operation is pending"},
1223n/a {NULL},
1224n/a};
1225n/a
1226n/aPyTypeObject OverlappedType = {
1227n/a PyVarObject_HEAD_INIT(NULL, 0)
1228n/a /* tp_name */ "_overlapped.Overlapped",
1229n/a /* tp_basicsize */ sizeof(OverlappedObject),
1230n/a /* tp_itemsize */ 0,
1231n/a /* tp_dealloc */ (destructor) Overlapped_dealloc,
1232n/a /* tp_print */ 0,
1233n/a /* tp_getattr */ 0,
1234n/a /* tp_setattr */ 0,
1235n/a /* tp_reserved */ 0,
1236n/a /* tp_repr */ 0,
1237n/a /* tp_as_number */ 0,
1238n/a /* tp_as_sequence */ 0,
1239n/a /* tp_as_mapping */ 0,
1240n/a /* tp_hash */ 0,
1241n/a /* tp_call */ 0,
1242n/a /* tp_str */ 0,
1243n/a /* tp_getattro */ 0,
1244n/a /* tp_setattro */ 0,
1245n/a /* tp_as_buffer */ 0,
1246n/a /* tp_flags */ Py_TPFLAGS_DEFAULT,
1247n/a /* tp_doc */ "OVERLAPPED structure wrapper",
1248n/a /* tp_traverse */ 0,
1249n/a /* tp_clear */ 0,
1250n/a /* tp_richcompare */ 0,
1251n/a /* tp_weaklistoffset */ 0,
1252n/a /* tp_iter */ 0,
1253n/a /* tp_iternext */ 0,
1254n/a /* tp_methods */ Overlapped_methods,
1255n/a /* tp_members */ Overlapped_members,
1256n/a /* tp_getset */ Overlapped_getsets,
1257n/a /* tp_base */ 0,
1258n/a /* tp_dict */ 0,
1259n/a /* tp_descr_get */ 0,
1260n/a /* tp_descr_set */ 0,
1261n/a /* tp_dictoffset */ 0,
1262n/a /* tp_init */ 0,
1263n/a /* tp_alloc */ 0,
1264n/a /* tp_new */ Overlapped_new,
1265n/a};
1266n/a
1267n/astatic PyMethodDef overlapped_functions[] = {
1268n/a {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
1269n/a METH_VARARGS, CreateIoCompletionPort_doc},
1270n/a {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
1271n/a METH_VARARGS, GetQueuedCompletionStatus_doc},
1272n/a {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
1273n/a METH_VARARGS, PostQueuedCompletionStatus_doc},
1274n/a {"FormatMessage", overlapped_FormatMessage,
1275n/a METH_VARARGS, FormatMessage_doc},
1276n/a {"BindLocal", overlapped_BindLocal,
1277n/a METH_VARARGS, BindLocal_doc},
1278n/a {"RegisterWaitWithQueue", overlapped_RegisterWaitWithQueue,
1279n/a METH_VARARGS, RegisterWaitWithQueue_doc},
1280n/a {"UnregisterWait", overlapped_UnregisterWait,
1281n/a METH_VARARGS, UnregisterWait_doc},
1282n/a {"UnregisterWaitEx", overlapped_UnregisterWaitEx,
1283n/a METH_VARARGS, UnregisterWaitEx_doc},
1284n/a {"CreateEvent", overlapped_CreateEvent,
1285n/a METH_VARARGS, CreateEvent_doc},
1286n/a {"SetEvent", overlapped_SetEvent,
1287n/a METH_VARARGS, SetEvent_doc},
1288n/a {"ResetEvent", overlapped_ResetEvent,
1289n/a METH_VARARGS, ResetEvent_doc},
1290n/a {"ConnectPipe",
1291n/a (PyCFunction) ConnectPipe,
1292n/a METH_VARARGS, ConnectPipe_doc},
1293n/a {NULL}
1294n/a};
1295n/a
1296n/astatic struct PyModuleDef overlapped_module = {
1297n/a PyModuleDef_HEAD_INIT,
1298n/a "_overlapped",
1299n/a NULL,
1300n/a -1,
1301n/a overlapped_functions,
1302n/a NULL,
1303n/a NULL,
1304n/a NULL,
1305n/a NULL
1306n/a};
1307n/a
1308n/a#define WINAPI_CONSTANT(fmt, con) \
1309n/a PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1310n/a
1311n/aPyMODINIT_FUNC
1312n/aPyInit__overlapped(void)
1313n/a{
1314n/a PyObject *m, *d;
1315n/a
1316n/a /* Ensure WSAStartup() called before initializing function pointers */
1317n/a m = PyImport_ImportModule("_socket");
1318n/a if (!m)
1319n/a return NULL;
1320n/a Py_DECREF(m);
1321n/a
1322n/a if (initialize_function_pointers() < 0)
1323n/a return NULL;
1324n/a
1325n/a if (PyType_Ready(&OverlappedType) < 0)
1326n/a return NULL;
1327n/a
1328n/a m = PyModule_Create(&overlapped_module);
1329n/a if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
1330n/a return NULL;
1331n/a
1332n/a d = PyModule_GetDict(m);
1333n/a
1334n/a WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1335n/a WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1336n/a WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1337n/a WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1338n/a WINAPI_CONSTANT(F_DWORD, INFINITE);
1339n/a WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1340n/a WINAPI_CONSTANT(F_HANDLE, NULL);
1341n/a WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
1342n/a WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
1343n/a WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
1344n/a
1345n/a return m;
1346n/a}