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