summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2013-09-04 07:52:35 -0700
committerGuido van Rossum <guido@python.org>2013-09-04 07:52:35 -0700
commit771fb9454febf259603c681673633d7d48ec5274 (patch)
tree8046df8c33f97a36e6faa9b50582b03c7a08ecb2
parent547e8accb5290b5e513a09213c3b61bfd34316ff (diff)
downloadtrollius-proactor.tar.gz
Close ancient proactor branch.proactor
-rw-r--r--overlapped.c1994
-rw-r--r--setup.cfg2
-rw-r--r--setup.py8
3 files changed, 1002 insertions, 1002 deletions
diff --git a/overlapped.c b/overlapped.c
index 8b4bdc1..1e7d611 100644
--- a/overlapped.c
+++ b/overlapped.c
@@ -1,997 +1,997 @@
-/*
- * Support for overlapped IO
- *
- * Some code borrowed from Modules/_winapi.c of CPython
- */
-
-/* XXX check overflow and DWORD <-> Py_ssize_t conversions
- Check itemsize */
-
-#include "Python.h"
-#include "structmember.h"
-
-#define WINDOWS_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <mswsock.h>
-
-#if defined(MS_WIN32) && !defined(MS_WIN64)
-# define F_POINTER "k"
-# define T_POINTER T_ULONG
-#else
-# define F_POINTER "K"
-# define T_POINTER T_ULONGLONG
-#endif
-
-#define F_HANDLE F_POINTER
-#define F_ULONG_PTR F_POINTER
-#define F_DWORD "k"
-#define F_BOOL "i"
-#define F_UINT "I"
-
-#define T_HANDLE T_POINTER
-
-enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_WRITE, TYPE_ACCEPT,
- TYPE_CONNECT, TYPE_DISCONNECT};
-
-/*
- * Some functions should be loaded at runtime
- */
-
-static LPFN_ACCEPTEX Py_AcceptEx = NULL;
-static LPFN_CONNECTEX Py_ConnectEx = NULL;
-static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
-static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
-
-#define GET_WSA_POINTER(s, x) \
- (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
- &Guid##x, sizeof(Guid##x), &Py_##x, \
- sizeof(Py_##x), &dwBytes, NULL, NULL))
-
-static int
-initialize_function_pointers(void)
-{
- GUID GuidAcceptEx = WSAID_ACCEPTEX;
- GUID GuidConnectEx = WSAID_CONNECTEX;
- GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
- HINSTANCE hKernel32;
- SOCKET s;
- DWORD dwBytes;
-
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s == INVALID_SOCKET) {
- PyErr_SetFromWindowsErr(WSAGetLastError());
- return -1;
- }
-
- if (!GET_WSA_POINTER(s, AcceptEx) ||
- !GET_WSA_POINTER(s, ConnectEx) ||
- !GET_WSA_POINTER(s, DisconnectEx))
- {
- closesocket(s);
- PyErr_SetFromWindowsErr(WSAGetLastError());
- return -1;
- }
-
- closesocket(s);
-
- /* On WinXP we will have Py_CancelIoEx == NULL */
- hKernel32 = GetModuleHandle("KERNEL32");
- *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
- return 0;
-}
-
-/*
- * Completion port stuff
- */
-
-PyDoc_STRVAR(
- CreateIoCompletionPort_doc,
- "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
- "Create a completion port or register a handle with a port.");
-
-static PyObject *
-overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
-{
- HANDLE FileHandle;
- HANDLE ExistingCompletionPort;
- ULONG_PTR CompletionKey;
- DWORD NumberOfConcurrentThreads;
- HANDLE ret;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
- &FileHandle, &ExistingCompletionPort, &CompletionKey,
- &NumberOfConcurrentThreads))
- return NULL;
-
- Py_BEGIN_ALLOW_THREADS
- ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
- CompletionKey, NumberOfConcurrentThreads);
- Py_END_ALLOW_THREADS
-
- if (ret == NULL)
- return PyErr_SetFromWindowsErr(0);
- return Py_BuildValue(F_HANDLE, ret);
-}
-
-PyDoc_STRVAR(
- GetQueuedCompletionStatus_doc,
- "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
- "Get a message from completion port. Wait for up to msecs milliseconds.");
-
-static PyObject *
-overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
-{
- HANDLE CompletionPort;
- DWORD Milliseconds;
- DWORD NumberOfBytes;
- ULONG_PTR CompletionKey;
- OVERLAPPED *Overlapped = NULL;
- DWORD err;
- BOOL ret;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
- &CompletionPort, &Milliseconds))
- return NULL;
-
- Py_BEGIN_ALLOW_THREADS
- ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
- &CompletionKey, &Overlapped, Milliseconds);
- Py_END_ALLOW_THREADS
-
- err = ret ? ERROR_SUCCESS : GetLastError();
- if (Overlapped == NULL) {
- if (err == WAIT_TIMEOUT)
- Py_RETURN_NONE;
- else
- return PyErr_SetFromWindowsErr(err);
- }
- return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
- err, NumberOfBytes, CompletionKey, Overlapped);
-}
-
-PyDoc_STRVAR(
- PostQueuedCompletionStatus_doc,
- "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
- "Post a message to completion port.");
-
-static PyObject *
-overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
-{
- HANDLE CompletionPort;
- DWORD NumberOfBytes;
- ULONG_PTR CompletionKey;
- OVERLAPPED *Overlapped;
- BOOL ret;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
- &CompletionPort, &NumberOfBytes, &CompletionKey,
- &Overlapped))
- return NULL;
-
- Py_BEGIN_ALLOW_THREADS
- ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
- CompletionKey, Overlapped);
- Py_END_ALLOW_THREADS
-
- if (!ret)
- return PyErr_SetFromWindowsErr(0);
- Py_RETURN_NONE;
-}
-
-/*
- * Bind socket handle to local port without doing slow getaddrinfo()
- */
-
-PyDoc_STRVAR(
- BindLocal_doc,
- "BindLocal(handle, length_of_address_tuple) -> None\n\n"
- "Bind a socket handle to an arbitrary local port.\n"
- "If length_of_address_tuple is 2 then an AF_INET address is used.\n"
- "If length_of_address_tuple is 4 then an AF_INET6 address is used.");
-
-static PyObject *
-overlapped_BindLocal(PyObject *self, PyObject *args)
-{
- SOCKET Socket;
- int TupleLength;
- BOOL ret;
-
- if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &TupleLength))
- return NULL;
-
- if (TupleLength == 2) {
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.S_un.S_addr = INADDR_ANY;
- ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
- } else if (TupleLength == 4) {
- struct sockaddr_in6 addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_port = 0;
- addr.sin6_addr = in6addr_any;
- ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
- } else {
- PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
- return NULL;
- }
-
- if (!ret)
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
- Py_RETURN_NONE;
-}
-
-/*
- * Set notification mode for the handle
- */
-
-PyDoc_STRVAR(
- SetFileCompletionNotificationModes_doc,
- "SetFileCompletionNotificationModes(FileHandle, Flags) -> None\n\n"
- "Set whether notification happens if operation succeeds without blocking");
-
-static PyObject *
-overlapped_SetFileCompletionNotificationModes(PyObject *self, PyObject *args)
-{
- HANDLE FileHandle;
- UCHAR Flags;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_BOOL, &FileHandle, &Flags))
- return NULL;
-
- if (!SetFileCompletionNotificationModes(FileHandle, Flags))
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
-
- Py_RETURN_NONE;
-}
-
-/*
- * A Python object wrapping an OVERLAPPED structure and other useful data
- * for overlapped I/O
- */
-
-PyDoc_STRVAR(
- Overlapped_doc,
- "Overlapped object");
-
-typedef struct {
- PyObject_HEAD
- OVERLAPPED overlapped;
- /* For convenience, we store the file handle too */
- HANDLE handle;
- /* Error returned by last method call */
- DWORD error;
- /* Type of operation */
- DWORD type;
- /* Buffer used for reading (optional) */
- PyObject *read_buffer;
- /* Buffer used for writing (optional) */
- Py_buffer write_buffer;
-} OverlappedObject;
-
-
-static PyObject *
-Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- OverlappedObject *self;
- HANDLE event = INVALID_HANDLE_VALUE;
- static char *kwlist[] = {"event", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
- return NULL;
-
- if (event == INVALID_HANDLE_VALUE) {
- event = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (event == NULL)
- return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
- }
-
- self = PyObject_New(OverlappedObject, type);
- if (self == NULL) {
- if (event != NULL)
- CloseHandle(event);
- return NULL;
- }
-
- self->handle = NULL;
- self->error = 0;
- self->type = TYPE_NONE;
- self->read_buffer = NULL;
- memset(&self->overlapped, 0, sizeof(OVERLAPPED));
- memset(&self->write_buffer, 0, sizeof(Py_buffer));
- if (event)
- self->overlapped.hEvent = event;
- return (PyObject *)self;
-}
-
-static void
-Overlapped_dealloc(OverlappedObject *self)
-{
- DWORD bytes;
- DWORD olderr = GetLastError();
- BOOL wait = FALSE;
- BOOL ret;
-
- if (!HasOverlappedIoCompleted(&self->overlapped) &&
- self->type != TYPE_NOT_STARTED)
- {
- if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
- wait = TRUE;
-
- Py_BEGIN_ALLOW_THREADS
- ret = GetOverlappedResult(self->handle, &self->overlapped,
- &bytes, wait);
- Py_END_ALLOW_THREADS
-
- switch (ret ? ERROR_SUCCESS : GetLastError()) {
- case ERROR_SUCCESS:
- case ERROR_NOT_FOUND:
- case ERROR_OPERATION_ABORTED:
- break;
- default:
- PyErr_SetString(
- PyExc_RuntimeError,
- "I/O operations still in flight while destroying "
- "Overlapped object, the process may crash");
- PyErr_WriteUnraisable(NULL);
- }
- }
-
- if (self->overlapped.hEvent != NULL)
- CloseHandle(self->overlapped.hEvent);
-
- if (self->write_buffer.obj)
- PyBuffer_Release(&self->write_buffer);
-
- Py_CLEAR(self->read_buffer);
- PyObject_Del(self);
- SetLastError(olderr);
-}
-
-PyDoc_STRVAR(
- Overlapped_cancel_doc,
- "cancel() -> None\n\n"
- "Cancel overlapped operation");
-
-static PyObject *
-Overlapped_cancel(OverlappedObject *self)
-{
- BOOL ret = TRUE;
-
- if (self->type == TYPE_NOT_STARTED)
- Py_RETURN_NONE;
-
- if (!HasOverlappedIoCompleted(&self->overlapped)) {
- Py_BEGIN_ALLOW_THREADS
- if (Py_CancelIoEx)
- ret = Py_CancelIoEx(self->handle, &self->overlapped);
- else
- ret = CancelIo(self->handle);
- Py_END_ALLOW_THREADS
- }
-
- /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
- if (!ret && GetLastError() != ERROR_NOT_FOUND)
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(
- Overlapped_getresult_doc,
- "getresult(wait=False) -> result\n\n"
- "Retrieve result of operation. If wait is true then it blocks\n"
- "until the operation is finished. If wait is false and the\n"
- "operation is still pending then an error is raised.");
-
-static PyObject *
-Overlapped_getresult(OverlappedObject *self, PyObject *args)
-{
- BOOL wait = FALSE;
- DWORD transferred = 0;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
- return NULL;
-
- if (self->type == TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
- return NULL;
- }
-
- if (self->type == TYPE_NOT_STARTED) {
- PyErr_SetString(PyExc_ValueError, "operation failed to start");
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
- wait);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : GetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_MORE_DATA:
- break;
- case ERROR_BROKEN_PIPE:
- if (self->read_buffer != NULL)
- break;
- /* fall through */
- default:
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-
- switch (self->type) {
- case TYPE_READ:
- assert(PyBytes_CheckExact(self->read_buffer));
- if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
- _PyBytes_Resize(&self->read_buffer, transferred))
- return NULL;
- Py_INCREF(self->read_buffer);
- return self->read_buffer;
- case TYPE_ACCEPT:
- case TYPE_CONNECT:
- case TYPE_DISCONNECT:
- Py_RETURN_NONE;
- default:
- return PyLong_FromUnsignedLong((unsigned long) transferred);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_ReadFile_doc,
- "ReadFile(handle, size) -> Overlapped[message]\n\n"
- "Start overlapped read");
-
-static PyObject *
-Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
-{
- HANDLE handle;
- DWORD size;
- DWORD nread;
- PyObject *buf;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
-#if SIZEOF_SIZE_T <= SIZEOF_LONG
- size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
-#endif
- buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
- if (buf == NULL)
- return NULL;
-
- self->type = TYPE_READ;
- self->handle = handle;
- self->read_buffer = buf;
-
- Py_BEGIN_ALLOW_THREADS
- ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
- &self->overlapped);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : GetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_MORE_DATA:
- case ERROR_IO_PENDING:
- case ERROR_BROKEN_PIPE:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_WSARecv_doc,
- "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
- "Start overlapped receive");
-
-static PyObject *
-Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
-{
- HANDLE handle;
- DWORD size;
- DWORD flags;
- DWORD nread;
- PyObject *buf;
- WSABUF wsabuf;
- int ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_DWORD,
- &handle, &size, &flags))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
-#if SIZEOF_SIZE_T <= SIZEOF_LONG
- size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
-#endif
- buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
- if (buf == NULL)
- return NULL;
-
- self->type = TYPE_READ;
- self->handle = handle;
- self->read_buffer = buf;
- wsabuf.len = size;
- wsabuf.buf = PyBytes_AS_STRING(buf);
-
- Py_BEGIN_ALLOW_THREADS
- ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
- &self->overlapped, NULL);
- Py_END_ALLOW_THREADS
-
- self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_MORE_DATA:
- case ERROR_IO_PENDING:
- case ERROR_BROKEN_PIPE:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_WriteFile_doc,
- "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
- "Start overlapped write");
-
-static PyObject *
-Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
-{
- HANDLE handle;
- PyObject *bufobj;
- DWORD written;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
- if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
- return NULL;
-
-#if SIZEOF_SIZE_T > SIZEOF_LONG
- if (self->write_buffer.len > (Py_ssize_t)PY_ULONG_MAX) {
- PyBuffer_Release(&self->write_buffer);
- PyErr_SetString(PyExc_ValueError, "buffer to large");
- return NULL;
- }
-#endif
-
- self->type = TYPE_WRITE;
- self->handle = handle;
-
- Py_BEGIN_ALLOW_THREADS
- ret = WriteFile(handle, self->write_buffer.buf, self->write_buffer.len,
- &written, &self->overlapped);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : GetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_MORE_DATA:
- case ERROR_IO_PENDING:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_WSASend_doc,
- "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
- "Start overlapped send");
-
-static PyObject *
-Overlapped_WSASend(OverlappedObject *self, PyObject *args)
-{
- HANDLE handle;
- PyObject *bufobj;
- DWORD flags;
- DWORD written;
- WSABUF wsabuf;
- int ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
- &handle, &bufobj, &flags))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
- if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
- return NULL;
-
-#if SIZEOF_SIZE_T > SIZEOF_LONG
- if (self->write_buffer.len > (Py_ssize_t)PY_ULONG_MAX) {
- PyBuffer_Release(&self->write_buffer);
- PyErr_SetString(PyExc_ValueError, "buffer to large");
- return NULL;
- }
-#endif
-
- self->type = TYPE_WRITE;
- self->handle = handle;
- wsabuf.len = (DWORD)self->write_buffer.len;
- wsabuf.buf = self->write_buffer.buf;
-
- Py_BEGIN_ALLOW_THREADS
- ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
- &self->overlapped, NULL);
- Py_END_ALLOW_THREADS
-
- self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_MORE_DATA:
- case ERROR_IO_PENDING:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_AcceptEx_doc,
- "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
- "Start overlapped wait for client to connect");
-
-static PyObject *
-Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
-{
- SOCKET ListenSocket;
- SOCKET AcceptSocket;
- DWORD BytesReceived;
- DWORD size;
- PyObject *buf;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
- &ListenSocket, &AcceptSocket))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
- size = sizeof(struct sockaddr_in6) + 16;
- buf = PyBytes_FromStringAndSize(NULL, size*2);
- if (!buf)
- return NULL;
-
- self->type = TYPE_ACCEPT;
- self->handle = (HANDLE)ListenSocket;
- self->read_buffer = buf;
-
- Py_BEGIN_ALLOW_THREADS
- ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
- 0, size, size, &BytesReceived, &self->overlapped);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_IO_PENDING:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-
-static int
-parse_address(PyObject *obj, SOCKADDR *Address, int Length)
-{
- char *Host;
- unsigned short Port;
- unsigned long FlowInfo;
- unsigned long ScopeId;
-
- memset(Address, 0, Length);
-
- if (PyArg_ParseTuple(obj, "sH", &Host, &Port))
- {
- Address->sa_family = AF_INET;
- if (WSAStringToAddressA(Host, AF_INET, NULL, Address, &Length) < 0) {
- PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
- return -1;
- }
- ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
- return Length;
- }
- else if (PyArg_ParseTuple(obj, "sHkk", &Host, &Port, &FlowInfo, &ScopeId))
- {
- PyErr_Clear();
- Address->sa_family = AF_INET6;
- if (WSAStringToAddressA(Host, AF_INET6, NULL, Address, &Length) < 0) {
- PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
- return -1;
- }
- ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
- ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
- ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
- return Length;
- }
-
- return -1;
-}
-
-
-PyDoc_STRVAR(
- Overlapped_ConnectEx_doc,
- "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
- "Start overlapped connect. client_handle should be unbound.");
-
-static PyObject *
-Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
-{
- SOCKET ConnectSocket;
- PyObject *AddressObj;
- char AddressBuf[sizeof(struct sockaddr_in6)];
- SOCKADDR *Address = (SOCKADDR*)AddressBuf;
- int Length;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE "O", &ConnectSocket, &AddressObj))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
- Length = sizeof(AddressBuf);
- Length = parse_address(AddressObj, Address, Length);
- if (Length < 0)
- return NULL;
-
- self->type = TYPE_CONNECT;
- self->handle = (HANDLE)ConnectSocket;
-
- Py_BEGIN_ALLOW_THREADS
- ret = Py_ConnectEx(ConnectSocket, Address, Length,
- NULL, 0, NULL, &self->overlapped);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_IO_PENDING:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-PyDoc_STRVAR(
- Overlapped_DisconnectEx_doc,
- "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
- "Start overlapped connect. client_handle should be unbound.");
-
-static PyObject *
-Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
-{
- SOCKET Socket;
- DWORD flags;
- BOOL ret;
- DWORD err;
-
- if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
- return NULL;
-
- if (self->type != TYPE_NONE) {
- PyErr_SetString(PyExc_ValueError, "operation already attempted");
- return NULL;
- }
-
- self->type = TYPE_DISCONNECT;
- self->handle = (HANDLE)Socket;
-
- Py_BEGIN_ALLOW_THREADS
- ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
- Py_END_ALLOW_THREADS
-
- self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
- switch (err) {
- case ERROR_SUCCESS:
- case ERROR_IO_PENDING:
- Py_RETURN_NONE;
- default:
- self->type = TYPE_NOT_STARTED;
- return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
- }
-}
-
-static PyObject*
-Overlapped_getaddress(OverlappedObject *self)
-{
- return PyLong_FromVoidPtr(&self->overlapped);
-}
-
-static PyObject*
-Overlapped_getpending(OverlappedObject *self)
-{
- return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
- self->type != TYPE_NOT_STARTED);
-}
-
-static PyMethodDef Overlapped_methods[] = {
- {"getresult", (PyCFunction) Overlapped_getresult,
- METH_VARARGS, Overlapped_getresult_doc},
- {"cancel", (PyCFunction) Overlapped_cancel,
- METH_NOARGS, Overlapped_cancel_doc},
- {"ReadFile", (PyCFunction) Overlapped_ReadFile,
- METH_VARARGS, Overlapped_ReadFile_doc},
- {"WSARecv", (PyCFunction) Overlapped_WSARecv,
- METH_VARARGS, Overlapped_WSARecv_doc},
- {"WriteFile", (PyCFunction) Overlapped_WriteFile,
- METH_VARARGS, Overlapped_WriteFile_doc},
- {"WSASend", (PyCFunction) Overlapped_WSASend,
- METH_VARARGS, Overlapped_WSASend_doc},
- {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
- METH_VARARGS, Overlapped_AcceptEx_doc},
- {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
- METH_VARARGS, Overlapped_ConnectEx_doc},
- {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
- METH_VARARGS, Overlapped_DisconnectEx_doc},
- {NULL}
-};
-
-static PyMemberDef Overlapped_members[] = {
- {"error", T_ULONG,
- offsetof(OverlappedObject, error),
- READONLY, "Error from last operation"},
- {"event", T_HANDLE,
- offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
- READONLY, "Overlapped event handle"},
- {NULL}
-};
-
-static PyGetSetDef Overlapped_getsets[] = {
- {"address", (getter)Overlapped_getaddress, NULL,
- "Address of overlapped structure"},
- {"pending", (getter)Overlapped_getpending, NULL,
- "Whether the operation is pending"},
- {NULL},
-};
-
-PyTypeObject OverlappedType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- /* tp_name */ "_overlapped.Overlapped",
- /* tp_basicsize */ sizeof(OverlappedObject),
- /* tp_itemsize */ 0,
- /* tp_dealloc */ (destructor) Overlapped_dealloc,
- /* tp_print */ 0,
- /* tp_getattr */ 0,
- /* tp_setattr */ 0,
- /* tp_reserved */ 0,
- /* tp_repr */ 0,
- /* tp_as_number */ 0,
- /* tp_as_sequence */ 0,
- /* tp_as_mapping */ 0,
- /* tp_hash */ 0,
- /* tp_call */ 0,
- /* tp_str */ 0,
- /* tp_getattro */ 0,
- /* tp_setattro */ 0,
- /* tp_as_buffer */ 0,
- /* tp_flags */ Py_TPFLAGS_DEFAULT,
- /* tp_doc */ "OVERLAPPED structure wrapper",
- /* tp_traverse */ 0,
- /* tp_clear */ 0,
- /* tp_richcompare */ 0,
- /* tp_weaklistoffset */ 0,
- /* tp_iter */ 0,
- /* tp_iternext */ 0,
- /* tp_methods */ Overlapped_methods,
- /* tp_members */ Overlapped_members,
- /* tp_getset */ Overlapped_getsets,
- /* tp_base */ 0,
- /* tp_dict */ 0,
- /* tp_descr_get */ 0,
- /* tp_descr_set */ 0,
- /* tp_dictoffset */ 0,
- /* tp_init */ 0,
- /* tp_alloc */ 0,
- /* tp_new */ Overlapped_new,
-};
-
-static PyMethodDef overlapped_functions[] = {
- {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
- METH_VARARGS, CreateIoCompletionPort_doc},
- {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
- METH_VARARGS, GetQueuedCompletionStatus_doc},
- {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
- METH_VARARGS, PostQueuedCompletionStatus_doc},
- {"BindLocal", overlapped_BindLocal,
- METH_VARARGS, BindLocal_doc},
- {"SetFileCompletionNotificationModes",
- overlapped_SetFileCompletionNotificationModes,
- METH_VARARGS, SetFileCompletionNotificationModes_doc},
- {NULL}
-};
-
-static struct PyModuleDef overlapped_module = {
- PyModuleDef_HEAD_INIT,
- "_overlapped",
- NULL,
- -1,
- overlapped_functions,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-#define WINAPI_CONSTANT(fmt, con) \
- PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
-
-PyMODINIT_FUNC
-PyInit__overlapped(void)
-{
- PyObject *m, *d;
-
- /* Ensure WSAStartup() called before initializing function pointers */
- m = PyImport_ImportModule("_socket");
- if (!m)
- return NULL;
- Py_DECREF(m);
-
- if (initialize_function_pointers() < 0)
- return NULL;
-
- if (PyType_Ready(&OverlappedType) < 0)
- return NULL;
-
- m = PyModule_Create(&overlapped_module);
- if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
- return NULL;
-
- d = PyModule_GetDict(m);
-
- WINAPI_CONSTANT(F_DWORD, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
- WINAPI_CONSTANT(F_DWORD, INFINITE);
- WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
- WINAPI_CONSTANT(F_HANDLE, NULL);
- WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
- WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
- WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
-
- return m;
-}
+/*
+ * Support for overlapped IO
+ *
+ * Some code borrowed from Modules/_winapi.c of CPython
+ */
+
+/* XXX check overflow and DWORD <-> Py_ssize_t conversions
+ Check itemsize */
+
+#include "Python.h"
+#include "structmember.h"
+
+#define WINDOWS_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <mswsock.h>
+
+#if defined(MS_WIN32) && !defined(MS_WIN64)
+# define F_POINTER "k"
+# define T_POINTER T_ULONG
+#else
+# define F_POINTER "K"
+# define T_POINTER T_ULONGLONG
+#endif
+
+#define F_HANDLE F_POINTER
+#define F_ULONG_PTR F_POINTER
+#define F_DWORD "k"
+#define F_BOOL "i"
+#define F_UINT "I"
+
+#define T_HANDLE T_POINTER
+
+enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_WRITE, TYPE_ACCEPT,
+ TYPE_CONNECT, TYPE_DISCONNECT};
+
+/*
+ * Some functions should be loaded at runtime
+ */
+
+static LPFN_ACCEPTEX Py_AcceptEx = NULL;
+static LPFN_CONNECTEX Py_ConnectEx = NULL;
+static LPFN_DISCONNECTEX Py_DisconnectEx = NULL;
+static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
+
+#define GET_WSA_POINTER(s, x) \
+ (SOCKET_ERROR != WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, \
+ &Guid##x, sizeof(Guid##x), &Py_##x, \
+ sizeof(Py_##x), &dwBytes, NULL, NULL))
+
+static int
+initialize_function_pointers(void)
+{
+ GUID GuidAcceptEx = WSAID_ACCEPTEX;
+ GUID GuidConnectEx = WSAID_CONNECTEX;
+ GUID GuidDisconnectEx = WSAID_DISCONNECTEX;
+ HINSTANCE hKernel32;
+ SOCKET s;
+ DWORD dwBytes;
+
+ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ PyErr_SetFromWindowsErr(WSAGetLastError());
+ return -1;
+ }
+
+ if (!GET_WSA_POINTER(s, AcceptEx) ||
+ !GET_WSA_POINTER(s, ConnectEx) ||
+ !GET_WSA_POINTER(s, DisconnectEx))
+ {
+ closesocket(s);
+ PyErr_SetFromWindowsErr(WSAGetLastError());
+ return -1;
+ }
+
+ closesocket(s);
+
+ /* On WinXP we will have Py_CancelIoEx == NULL */
+ hKernel32 = GetModuleHandle("KERNEL32");
+ *(FARPROC *)&Py_CancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
+ return 0;
+}
+
+/*
+ * Completion port stuff
+ */
+
+PyDoc_STRVAR(
+ CreateIoCompletionPort_doc,
+ "CreateIoCompletionPort(handle, port, key, concurrency) -> port\n\n"
+ "Create a completion port or register a handle with a port.");
+
+static PyObject *
+overlapped_CreateIoCompletionPort(PyObject *self, PyObject *args)
+{
+ HANDLE FileHandle;
+ HANDLE ExistingCompletionPort;
+ ULONG_PTR CompletionKey;
+ DWORD NumberOfConcurrentThreads;
+ HANDLE ret;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_ULONG_PTR F_DWORD,
+ &FileHandle, &ExistingCompletionPort, &CompletionKey,
+ &NumberOfConcurrentThreads))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
+ CompletionKey, NumberOfConcurrentThreads);
+ Py_END_ALLOW_THREADS
+
+ if (ret == NULL)
+ return PyErr_SetFromWindowsErr(0);
+ return Py_BuildValue(F_HANDLE, ret);
+}
+
+PyDoc_STRVAR(
+ GetQueuedCompletionStatus_doc,
+ "GetQueuedCompletionStatus(port, msecs) -> (err, bytes, key, address)\n\n"
+ "Get a message from completion port. Wait for up to msecs milliseconds.");
+
+static PyObject *
+overlapped_GetQueuedCompletionStatus(PyObject *self, PyObject *args)
+{
+ HANDLE CompletionPort;
+ DWORD Milliseconds;
+ DWORD NumberOfBytes;
+ ULONG_PTR CompletionKey;
+ OVERLAPPED *Overlapped = NULL;
+ DWORD err;
+ BOOL ret;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD,
+ &CompletionPort, &Milliseconds))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = GetQueuedCompletionStatus(CompletionPort, &NumberOfBytes,
+ &CompletionKey, &Overlapped, Milliseconds);
+ Py_END_ALLOW_THREADS
+
+ err = ret ? ERROR_SUCCESS : GetLastError();
+ if (Overlapped == NULL) {
+ if (err == WAIT_TIMEOUT)
+ Py_RETURN_NONE;
+ else
+ return PyErr_SetFromWindowsErr(err);
+ }
+ return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
+ err, NumberOfBytes, CompletionKey, Overlapped);
+}
+
+PyDoc_STRVAR(
+ PostQueuedCompletionStatus_doc,
+ "PostQueuedCompletionStatus(port, bytes, key, address) -> None\n\n"
+ "Post a message to completion port.");
+
+static PyObject *
+overlapped_PostQueuedCompletionStatus(PyObject *self, PyObject *args)
+{
+ HANDLE CompletionPort;
+ DWORD NumberOfBytes;
+ ULONG_PTR CompletionKey;
+ OVERLAPPED *Overlapped;
+ BOOL ret;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_ULONG_PTR F_POINTER,
+ &CompletionPort, &NumberOfBytes, &CompletionKey,
+ &Overlapped))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
+ CompletionKey, Overlapped);
+ Py_END_ALLOW_THREADS
+
+ if (!ret)
+ return PyErr_SetFromWindowsErr(0);
+ Py_RETURN_NONE;
+}
+
+/*
+ * Bind socket handle to local port without doing slow getaddrinfo()
+ */
+
+PyDoc_STRVAR(
+ BindLocal_doc,
+ "BindLocal(handle, length_of_address_tuple) -> None\n\n"
+ "Bind a socket handle to an arbitrary local port.\n"
+ "If length_of_address_tuple is 2 then an AF_INET address is used.\n"
+ "If length_of_address_tuple is 4 then an AF_INET6 address is used.");
+
+static PyObject *
+overlapped_BindLocal(PyObject *self, PyObject *args)
+{
+ SOCKET Socket;
+ int TupleLength;
+ BOOL ret;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE "i", &Socket, &TupleLength))
+ return NULL;
+
+ if (TupleLength == 2) {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ addr.sin_addr.S_un.S_addr = INADDR_ANY;
+ ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
+ } else if (TupleLength == 4) {
+ struct sockaddr_in6 addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = 0;
+ addr.sin6_addr = in6addr_any;
+ ret = bind(Socket, (SOCKADDR*)&addr, sizeof(addr)) != SOCKET_ERROR;
+ } else {
+ PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
+ return NULL;
+ }
+
+ if (!ret)
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+ Py_RETURN_NONE;
+}
+
+/*
+ * Set notification mode for the handle
+ */
+
+PyDoc_STRVAR(
+ SetFileCompletionNotificationModes_doc,
+ "SetFileCompletionNotificationModes(FileHandle, Flags) -> None\n\n"
+ "Set whether notification happens if operation succeeds without blocking");
+
+static PyObject *
+overlapped_SetFileCompletionNotificationModes(PyObject *self, PyObject *args)
+{
+ HANDLE FileHandle;
+ UCHAR Flags;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_BOOL, &FileHandle, &Flags))
+ return NULL;
+
+ if (!SetFileCompletionNotificationModes(FileHandle, Flags))
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * A Python object wrapping an OVERLAPPED structure and other useful data
+ * for overlapped I/O
+ */
+
+PyDoc_STRVAR(
+ Overlapped_doc,
+ "Overlapped object");
+
+typedef struct {
+ PyObject_HEAD
+ OVERLAPPED overlapped;
+ /* For convenience, we store the file handle too */
+ HANDLE handle;
+ /* Error returned by last method call */
+ DWORD error;
+ /* Type of operation */
+ DWORD type;
+ /* Buffer used for reading (optional) */
+ PyObject *read_buffer;
+ /* Buffer used for writing (optional) */
+ Py_buffer write_buffer;
+} OverlappedObject;
+
+
+static PyObject *
+Overlapped_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ OverlappedObject *self;
+ HANDLE event = INVALID_HANDLE_VALUE;
+ static char *kwlist[] = {"event", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|" F_HANDLE, kwlist, &event))
+ return NULL;
+
+ if (event == INVALID_HANDLE_VALUE) {
+ event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (event == NULL)
+ return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
+ }
+
+ self = PyObject_New(OverlappedObject, type);
+ if (self == NULL) {
+ if (event != NULL)
+ CloseHandle(event);
+ return NULL;
+ }
+
+ self->handle = NULL;
+ self->error = 0;
+ self->type = TYPE_NONE;
+ self->read_buffer = NULL;
+ memset(&self->overlapped, 0, sizeof(OVERLAPPED));
+ memset(&self->write_buffer, 0, sizeof(Py_buffer));
+ if (event)
+ self->overlapped.hEvent = event;
+ return (PyObject *)self;
+}
+
+static void
+Overlapped_dealloc(OverlappedObject *self)
+{
+ DWORD bytes;
+ DWORD olderr = GetLastError();
+ BOOL wait = FALSE;
+ BOOL ret;
+
+ if (!HasOverlappedIoCompleted(&self->overlapped) &&
+ self->type != TYPE_NOT_STARTED)
+ {
+ if (Py_CancelIoEx && Py_CancelIoEx(self->handle, &self->overlapped))
+ wait = TRUE;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = GetOverlappedResult(self->handle, &self->overlapped,
+ &bytes, wait);
+ Py_END_ALLOW_THREADS
+
+ switch (ret ? ERROR_SUCCESS : GetLastError()) {
+ case ERROR_SUCCESS:
+ case ERROR_NOT_FOUND:
+ case ERROR_OPERATION_ABORTED:
+ break;
+ default:
+ PyErr_SetString(
+ PyExc_RuntimeError,
+ "I/O operations still in flight while destroying "
+ "Overlapped object, the process may crash");
+ PyErr_WriteUnraisable(NULL);
+ }
+ }
+
+ if (self->overlapped.hEvent != NULL)
+ CloseHandle(self->overlapped.hEvent);
+
+ if (self->write_buffer.obj)
+ PyBuffer_Release(&self->write_buffer);
+
+ Py_CLEAR(self->read_buffer);
+ PyObject_Del(self);
+ SetLastError(olderr);
+}
+
+PyDoc_STRVAR(
+ Overlapped_cancel_doc,
+ "cancel() -> None\n\n"
+ "Cancel overlapped operation");
+
+static PyObject *
+Overlapped_cancel(OverlappedObject *self)
+{
+ BOOL ret = TRUE;
+
+ if (self->type == TYPE_NOT_STARTED)
+ Py_RETURN_NONE;
+
+ if (!HasOverlappedIoCompleted(&self->overlapped)) {
+ Py_BEGIN_ALLOW_THREADS
+ if (Py_CancelIoEx)
+ ret = Py_CancelIoEx(self->handle, &self->overlapped);
+ else
+ ret = CancelIo(self->handle);
+ Py_END_ALLOW_THREADS
+ }
+
+ /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
+ if (!ret && GetLastError() != ERROR_NOT_FOUND)
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(
+ Overlapped_getresult_doc,
+ "getresult(wait=False) -> result\n\n"
+ "Retrieve result of operation. If wait is true then it blocks\n"
+ "until the operation is finished. If wait is false and the\n"
+ "operation is still pending then an error is raised.");
+
+static PyObject *
+Overlapped_getresult(OverlappedObject *self, PyObject *args)
+{
+ BOOL wait = FALSE;
+ DWORD transferred = 0;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, "|" F_BOOL, &wait))
+ return NULL;
+
+ if (self->type == TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation not yet attempted");
+ return NULL;
+ }
+
+ if (self->type == TYPE_NOT_STARTED) {
+ PyErr_SetString(PyExc_ValueError, "operation failed to start");
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
+ wait);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : GetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ break;
+ case ERROR_BROKEN_PIPE:
+ if (self->read_buffer != NULL)
+ break;
+ /* fall through */
+ default:
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+
+ switch (self->type) {
+ case TYPE_READ:
+ assert(PyBytes_CheckExact(self->read_buffer));
+ if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
+ _PyBytes_Resize(&self->read_buffer, transferred))
+ return NULL;
+ Py_INCREF(self->read_buffer);
+ return self->read_buffer;
+ case TYPE_ACCEPT:
+ case TYPE_CONNECT:
+ case TYPE_DISCONNECT:
+ Py_RETURN_NONE;
+ default:
+ return PyLong_FromUnsignedLong((unsigned long) transferred);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_ReadFile_doc,
+ "ReadFile(handle, size) -> Overlapped[message]\n\n"
+ "Start overlapped read");
+
+static PyObject *
+Overlapped_ReadFile(OverlappedObject *self, PyObject *args)
+{
+ HANDLE handle;
+ DWORD size;
+ DWORD nread;
+ PyObject *buf;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &handle, &size))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+#if SIZEOF_SIZE_T <= SIZEOF_LONG
+ size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
+#endif
+ buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
+ if (buf == NULL)
+ return NULL;
+
+ self->type = TYPE_READ;
+ self->handle = handle;
+ self->read_buffer = buf;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
+ &self->overlapped);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : GetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ case ERROR_IO_PENDING:
+ case ERROR_BROKEN_PIPE:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_WSARecv_doc,
+ "RecvFile(handle, size, flags) -> Overlapped[message]\n\n"
+ "Start overlapped receive");
+
+static PyObject *
+Overlapped_WSARecv(OverlappedObject *self, PyObject *args)
+{
+ HANDLE handle;
+ DWORD size;
+ DWORD flags;
+ DWORD nread;
+ PyObject *buf;
+ WSABUF wsabuf;
+ int ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD F_DWORD,
+ &handle, &size, &flags))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+#if SIZEOF_SIZE_T <= SIZEOF_LONG
+ size = Py_MIN(size, (DWORD)PY_SSIZE_T_MAX);
+#endif
+ buf = PyBytes_FromStringAndSize(NULL, Py_MAX(size, 1));
+ if (buf == NULL)
+ return NULL;
+
+ self->type = TYPE_READ;
+ self->handle = handle;
+ self->read_buffer = buf;
+ wsabuf.len = size;
+ wsabuf.buf = PyBytes_AS_STRING(buf);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
+ &self->overlapped, NULL);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ case ERROR_IO_PENDING:
+ case ERROR_BROKEN_PIPE:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_WriteFile_doc,
+ "WriteFile(handle, buf) -> Overlapped[bytes_transferred]\n\n"
+ "Start overlapped write");
+
+static PyObject *
+Overlapped_WriteFile(OverlappedObject *self, PyObject *args)
+{
+ HANDLE handle;
+ PyObject *bufobj;
+ DWORD written;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE "O", &handle, &bufobj))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+ if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
+ return NULL;
+
+#if SIZEOF_SIZE_T > SIZEOF_LONG
+ if (self->write_buffer.len > (Py_ssize_t)PY_ULONG_MAX) {
+ PyBuffer_Release(&self->write_buffer);
+ PyErr_SetString(PyExc_ValueError, "buffer to large");
+ return NULL;
+ }
+#endif
+
+ self->type = TYPE_WRITE;
+ self->handle = handle;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = WriteFile(handle, self->write_buffer.buf, self->write_buffer.len,
+ &written, &self->overlapped);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : GetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_WSASend_doc,
+ "WSASend(handle, buf, flags) -> Overlapped[bytes_transferred]\n\n"
+ "Start overlapped send");
+
+static PyObject *
+Overlapped_WSASend(OverlappedObject *self, PyObject *args)
+{
+ HANDLE handle;
+ PyObject *bufobj;
+ DWORD flags;
+ DWORD written;
+ WSABUF wsabuf;
+ int ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE "O" F_DWORD,
+ &handle, &bufobj, &flags))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+ if (!PyArg_Parse(bufobj, "y*", &self->write_buffer))
+ return NULL;
+
+#if SIZEOF_SIZE_T > SIZEOF_LONG
+ if (self->write_buffer.len > (Py_ssize_t)PY_ULONG_MAX) {
+ PyBuffer_Release(&self->write_buffer);
+ PyErr_SetString(PyExc_ValueError, "buffer to large");
+ return NULL;
+ }
+#endif
+
+ self->type = TYPE_WRITE;
+ self->handle = handle;
+ wsabuf.len = (DWORD)self->write_buffer.len;
+ wsabuf.buf = self->write_buffer.buf;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = WSASend((SOCKET)handle, &wsabuf, 1, &written, flags,
+ &self->overlapped, NULL);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_AcceptEx_doc,
+ "AcceptEx(listen_handle, accept_handle) -> Overlapped[address_as_bytes]\n\n"
+ "Start overlapped wait for client to connect");
+
+static PyObject *
+Overlapped_AcceptEx(OverlappedObject *self, PyObject *args)
+{
+ SOCKET ListenSocket;
+ SOCKET AcceptSocket;
+ DWORD BytesReceived;
+ DWORD size;
+ PyObject *buf;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE,
+ &ListenSocket, &AcceptSocket))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+ size = sizeof(struct sockaddr_in6) + 16;
+ buf = PyBytes_FromStringAndSize(NULL, size*2);
+ if (!buf)
+ return NULL;
+
+ self->type = TYPE_ACCEPT;
+ self->handle = (HANDLE)ListenSocket;
+ self->read_buffer = buf;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = Py_AcceptEx(ListenSocket, AcceptSocket, PyBytes_AS_STRING(buf),
+ 0, size, size, &BytesReceived, &self->overlapped);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+
+static int
+parse_address(PyObject *obj, SOCKADDR *Address, int Length)
+{
+ char *Host;
+ unsigned short Port;
+ unsigned long FlowInfo;
+ unsigned long ScopeId;
+
+ memset(Address, 0, Length);
+
+ if (PyArg_ParseTuple(obj, "sH", &Host, &Port))
+ {
+ Address->sa_family = AF_INET;
+ if (WSAStringToAddressA(Host, AF_INET, NULL, Address, &Length) < 0) {
+ PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+ return -1;
+ }
+ ((SOCKADDR_IN*)Address)->sin_port = htons(Port);
+ return Length;
+ }
+ else if (PyArg_ParseTuple(obj, "sHkk", &Host, &Port, &FlowInfo, &ScopeId))
+ {
+ PyErr_Clear();
+ Address->sa_family = AF_INET6;
+ if (WSAStringToAddressA(Host, AF_INET6, NULL, Address, &Length) < 0) {
+ PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+ return -1;
+ }
+ ((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
+ ((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
+ ((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
+ return Length;
+ }
+
+ return -1;
+}
+
+
+PyDoc_STRVAR(
+ Overlapped_ConnectEx_doc,
+ "ConnectEx(client_handle, address_as_bytes) -> Overlapped[None]\n\n"
+ "Start overlapped connect. client_handle should be unbound.");
+
+static PyObject *
+Overlapped_ConnectEx(OverlappedObject *self, PyObject *args)
+{
+ SOCKET ConnectSocket;
+ PyObject *AddressObj;
+ char AddressBuf[sizeof(struct sockaddr_in6)];
+ SOCKADDR *Address = (SOCKADDR*)AddressBuf;
+ int Length;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE "O", &ConnectSocket, &AddressObj))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+ Length = sizeof(AddressBuf);
+ Length = parse_address(AddressObj, Address, Length);
+ if (Length < 0)
+ return NULL;
+
+ self->type = TYPE_CONNECT;
+ self->handle = (HANDLE)ConnectSocket;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = Py_ConnectEx(ConnectSocket, Address, Length,
+ NULL, 0, NULL, &self->overlapped);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+PyDoc_STRVAR(
+ Overlapped_DisconnectEx_doc,
+ "DisconnectEx(handle, flags) -> Overlapped[None]\n\n"
+ "Start overlapped connect. client_handle should be unbound.");
+
+static PyObject *
+Overlapped_DisconnectEx(OverlappedObject *self, PyObject *args)
+{
+ SOCKET Socket;
+ DWORD flags;
+ BOOL ret;
+ DWORD err;
+
+ if (!PyArg_ParseTuple(args, F_HANDLE F_DWORD, &Socket, &flags))
+ return NULL;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+ self->type = TYPE_DISCONNECT;
+ self->handle = (HANDLE)Socket;
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = Py_DisconnectEx(Socket, &self->overlapped, flags, 0);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
+ switch (err) {
+ case ERROR_SUCCESS:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+}
+
+static PyObject*
+Overlapped_getaddress(OverlappedObject *self)
+{
+ return PyLong_FromVoidPtr(&self->overlapped);
+}
+
+static PyObject*
+Overlapped_getpending(OverlappedObject *self)
+{
+ return PyBool_FromLong(!HasOverlappedIoCompleted(&self->overlapped) &&
+ self->type != TYPE_NOT_STARTED);
+}
+
+static PyMethodDef Overlapped_methods[] = {
+ {"getresult", (PyCFunction) Overlapped_getresult,
+ METH_VARARGS, Overlapped_getresult_doc},
+ {"cancel", (PyCFunction) Overlapped_cancel,
+ METH_NOARGS, Overlapped_cancel_doc},
+ {"ReadFile", (PyCFunction) Overlapped_ReadFile,
+ METH_VARARGS, Overlapped_ReadFile_doc},
+ {"WSARecv", (PyCFunction) Overlapped_WSARecv,
+ METH_VARARGS, Overlapped_WSARecv_doc},
+ {"WriteFile", (PyCFunction) Overlapped_WriteFile,
+ METH_VARARGS, Overlapped_WriteFile_doc},
+ {"WSASend", (PyCFunction) Overlapped_WSASend,
+ METH_VARARGS, Overlapped_WSASend_doc},
+ {"AcceptEx", (PyCFunction) Overlapped_AcceptEx,
+ METH_VARARGS, Overlapped_AcceptEx_doc},
+ {"ConnectEx", (PyCFunction) Overlapped_ConnectEx,
+ METH_VARARGS, Overlapped_ConnectEx_doc},
+ {"DisconnectEx", (PyCFunction) Overlapped_DisconnectEx,
+ METH_VARARGS, Overlapped_DisconnectEx_doc},
+ {NULL}
+};
+
+static PyMemberDef Overlapped_members[] = {
+ {"error", T_ULONG,
+ offsetof(OverlappedObject, error),
+ READONLY, "Error from last operation"},
+ {"event", T_HANDLE,
+ offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
+ READONLY, "Overlapped event handle"},
+ {NULL}
+};
+
+static PyGetSetDef Overlapped_getsets[] = {
+ {"address", (getter)Overlapped_getaddress, NULL,
+ "Address of overlapped structure"},
+ {"pending", (getter)Overlapped_getpending, NULL,
+ "Whether the operation is pending"},
+ {NULL},
+};
+
+PyTypeObject OverlappedType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* tp_name */ "_overlapped.Overlapped",
+ /* tp_basicsize */ sizeof(OverlappedObject),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor) Overlapped_dealloc,
+ /* tp_print */ 0,
+ /* tp_getattr */ 0,
+ /* tp_setattr */ 0,
+ /* tp_reserved */ 0,
+ /* tp_repr */ 0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ 0,
+ /* tp_call */ 0,
+ /* tp_str */ 0,
+ /* tp_getattro */ 0,
+ /* tp_setattro */ 0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT,
+ /* tp_doc */ "OVERLAPPED structure wrapper",
+ /* tp_traverse */ 0,
+ /* tp_clear */ 0,
+ /* tp_richcompare */ 0,
+ /* tp_weaklistoffset */ 0,
+ /* tp_iter */ 0,
+ /* tp_iternext */ 0,
+ /* tp_methods */ Overlapped_methods,
+ /* tp_members */ Overlapped_members,
+ /* tp_getset */ Overlapped_getsets,
+ /* tp_base */ 0,
+ /* tp_dict */ 0,
+ /* tp_descr_get */ 0,
+ /* tp_descr_set */ 0,
+ /* tp_dictoffset */ 0,
+ /* tp_init */ 0,
+ /* tp_alloc */ 0,
+ /* tp_new */ Overlapped_new,
+};
+
+static PyMethodDef overlapped_functions[] = {
+ {"CreateIoCompletionPort", overlapped_CreateIoCompletionPort,
+ METH_VARARGS, CreateIoCompletionPort_doc},
+ {"GetQueuedCompletionStatus", overlapped_GetQueuedCompletionStatus,
+ METH_VARARGS, GetQueuedCompletionStatus_doc},
+ {"PostQueuedCompletionStatus", overlapped_PostQueuedCompletionStatus,
+ METH_VARARGS, PostQueuedCompletionStatus_doc},
+ {"BindLocal", overlapped_BindLocal,
+ METH_VARARGS, BindLocal_doc},
+ {"SetFileCompletionNotificationModes",
+ overlapped_SetFileCompletionNotificationModes,
+ METH_VARARGS, SetFileCompletionNotificationModes_doc},
+ {NULL}
+};
+
+static struct PyModuleDef overlapped_module = {
+ PyModuleDef_HEAD_INIT,
+ "_overlapped",
+ NULL,
+ -1,
+ overlapped_functions,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+#define WINAPI_CONSTANT(fmt, con) \
+ PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
+
+PyMODINIT_FUNC
+PyInit__overlapped(void)
+{
+ PyObject *m, *d;
+
+ /* Ensure WSAStartup() called before initializing function pointers */
+ m = PyImport_ImportModule("_socket");
+ if (!m)
+ return NULL;
+ Py_DECREF(m);
+
+ if (initialize_function_pointers() < 0)
+ return NULL;
+
+ if (PyType_Ready(&OverlappedType) < 0)
+ return NULL;
+
+ m = PyModule_Create(&overlapped_module);
+ if (PyModule_AddObject(m, "Overlapped", (PyObject *)&OverlappedType) < 0)
+ return NULL;
+
+ d = PyModule_GetDict(m);
+
+ WINAPI_CONSTANT(F_DWORD, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
+ WINAPI_CONSTANT(F_DWORD, INFINITE);
+ WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
+ WINAPI_CONSTANT(F_HANDLE, NULL);
+ WINAPI_CONSTANT(F_DWORD, SO_UPDATE_ACCEPT_CONTEXT);
+ WINAPI_CONSTANT(F_DWORD, SO_UPDATE_CONNECT_CONTEXT);
+ WINAPI_CONSTANT(F_DWORD, TF_REUSE_SOCKET);
+
+ return m;
+}
diff --git a/setup.cfg b/setup.cfg
index 2754e2b..ac4dda1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,2 @@
-[build_ext]
+[build_ext]
inplace=1 \ No newline at end of file
diff --git a/setup.py b/setup.py
index ff70754..67b037c 100644
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,4 @@
-from distutils.core import setup, Extension
-
-ext = Extension('_overlapped', ['overlapped.c'], libraries=['ws2_32'])
-setup(name='_overlapped', ext_modules=[ext])
+from distutils.core import setup, Extension
+
+ext = Extension('_overlapped', ['overlapped.c'], libraries=['ws2_32'])
+setup(name='_overlapped', ext_modules=[ext])