2013-10-17 22:40:50 +02:00
|
|
|
/*
|
|
|
|
* 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"
|
2020-04-15 02:35:41 +02:00
|
|
|
#include "structmember.h" // PyMemberDef
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[python input]
|
2022-07-29 00:09:46 +02:00
|
|
|
class pointer_converter(CConverter):
|
2020-07-10 19:43:37 +02:00
|
|
|
format_unit = '"F_POINTER"'
|
|
|
|
|
2022-07-29 00:09:46 +02:00
|
|
|
def parse_arg(self, argname, displayname):
|
|
|
|
return """
|
|
|
|
{paramname} = PyLong_AsVoidPtr({argname});
|
|
|
|
if (!{paramname} && PyErr_Occurred()) {{{{
|
|
|
|
goto exit;
|
|
|
|
}}}}
|
|
|
|
""".format(argname=argname, paramname=self.parser_name)
|
|
|
|
|
|
|
|
class OVERLAPPED_converter(pointer_converter):
|
|
|
|
type = 'OVERLAPPED *'
|
|
|
|
|
|
|
|
class HANDLE_converter(pointer_converter):
|
2020-07-10 19:43:37 +02:00
|
|
|
type = 'HANDLE'
|
|
|
|
|
2022-07-29 00:09:46 +02:00
|
|
|
class ULONG_PTR_converter(pointer_converter):
|
2020-07-10 19:43:37 +02:00
|
|
|
type = 'ULONG_PTR'
|
|
|
|
|
2022-08-01 18:30:15 +02:00
|
|
|
def parse_arg(self, argname, displayname):
|
|
|
|
return """
|
|
|
|
{paramname} = (uintptr_t)PyLong_AsVoidPtr({argname});
|
|
|
|
if (!{paramname} && PyErr_Occurred()) {{{{
|
|
|
|
goto exit;
|
|
|
|
}}}}
|
|
|
|
""".format(argname=argname, paramname=self.parser_name)
|
|
|
|
|
2022-07-29 00:09:46 +02:00
|
|
|
class DWORD_converter(unsigned_long_converter):
|
2020-07-10 19:43:37 +02:00
|
|
|
type = 'DWORD'
|
|
|
|
|
2022-07-29 00:09:46 +02:00
|
|
|
class BOOL_converter(int_converter):
|
2020-07-10 19:43:37 +02:00
|
|
|
type = 'BOOL'
|
|
|
|
[python start generated code]*/
|
2022-08-01 18:30:15 +02:00
|
|
|
/*[python end generated code: output=da39a3ee5e6b4b0d input=8a07ea3018f4cec8]*/
|
2020-07-10 19:43:37 +02:00
|
|
|
|
|
|
|
/*[clinic input]
|
|
|
|
module _overlapped
|
|
|
|
class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType"
|
|
|
|
[clinic start generated code]*/
|
|
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=92e5a799db35b96c]*/
|
|
|
|
|
|
|
|
|
2017-10-19 21:46:40 +02:00
|
|
|
enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
|
|
|
|
TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
|
2019-05-28 11:52:15 +02:00
|
|
|
TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
|
2022-03-13 17:42:29 +01:00
|
|
|
TYPE_WRITE_TO, TYPE_READ_FROM_INTO};
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
union {
|
2017-10-19 21:46:40 +02:00
|
|
|
/* Buffer allocated by us: TYPE_READ and TYPE_ACCEPT */
|
|
|
|
PyObject *allocated_buffer;
|
2019-05-28 11:52:15 +02:00
|
|
|
/* Buffer passed by the user: TYPE_WRITE, TYPE_WRITE_TO, and TYPE_READINTO */
|
2017-10-19 21:46:40 +02:00
|
|
|
Py_buffer user_buffer;
|
2019-05-28 11:52:15 +02:00
|
|
|
|
|
|
|
/* Data used for reading from a connectionless socket:
|
|
|
|
TYPE_READ_FROM */
|
|
|
|
struct {
|
|
|
|
// A (buffer, (host, port)) tuple
|
|
|
|
PyObject *result;
|
|
|
|
// The actual read buffer
|
|
|
|
PyObject *allocated_buffer;
|
|
|
|
struct sockaddr_in6 address;
|
|
|
|
int address_length;
|
|
|
|
} read_from;
|
2022-03-13 17:42:29 +01:00
|
|
|
|
|
|
|
/* Data used for reading from a connectionless socket:
|
|
|
|
TYPE_READ_FROM_INTO */
|
|
|
|
struct {
|
|
|
|
// A (number of bytes read, (host, port)) tuple
|
|
|
|
PyObject* result;
|
|
|
|
/* Buffer passed by the user */
|
2022-03-13 22:28:45 +01:00
|
|
|
Py_buffer user_buffer;
|
2022-03-13 17:42:29 +01:00
|
|
|
struct sockaddr_in6 address;
|
|
|
|
int address_length;
|
|
|
|
} read_from_into;
|
2013-10-17 22:40:50 +02:00
|
|
|
};
|
|
|
|
} OverlappedObject;
|
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
|
2022-03-13 22:28:45 +01:00
|
|
|
static inline void
|
|
|
|
steal_buffer(Py_buffer * dst, Py_buffer * src)
|
|
|
|
{
|
|
|
|
memcpy(dst, src, sizeof(Py_buffer));
|
|
|
|
memset(src, 0, sizeof(Py_buffer));
|
|
|
|
}
|
|
|
|
|
2013-10-17 22:40:50 +02:00
|
|
|
/*
|
|
|
|
* Map Windows error codes to subclasses of OSError
|
|
|
|
*/
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
SetFromWindowsErr(DWORD err)
|
|
|
|
{
|
|
|
|
PyObject *exception_type;
|
|
|
|
|
|
|
|
if (err == 0)
|
|
|
|
err = GetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_CONNECTION_REFUSED:
|
|
|
|
exception_type = PyExc_ConnectionRefusedError;
|
|
|
|
break;
|
|
|
|
case ERROR_CONNECTION_ABORTED:
|
|
|
|
exception_type = PyExc_ConnectionAbortedError;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
exception_type = PyExc_OSError;
|
|
|
|
}
|
|
|
|
return PyErr_SetExcFromWindowsErr(exception_type, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2018-02-25 17:32:14 +01:00
|
|
|
static LPFN_TRANSMITFILE Py_TransmitFile = NULL;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
#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;
|
2018-02-25 17:32:14 +01:00
|
|
|
GUID GuidTransmitFile = WSAID_TRANSMITFILE;
|
2013-10-17 22:40:50 +02:00
|
|
|
SOCKET s;
|
|
|
|
DWORD dwBytes;
|
|
|
|
|
2022-03-13 22:28:45 +01:00
|
|
|
if (Py_AcceptEx != NULL &&
|
|
|
|
Py_ConnectEx != NULL &&
|
|
|
|
Py_DisconnectEx != NULL &&
|
|
|
|
Py_TransmitFile != NULL)
|
|
|
|
{
|
|
|
|
// All function pointers are initialized already
|
|
|
|
// by previous module import
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-17 22:40:50 +02:00
|
|
|
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
if (s == INVALID_SOCKET) {
|
|
|
|
SetFromWindowsErr(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GET_WSA_POINTER(s, AcceptEx) ||
|
|
|
|
!GET_WSA_POINTER(s, ConnectEx) ||
|
2018-02-25 17:32:14 +01:00
|
|
|
!GET_WSA_POINTER(s, DisconnectEx) ||
|
|
|
|
!GET_WSA_POINTER(s, TransmitFile))
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
closesocket(s);
|
|
|
|
SetFromWindowsErr(WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
closesocket(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Completion port stuff
|
|
|
|
*/
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.CreateIoCompletionPort
|
|
|
|
|
|
|
|
handle as FileHandle: HANDLE
|
|
|
|
port as ExistingCompletionPort: HANDLE
|
|
|
|
key as CompletionKey: ULONG_PTR
|
|
|
|
concurrency as NumberOfConcurrentThreads: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Create a completion port or register a handle with a port.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_CreateIoCompletionPort_impl(PyObject *module, HANDLE FileHandle,
|
|
|
|
HANDLE ExistingCompletionPort,
|
|
|
|
ULONG_PTR CompletionKey,
|
|
|
|
DWORD NumberOfConcurrentThreads)
|
|
|
|
/*[clinic end generated code: output=24ede2b0f05e5433 input=847bae4d0efe1976]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
HANDLE ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = CreateIoCompletionPort(FileHandle, ExistingCompletionPort,
|
|
|
|
CompletionKey, NumberOfConcurrentThreads);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (ret == NULL)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
return Py_BuildValue(F_HANDLE, ret);
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.GetQueuedCompletionStatus
|
|
|
|
|
|
|
|
port as CompletionPort: HANDLE
|
|
|
|
msecs as Milliseconds: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Get a message from completion port.
|
|
|
|
|
|
|
|
Wait for up to msecs milliseconds.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_GetQueuedCompletionStatus_impl(PyObject *module,
|
|
|
|
HANDLE CompletionPort,
|
|
|
|
DWORD Milliseconds)
|
|
|
|
/*[clinic end generated code: output=68314171628dddb7 input=94a042d14c4f6410]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
DWORD NumberOfBytes = 0;
|
|
|
|
ULONG_PTR CompletionKey = 0;
|
|
|
|
OVERLAPPED *Overlapped = NULL;
|
|
|
|
DWORD err;
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
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 SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
return Py_BuildValue(F_DWORD F_DWORD F_ULONG_PTR F_POINTER,
|
|
|
|
err, NumberOfBytes, CompletionKey, Overlapped);
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.PostQueuedCompletionStatus
|
|
|
|
|
|
|
|
port as CompletionPort: HANDLE
|
|
|
|
bytes as NumberOfBytes: DWORD
|
|
|
|
key as CompletionKey: ULONG_PTR
|
|
|
|
address as Overlapped: OVERLAPPED
|
|
|
|
/
|
|
|
|
|
|
|
|
Post a message to completion port.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_PostQueuedCompletionStatus_impl(PyObject *module,
|
|
|
|
HANDLE CompletionPort,
|
|
|
|
DWORD NumberOfBytes,
|
|
|
|
ULONG_PTR CompletionKey,
|
|
|
|
OVERLAPPED *Overlapped)
|
|
|
|
/*[clinic end generated code: output=93e73f2933a43e9e input=e936202d87937aca]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = PostQueuedCompletionStatus(CompletionPort, NumberOfBytes,
|
|
|
|
CompletionKey, Overlapped);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2013-10-30 22:44:05 +01:00
|
|
|
/*
|
|
|
|
* Wait for a handle
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct PostCallbackData {
|
|
|
|
HANDLE CompletionPort;
|
|
|
|
LPOVERLAPPED Overlapped;
|
|
|
|
};
|
|
|
|
|
|
|
|
static VOID CALLBACK
|
2020-07-15 20:43:00 +02:00
|
|
|
PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
|
|
|
|
|
|
|
|
PostQueuedCompletionStatus(p->CompletionPort, TimerOrWaitFired,
|
|
|
|
0, p->Overlapped);
|
|
|
|
/* ignore possible error! */
|
2016-03-16 23:25:02 +01:00
|
|
|
PyMem_RawFree(p);
|
2013-10-30 22:44:05 +01:00
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.RegisterWaitWithQueue
|
|
|
|
|
|
|
|
Object: HANDLE
|
|
|
|
CompletionPort: HANDLE
|
|
|
|
Overlapped: OVERLAPPED
|
|
|
|
Timeout as Milliseconds: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Register wait for Object; when complete CompletionPort is notified.
|
|
|
|
[clinic start generated code]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
|
|
|
|
HANDLE CompletionPort,
|
|
|
|
OVERLAPPED *Overlapped,
|
|
|
|
DWORD Milliseconds)
|
|
|
|
/*[clinic end generated code: output=c2ace732e447fe45 input=2dd4efee44abe8ee]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
HANDLE NewWaitObject;
|
2020-07-10 19:43:37 +02:00
|
|
|
struct PostCallbackData data = {CompletionPort, Overlapped}, *pdata;
|
2013-10-30 22:44:05 +01:00
|
|
|
|
2016-03-16 23:25:02 +01:00
|
|
|
/* Use PyMem_RawMalloc() rather than PyMem_Malloc(), since
|
|
|
|
PostToQueueCallback() will call PyMem_Free() from a new C thread
|
|
|
|
which doesn't hold the GIL. */
|
|
|
|
pdata = PyMem_RawMalloc(sizeof(struct PostCallbackData));
|
2013-10-30 22:44:05 +01:00
|
|
|
if (pdata == NULL)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
|
|
|
|
*pdata = data;
|
|
|
|
|
|
|
|
if (!RegisterWaitForSingleObject(
|
2020-07-15 20:43:00 +02:00
|
|
|
&NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
|
2013-10-30 22:44:05 +01:00
|
|
|
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
|
|
|
|
{
|
2016-03-16 23:25:02 +01:00
|
|
|
PyMem_RawFree(pdata);
|
2013-10-30 22:44:05 +01:00
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Py_BuildValue(F_HANDLE, NewWaitObject);
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.UnregisterWait
|
|
|
|
|
|
|
|
WaitHandle: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Unregister wait handle.
|
|
|
|
[clinic start generated code]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_UnregisterWait_impl(PyObject *module, HANDLE WaitHandle)
|
|
|
|
/*[clinic end generated code: output=ec90cd955a9a617d input=a56709544cb2df0f]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = UnregisterWait(WaitHandle);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.UnregisterWaitEx
|
|
|
|
|
|
|
|
WaitHandle: HANDLE
|
|
|
|
Event: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Unregister wait handle.
|
|
|
|
[clinic start generated code]*/
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 23:39:51 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_UnregisterWaitEx_impl(PyObject *module, HANDLE WaitHandle,
|
|
|
|
HANDLE Event)
|
|
|
|
/*[clinic end generated code: output=2e3d84c1d5f65b92 input=953cddc1de50fab9]*/
|
Issue #23095, asyncio: Rewrite _WaitHandleFuture.cancel()
This change fixes a race conditon related to _WaitHandleFuture.cancel() leading
to Python crash or "GetQueuedCompletionStatus() returned an unexpected event"
logs. Before, the overlapped object was destroyed too early, it was possible
that the wait completed whereas the overlapped object was already destroyed.
Sometimes, a different overlapped was allocated at the same address, leading to
unexpected completition.
_WaitHandleFuture.cancel() now waits until the wait is cancelled to clear its
reference to the overlapped object. To wait until the cancellation is done,
UnregisterWaitEx() is used with an event instead of UnregisterWait().
To wait for this event, a new _WaitCancelFuture class was added. It's a
simplified version of _WaitCancelFuture. For example, its cancel() method calls
UnregisterWait(), not UnregisterWaitEx(). _WaitCancelFuture should not be
cancelled.
The overlapped object is kept alive in _WaitHandleFuture until the wait is
unregistered.
Other changes:
* Add _overlapped.UnregisterWaitEx()
* Remove fast-path in IocpProactor.wait_for_handle() to immediatly set the
result if the wait already completed. I'm not sure that it's safe to
call immediatly UnregisterWaitEx() before the completion was signaled.
* Add IocpProactor._unregistered() to forget an overlapped which may never be
signaled, but may be signaled for the next loop iteration. It avoids to
block forever IocpProactor.close() if a wait was cancelled, and it may also
avoid some "... unexpected event ..." warnings.
2015-01-21 23:39:51 +01:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = UnregisterWaitEx(WaitHandle, Event);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2013-10-30 22:44:05 +01:00
|
|
|
/*
|
|
|
|
* Event functions -- currently only used by tests
|
|
|
|
*/
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.CreateEvent
|
|
|
|
|
|
|
|
EventAttributes: object
|
|
|
|
ManualReset: BOOL
|
|
|
|
InitialState: BOOL
|
|
|
|
Name: Py_UNICODE(accept={str, NoneType})
|
|
|
|
/
|
|
|
|
|
|
|
|
Create an event.
|
|
|
|
|
|
|
|
EventAttributes must be None.
|
|
|
|
[clinic start generated code]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_CreateEvent_impl(PyObject *module, PyObject *EventAttributes,
|
|
|
|
BOOL ManualReset, BOOL InitialState,
|
|
|
|
const Py_UNICODE *Name)
|
|
|
|
/*[clinic end generated code: output=8e04f0916c17b13d input=dbc36ae14375ba24]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
HANDLE Event;
|
|
|
|
|
|
|
|
if (EventAttributes != Py_None) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "EventAttributes must be None");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
Event = CreateEventW(NULL, ManualReset, InitialState, Name);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (Event == NULL)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
return Py_BuildValue(F_HANDLE, Event);
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.SetEvent
|
|
|
|
|
|
|
|
Handle: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Set event.
|
|
|
|
[clinic start generated code]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_SetEvent_impl(PyObject *module, HANDLE Handle)
|
|
|
|
/*[clinic end generated code: output=5b8d974216b0e569 input=d8b0d26eb7391e80]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = SetEvent(Handle);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.ResetEvent
|
|
|
|
|
|
|
|
Handle: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Reset event.
|
|
|
|
[clinic start generated code]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_ResetEvent_impl(PyObject *module, HANDLE Handle)
|
|
|
|
/*[clinic end generated code: output=066537a8405cddb2 input=d4e089c9ba84ff2f]*/
|
2013-10-30 22:44:05 +01:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = ResetEvent(Handle);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2013-10-17 22:40:50 +02:00
|
|
|
/*
|
|
|
|
* Bind socket handle to local port without doing slow getaddrinfo()
|
|
|
|
*/
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.BindLocal
|
|
|
|
|
|
|
|
handle as Socket: HANDLE
|
|
|
|
family as Family: int
|
|
|
|
/
|
|
|
|
|
|
|
|
Bind a socket handle to an arbitrary local port.
|
|
|
|
|
|
|
|
family should be AF_INET or AF_INET6.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_BindLocal_impl(PyObject *module, HANDLE Socket, int Family)
|
|
|
|
/*[clinic end generated code: output=edb93862697aed9c input=a0e7b5c2f541170c]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
|
|
|
|
if (Family == AF_INET) {
|
|
|
|
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;
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
|
|
|
|
!= SOCKET_ERROR;
|
2013-10-17 22:40:50 +02:00
|
|
|
} else if (Family == AF_INET6) {
|
|
|
|
struct sockaddr_in6 addr;
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin6_family = AF_INET6;
|
|
|
|
addr.sin6_port = 0;
|
|
|
|
addr.sin6_addr = in6addr_any;
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = bind((SOCKET)Socket, (SOCKADDR*)&addr, sizeof(addr))
|
|
|
|
!= SOCKET_ERROR;
|
2013-10-17 22:40:50 +02:00
|
|
|
} else {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "expected tuple of length 2 or 4");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return SetFromWindowsErr(WSAGetLastError());
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Windows equivalent of os.strerror() -- compare _ctypes/callproc.c
|
|
|
|
*/
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.FormatMessage
|
|
|
|
|
|
|
|
error_code as code: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Return error message for an error code.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_FormatMessage_impl(PyObject *module, DWORD code)
|
|
|
|
/*[clinic end generated code: output=02c964ff22407c6b input=644bb5b80326179e]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
2020-07-10 19:43:37 +02:00
|
|
|
DWORD n;
|
2013-10-17 22:40:50 +02:00
|
|
|
WCHAR *lpMsgBuf;
|
|
|
|
PyObject *res;
|
|
|
|
|
|
|
|
n = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
2019-09-09 11:20:39 +02:00
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
2013-10-17 22:40:50 +02:00
|
|
|
NULL,
|
|
|
|
code,
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
(LPWSTR) &lpMsgBuf,
|
|
|
|
0,
|
|
|
|
NULL);
|
|
|
|
if (n) {
|
|
|
|
while (iswspace(lpMsgBuf[n-1]))
|
|
|
|
--n;
|
|
|
|
lpMsgBuf[n] = L'\0';
|
|
|
|
res = Py_BuildValue("u", lpMsgBuf);
|
|
|
|
} else {
|
|
|
|
res = PyUnicode_FromFormat("unknown error code %u", code);
|
|
|
|
}
|
|
|
|
LocalFree(lpMsgBuf);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark operation as completed - used when reading produces ERROR_BROKEN_PIPE
|
|
|
|
*/
|
|
|
|
|
2022-03-13 22:28:45 +01:00
|
|
|
static inline void
|
2013-10-17 22:40:50 +02:00
|
|
|
mark_as_completed(OVERLAPPED *ov)
|
|
|
|
{
|
|
|
|
ov->Internal = 0;
|
|
|
|
if (ov->hEvent != NULL)
|
|
|
|
SetEvent(ov->hEvent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A Python object wrapping an OVERLAPPED structure and other useful data
|
|
|
|
* for overlapped I/O
|
|
|
|
*/
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
@classmethod
|
|
|
|
_overlapped.Overlapped.__new__
|
|
|
|
|
|
|
|
event: HANDLE(c_default='INVALID_HANDLE_VALUE') = _overlapped.INVALID_HANDLE_VALUE
|
|
|
|
|
|
|
|
OVERLAPPED structure wrapper.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_impl(PyTypeObject *type, HANDLE event)
|
|
|
|
/*[clinic end generated code: output=6da60504a18eb421 input=26b8a7429e629e95]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
OverlappedObject *self;
|
|
|
|
|
|
|
|
if (event == INVALID_HANDLE_VALUE) {
|
|
|
|
event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (event == NULL)
|
|
|
|
return SetFromWindowsErr(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;
|
2017-10-19 21:46:40 +02:00
|
|
|
self->allocated_buffer = NULL;
|
2013-10-17 22:40:50 +02:00
|
|
|
memset(&self->overlapped, 0, sizeof(OVERLAPPED));
|
2017-10-19 21:46:40 +02:00
|
|
|
memset(&self->user_buffer, 0, sizeof(Py_buffer));
|
2013-10-17 22:40:50 +02:00
|
|
|
if (event)
|
|
|
|
self->overlapped.hEvent = event;
|
|
|
|
return (PyObject *)self;
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:35:14 +01:00
|
|
|
|
|
|
|
/* Note (bpo-32710): OverlappedType.tp_clear is not defined to not release
|
|
|
|
buffers while overlapped are still running, to prevent a crash. */
|
|
|
|
static int
|
|
|
|
Overlapped_clear(OverlappedObject *self)
|
|
|
|
{
|
|
|
|
switch (self->type) {
|
2019-05-28 11:52:15 +02:00
|
|
|
case TYPE_READ:
|
|
|
|
case TYPE_ACCEPT: {
|
|
|
|
Py_CLEAR(self->allocated_buffer);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_READ_FROM: {
|
|
|
|
// An initial call to WSARecvFrom will only allocate the buffer.
|
|
|
|
// The result tuple of (message, address) is only
|
|
|
|
// allocated _after_ a message has been received.
|
|
|
|
if(self->read_from.result) {
|
|
|
|
// We've received a message, free the result tuple.
|
|
|
|
Py_CLEAR(self->read_from.result);
|
|
|
|
}
|
|
|
|
if(self->read_from.allocated_buffer) {
|
|
|
|
Py_CLEAR(self->read_from.allocated_buffer);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2022-03-13 17:42:29 +01:00
|
|
|
case TYPE_READ_FROM_INTO: {
|
|
|
|
if (self->read_from_into.result) {
|
|
|
|
// We've received a message, free the result tuple.
|
|
|
|
Py_CLEAR(self->read_from_into.result);
|
|
|
|
}
|
2022-03-13 22:28:45 +01:00
|
|
|
if (self->read_from_into.user_buffer.obj) {
|
|
|
|
PyBuffer_Release(&self->read_from_into.user_buffer);
|
|
|
|
}
|
2022-03-13 17:42:29 +01:00
|
|
|
break;
|
|
|
|
}
|
2019-05-28 11:52:15 +02:00
|
|
|
case TYPE_WRITE:
|
|
|
|
case TYPE_WRITE_TO:
|
|
|
|
case TYPE_READINTO: {
|
|
|
|
if (self->user_buffer.obj) {
|
|
|
|
PyBuffer_Release(&self->user_buffer);
|
|
|
|
}
|
|
|
|
break;
|
2019-01-11 14:35:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self->type = TYPE_NOT_STARTED;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-17 22:40:50 +02:00
|
|
|
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)
|
|
|
|
{
|
2022-03-13 22:28:45 +01:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
if (CancelIoEx(self->handle, &self->overlapped))
|
2013-10-17 22:40:50 +02:00
|
|
|
wait = TRUE;
|
|
|
|
|
|
|
|
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_Format(
|
|
|
|
PyExc_RuntimeError,
|
|
|
|
"%R still has pending operation at "
|
|
|
|
"deallocation, the process may crash", self);
|
|
|
|
PyErr_WriteUnraisable(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:35:14 +01:00
|
|
|
if (self->overlapped.hEvent != NULL) {
|
2013-10-17 22:40:50 +02:00
|
|
|
CloseHandle(self->overlapped.hEvent);
|
|
|
|
}
|
2019-01-11 14:35:14 +01:00
|
|
|
|
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
SetLastError(olderr);
|
2020-09-07 15:12:40 +02:00
|
|
|
|
|
|
|
PyTypeObject *tp = Py_TYPE(self);
|
2020-12-01 10:37:39 +01:00
|
|
|
PyObject_Free(self);
|
2020-09-07 15:12:40 +02:00
|
|
|
Py_DECREF(tp);
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
|
|
|
|
2019-05-28 11:52:15 +02:00
|
|
|
|
|
|
|
/* Convert IPv4 sockaddr to a Python str. */
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
make_ipv4_addr(const struct sockaddr_in *addr)
|
|
|
|
{
|
|
|
|
char buf[INET_ADDRSTRLEN];
|
|
|
|
if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) {
|
|
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return PyUnicode_FromString(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert IPv6 sockaddr to a Python str. */
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
make_ipv6_addr(const struct sockaddr_in6 *addr)
|
|
|
|
{
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) == NULL) {
|
|
|
|
PyErr_SetFromErrno(PyExc_OSError);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return PyUnicode_FromString(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
unparse_address(LPSOCKADDR Address, DWORD Length)
|
|
|
|
{
|
|
|
|
/* The function is adopted from mocketmodule.c makesockaddr()*/
|
|
|
|
|
|
|
|
switch(Address->sa_family) {
|
|
|
|
case AF_INET: {
|
|
|
|
const struct sockaddr_in *a = (const struct sockaddr_in *)Address;
|
|
|
|
PyObject *addrobj = make_ipv4_addr(a);
|
|
|
|
PyObject *ret = NULL;
|
|
|
|
if (addrobj) {
|
|
|
|
ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port));
|
|
|
|
Py_DECREF(addrobj);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
case AF_INET6: {
|
|
|
|
const struct sockaddr_in6 *a = (const struct sockaddr_in6 *)Address;
|
|
|
|
PyObject *addrobj = make_ipv6_addr(a);
|
|
|
|
PyObject *ret = NULL;
|
|
|
|
if (addrobj) {
|
|
|
|
ret = Py_BuildValue("OiII",
|
|
|
|
addrobj,
|
|
|
|
ntohs(a->sin6_port),
|
|
|
|
ntohl(a->sin6_flowinfo),
|
|
|
|
a->sin6_scope_id);
|
|
|
|
Py_DECREF(addrobj);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
default: {
|
2020-05-18 08:21:30 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "recvfrom returned unsupported address family");
|
|
|
|
return NULL;
|
2019-05-28 11:52:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.cancel
|
|
|
|
|
|
|
|
Cancel overlapped operation.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_cancel_impl(OverlappedObject *self)
|
|
|
|
/*[clinic end generated code: output=54ad7aeece89901c input=80eb67c7b57dbcf1]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
BOOL ret = TRUE;
|
|
|
|
|
|
|
|
if (self->type == TYPE_NOT_STARTED
|
|
|
|
|| self->type == TYPE_WAIT_NAMED_PIPE_AND_CONNECT)
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
|
|
|
|
if (!HasOverlappedIoCompleted(&self->overlapped)) {
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2022-03-13 22:28:45 +01:00
|
|
|
ret = CancelIoEx(self->handle, &self->overlapped);
|
2013-10-17 22:40:50 +02:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
|
|
|
|
if (!ret && GetLastError() != ERROR_NOT_FOUND)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.getresult
|
|
|
|
|
|
|
|
wait: BOOL(c_default='FALSE') = False
|
|
|
|
/
|
|
|
|
|
|
|
|
Retrieve result of operation.
|
|
|
|
|
|
|
|
If wait is true then it blocks until the operation is finished. If wait
|
|
|
|
is false and the operation is still pending then an error is raised.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
|
|
|
|
/*[clinic end generated code: output=8c9bd04d08994f6c input=aa5b03e9897ca074]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
DWORD transferred = 0;
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
2019-05-28 11:52:15 +02:00
|
|
|
PyObject *addr;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
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:
|
2019-05-28 11:52:15 +02:00
|
|
|
if (self->type == TYPE_READ || self->type == TYPE_READINTO) {
|
2013-10-17 22:40:50 +02:00
|
|
|
break;
|
2019-05-28 11:52:15 +02:00
|
|
|
}
|
|
|
|
else if (self->type == TYPE_READ_FROM &&
|
|
|
|
(self->read_from.result != NULL ||
|
|
|
|
self->read_from.allocated_buffer != NULL))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2022-03-13 17:42:29 +01:00
|
|
|
else if (self->type == TYPE_READ_FROM_INTO &&
|
|
|
|
self->read_from_into.result != NULL)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (self->type) {
|
|
|
|
case TYPE_READ:
|
2017-10-19 21:46:40 +02:00
|
|
|
assert(PyBytes_CheckExact(self->allocated_buffer));
|
|
|
|
if (transferred != PyBytes_GET_SIZE(self->allocated_buffer) &&
|
|
|
|
_PyBytes_Resize(&self->allocated_buffer, transferred))
|
2013-10-17 22:40:50 +02:00
|
|
|
return NULL;
|
2019-05-28 11:52:15 +02:00
|
|
|
|
2022-11-14 16:21:23 +01:00
|
|
|
return Py_NewRef(self->allocated_buffer);
|
2019-05-28 11:52:15 +02:00
|
|
|
case TYPE_READ_FROM:
|
|
|
|
assert(PyBytes_CheckExact(self->read_from.allocated_buffer));
|
|
|
|
|
|
|
|
if (transferred != PyBytes_GET_SIZE(
|
|
|
|
self->read_from.allocated_buffer) &&
|
|
|
|
_PyBytes_Resize(&self->read_from.allocated_buffer, transferred))
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unparse the address
|
|
|
|
addr = unparse_address((SOCKADDR*)&self->read_from.address,
|
|
|
|
self->read_from.address_length);
|
|
|
|
|
|
|
|
if (addr == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The result is a two item tuple: (message, address)
|
|
|
|
self->read_from.result = PyTuple_New(2);
|
|
|
|
if (self->read_from.result == NULL) {
|
|
|
|
Py_CLEAR(addr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// first item: message
|
|
|
|
PyTuple_SET_ITEM(self->read_from.result, 0,
|
2022-11-14 16:21:23 +01:00
|
|
|
Py_NewRef(self->read_from.allocated_buffer));
|
2019-05-28 11:52:15 +02:00
|
|
|
// second item: address
|
|
|
|
PyTuple_SET_ITEM(self->read_from.result, 1, addr);
|
|
|
|
|
2022-11-14 16:21:23 +01:00
|
|
|
return Py_NewRef(self->read_from.result);
|
2022-03-13 17:42:29 +01:00
|
|
|
case TYPE_READ_FROM_INTO:
|
|
|
|
// unparse the address
|
|
|
|
addr = unparse_address((SOCKADDR*)&self->read_from_into.address,
|
|
|
|
self->read_from_into.address_length);
|
|
|
|
|
|
|
|
if (addr == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The result is a two item tuple: (number of bytes read, address)
|
|
|
|
self->read_from_into.result = PyTuple_New(2);
|
|
|
|
if (self->read_from_into.result == NULL) {
|
|
|
|
Py_CLEAR(addr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// first item: number of bytes read
|
|
|
|
PyTuple_SET_ITEM(self->read_from_into.result, 0,
|
|
|
|
PyLong_FromUnsignedLong((unsigned long)transferred));
|
|
|
|
// second item: address
|
|
|
|
PyTuple_SET_ITEM(self->read_from_into.result, 1, addr);
|
|
|
|
|
2022-11-14 16:21:23 +01:00
|
|
|
return Py_NewRef(self->read_from_into.result);
|
2013-10-17 22:40:50 +02:00
|
|
|
default:
|
|
|
|
return PyLong_FromUnsignedLong((unsigned long) transferred);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-19 21:46:40 +02:00
|
|
|
static PyObject *
|
|
|
|
do_ReadFile(OverlappedObject *self, HANDLE handle,
|
|
|
|
char *bufstart, DWORD buflen)
|
|
|
|
{
|
|
|
|
DWORD nread;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = ReadFile(handle, bufstart, buflen, &nread,
|
|
|
|
&self->overlapped);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : GetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
mark_as_completed(&self->overlapped);
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2017-10-19 21:46:40 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.ReadFile
|
|
|
|
|
|
|
|
handle: HANDLE
|
|
|
|
size: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped read.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_ReadFile_impl(OverlappedObject *self, HANDLE handle,
|
|
|
|
DWORD size)
|
|
|
|
/*[clinic end generated code: output=4c8557e16941e4ae input=98c495baa0342425]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
PyObject *buf;
|
|
|
|
|
|
|
|
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;
|
2017-10-19 21:46:40 +02:00
|
|
|
self->allocated_buffer = buf;
|
|
|
|
|
|
|
|
return do_ReadFile(self, handle, PyBytes_AS_STRING(buf), size);
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.ReadFileInto
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
handle: HANDLE
|
2022-03-13 22:28:45 +01:00
|
|
|
buf as bufobj: Py_buffer
|
2020-07-10 19:43:37 +02:00
|
|
|
/
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
Start overlapped receive.
|
|
|
|
[clinic start generated code]*/
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
static PyObject *
|
|
|
|
_overlapped_Overlapped_ReadFileInto_impl(OverlappedObject *self,
|
2022-03-13 22:28:45 +01:00
|
|
|
HANDLE handle, Py_buffer *bufobj)
|
|
|
|
/*[clinic end generated code: output=8754744506023071 input=4f037ba09939e32d]*/
|
2020-07-10 19:43:37 +02:00
|
|
|
{
|
2017-10-19 21:46:40 +02:00
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
2022-03-13 22:28:45 +01:00
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
2017-10-19 21:46:40 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->user_buffer, bufobj);
|
2017-10-19 21:46:40 +02:00
|
|
|
|
|
|
|
self->type = TYPE_READINTO;
|
|
|
|
self->handle = handle;
|
|
|
|
|
|
|
|
return do_ReadFile(self, handle, self->user_buffer.buf,
|
|
|
|
(DWORD)self->user_buffer.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
do_WSARecv(OverlappedObject *self, HANDLE handle,
|
|
|
|
char *bufstart, DWORD buflen, DWORD flags)
|
|
|
|
{
|
|
|
|
DWORD nread;
|
|
|
|
WSABUF wsabuf;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
2017-10-26 15:59:40 +02:00
|
|
|
|
2017-10-19 21:46:40 +02:00
|
|
|
wsabuf.buf = bufstart;
|
|
|
|
wsabuf.len = buflen;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2017-10-19 21:46:40 +02:00
|
|
|
ret = WSARecv((SOCKET)handle, &wsabuf, 1, &nread, &flags,
|
|
|
|
&self->overlapped, NULL);
|
2013-10-17 22:40:50 +02:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
2017-10-19 21:46:40 +02:00
|
|
|
self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
|
2013-10-17 22:40:50 +02:00
|
|
|
switch (err) {
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
mark_as_completed(&self->overlapped);
|
2015-01-26 22:30:49 +01:00
|
|
|
return SetFromWindowsErr(err);
|
2013-10-17 22:40:50 +02:00
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-13 17:42:29 +01:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSARecv
|
|
|
|
|
|
|
|
handle: HANDLE
|
|
|
|
size: DWORD
|
|
|
|
flags: DWORD = 0
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped receive.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_WSARecv_impl(OverlappedObject *self, HANDLE handle,
|
|
|
|
DWORD size, DWORD flags)
|
|
|
|
/*[clinic end generated code: output=3a5e9c61ff040906 input=8c04e506cc3d741a]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
PyObject *buf;
|
|
|
|
|
|
|
|
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;
|
2017-10-19 21:46:40 +02:00
|
|
|
self->allocated_buffer = buf;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2017-10-19 21:46:40 +02:00
|
|
|
return do_WSARecv(self, handle, PyBytes_AS_STRING(buf), size, flags);
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSARecvInto
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
handle: HANDLE
|
2022-03-13 22:28:45 +01:00
|
|
|
buf as bufobj: Py_buffer
|
2020-07-10 19:43:37 +02:00
|
|
|
flags: DWORD
|
|
|
|
/
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
Start overlapped receive.
|
|
|
|
[clinic start generated code]*/
|
2017-10-19 21:46:40 +02:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
static PyObject *
|
|
|
|
_overlapped_Overlapped_WSARecvInto_impl(OverlappedObject *self,
|
2022-03-13 22:28:45 +01:00
|
|
|
HANDLE handle, Py_buffer *bufobj,
|
2020-07-10 19:43:37 +02:00
|
|
|
DWORD flags)
|
2022-03-13 22:28:45 +01:00
|
|
|
/*[clinic end generated code: output=59ae7688786cf86b input=73e7fa00db633edd]*/
|
2020-07-10 19:43:37 +02:00
|
|
|
{
|
2017-10-19 21:46:40 +02:00
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
2022-03-13 22:28:45 +01:00
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
2017-10-19 21:46:40 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
|
|
|
return NULL;
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
2017-10-19 21:46:40 +02:00
|
|
|
#endif
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->user_buffer, bufobj);
|
2017-10-19 21:46:40 +02:00
|
|
|
|
|
|
|
self->type = TYPE_READINTO;
|
|
|
|
self->handle = handle;
|
|
|
|
|
|
|
|
return do_WSARecv(self, handle, self->user_buffer.buf,
|
|
|
|
(DWORD)self->user_buffer.len, flags);
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WriteFile
|
|
|
|
|
|
|
|
handle: HANDLE
|
2022-03-13 22:28:45 +01:00
|
|
|
buf as bufobj: Py_buffer
|
2020-07-10 19:43:37 +02:00
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped write.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_WriteFile_impl(OverlappedObject *self, HANDLE handle,
|
2022-03-13 22:28:45 +01:00
|
|
|
Py_buffer *bufobj)
|
|
|
|
/*[clinic end generated code: output=fa5d5880a1bf04b1 input=ac54424c362abfc1]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
DWORD written;
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
2022-03-13 22:28:45 +01:00
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
2017-08-15 18:04:18 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
2013-10-17 22:40:50 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->user_buffer, bufobj);
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
self->type = TYPE_WRITE;
|
|
|
|
self->handle = handle;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2017-10-19 21:46:40 +02:00
|
|
|
ret = WriteFile(handle, self->user_buffer.buf,
|
|
|
|
(DWORD)self->user_buffer.len,
|
2013-10-17 22:40:50 +02:00
|
|
|
&written, &self->overlapped);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : GetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSASend
|
|
|
|
|
|
|
|
handle: HANDLE
|
2022-03-13 22:28:45 +01:00
|
|
|
buf as bufobj: Py_buffer
|
2020-07-10 19:43:37 +02:00
|
|
|
flags: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped send.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_WSASend_impl(OverlappedObject *self, HANDLE handle,
|
2022-03-13 22:28:45 +01:00
|
|
|
Py_buffer *bufobj, DWORD flags)
|
|
|
|
/*[clinic end generated code: output=3baaa6e1f7fe229e input=c4167420ba2f93d8]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
DWORD written;
|
|
|
|
WSABUF wsabuf;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
2022-03-13 22:28:45 +01:00
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
2017-08-15 18:04:18 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
2013-10-17 22:40:50 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->user_buffer, bufobj);
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
self->type = TYPE_WRITE;
|
|
|
|
self->handle = handle;
|
2017-10-19 21:46:40 +02:00
|
|
|
wsabuf.len = (DWORD)self->user_buffer.len;
|
|
|
|
wsabuf.buf = self->user_buffer.buf;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
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_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.AcceptEx
|
|
|
|
|
|
|
|
listen_handle as ListenSocket: HANDLE
|
|
|
|
accept_handle as AcceptSocket: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped wait for client to connect.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_AcceptEx_impl(OverlappedObject *self,
|
|
|
|
HANDLE ListenSocket,
|
|
|
|
HANDLE AcceptSocket)
|
|
|
|
/*[clinic end generated code: output=9a7381d4232af889 input=b83473224fc3a1c5]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
DWORD BytesReceived;
|
|
|
|
DWORD size;
|
|
|
|
PyObject *buf;
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
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;
|
2020-07-10 19:43:37 +02:00
|
|
|
self->handle = ListenSocket;
|
2017-10-19 21:46:40 +02:00
|
|
|
self->allocated_buffer = buf;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = Py_AcceptEx((SOCKET)ListenSocket, (SOCKET)AcceptSocket,
|
|
|
|
PyBytes_AS_STRING(buf), 0, size, size, &BytesReceived,
|
|
|
|
&self->overlapped);
|
2013-10-17 22:40:50 +02:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
parse_address(PyObject *obj, SOCKADDR *Address, int Length)
|
|
|
|
{
|
2020-07-10 22:26:06 +02:00
|
|
|
PyObject *Host_obj;
|
2022-05-12 07:48:38 +02:00
|
|
|
wchar_t *Host;
|
2013-10-17 22:40:50 +02:00
|
|
|
unsigned short Port;
|
|
|
|
unsigned long FlowInfo;
|
|
|
|
unsigned long ScopeId;
|
|
|
|
|
|
|
|
memset(Address, 0, Length);
|
|
|
|
|
2020-07-10 22:26:06 +02:00
|
|
|
switch (PyTuple_GET_SIZE(obj)) {
|
|
|
|
case 2: {
|
|
|
|
if (!PyArg_ParseTuple(obj, "UH", &Host_obj, &Port)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Host = PyUnicode_AsWideCharString(Host_obj, NULL);
|
|
|
|
if (Host == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
Address->sa_family = AF_INET;
|
2016-09-08 19:35:16 +02:00
|
|
|
if (WSAStringToAddressW(Host, AF_INET, NULL, Address, &Length) < 0) {
|
2013-10-17 22:40:50 +02:00
|
|
|
SetFromWindowsErr(WSAGetLastError());
|
2020-07-10 22:26:06 +02:00
|
|
|
Length = -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
((SOCKADDR_IN*)Address)->sin_port = htons(Port);
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
2020-07-10 22:26:06 +02:00
|
|
|
PyMem_Free(Host);
|
2013-10-17 22:40:50 +02:00
|
|
|
return Length;
|
|
|
|
}
|
2020-07-10 22:26:06 +02:00
|
|
|
case 4: {
|
|
|
|
if (!PyArg_ParseTuple(obj,
|
|
|
|
"UHkk;ConnectEx(): illegal address_as_bytes argument",
|
|
|
|
&Host_obj, &Port, &FlowInfo, &ScopeId))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
Host = PyUnicode_AsWideCharString(Host_obj, NULL);
|
|
|
|
if (Host == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
Address->sa_family = AF_INET6;
|
2016-09-08 19:35:16 +02:00
|
|
|
if (WSAStringToAddressW(Host, AF_INET6, NULL, Address, &Length) < 0) {
|
2013-10-17 22:40:50 +02:00
|
|
|
SetFromWindowsErr(WSAGetLastError());
|
2020-07-10 22:26:06 +02:00
|
|
|
Length = -1;
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
2020-07-10 22:26:06 +02:00
|
|
|
else {
|
|
|
|
((SOCKADDR_IN6*)Address)->sin6_port = htons(Port);
|
|
|
|
((SOCKADDR_IN6*)Address)->sin6_flowinfo = FlowInfo;
|
|
|
|
((SOCKADDR_IN6*)Address)->sin6_scope_id = ScopeId;
|
|
|
|
}
|
|
|
|
PyMem_Free(Host);
|
2013-10-17 22:40:50 +02:00
|
|
|
return Length;
|
|
|
|
}
|
2020-07-10 22:26:06 +02:00
|
|
|
default:
|
|
|
|
PyErr_SetString(PyExc_ValueError, "illegal address_as_bytes argument");
|
|
|
|
return -1;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.ConnectEx
|
|
|
|
|
|
|
|
client_handle as ConnectSocket: HANDLE
|
|
|
|
address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped connect.
|
|
|
|
|
|
|
|
client_handle should be unbound.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_ConnectEx_impl(OverlappedObject *self,
|
|
|
|
HANDLE ConnectSocket,
|
|
|
|
PyObject *AddressObj)
|
|
|
|
/*[clinic end generated code: output=5aebbbdb4f022833 input=d6bbd2d84b156fc1]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
char AddressBuf[sizeof(struct sockaddr_in6)];
|
|
|
|
SOCKADDR *Address = (SOCKADDR*)AddressBuf;
|
|
|
|
int Length;
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
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;
|
2020-07-10 19:43:37 +02:00
|
|
|
self->handle = ConnectSocket;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = Py_ConnectEx((SOCKET)ConnectSocket, Address, Length,
|
2013-10-17 22:40:50 +02:00
|
|
|
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:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.DisconnectEx
|
|
|
|
|
|
|
|
handle as Socket: HANDLE
|
|
|
|
flags: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_DisconnectEx_impl(OverlappedObject *self,
|
|
|
|
HANDLE Socket, DWORD flags)
|
|
|
|
/*[clinic end generated code: output=8d64ddb8c93c2126 input=680845cdcdf820eb]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
self->type = TYPE_DISCONNECT;
|
2020-07-10 19:43:37 +02:00
|
|
|
self->handle = Socket;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = Py_DisconnectEx((SOCKET)Socket, &self->overlapped, flags, 0);
|
2013-10-17 22:40:50 +02:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.TransmitFile
|
|
|
|
|
|
|
|
socket as Socket: HANDLE
|
|
|
|
file as File: HANDLE
|
|
|
|
offset: DWORD
|
|
|
|
offset_high: DWORD
|
|
|
|
count_to_write: DWORD
|
|
|
|
count_per_send: DWORD
|
|
|
|
flags: DWORD
|
|
|
|
/
|
|
|
|
|
|
|
|
Transmit file data over a connected socket.
|
|
|
|
[clinic start generated code]*/
|
2018-02-25 17:32:14 +01:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_TransmitFile_impl(OverlappedObject *self,
|
|
|
|
HANDLE Socket, HANDLE File,
|
|
|
|
DWORD offset, DWORD offset_high,
|
|
|
|
DWORD count_to_write,
|
|
|
|
DWORD count_per_send, DWORD flags)
|
|
|
|
/*[clinic end generated code: output=03f3ca5512e678fd input=7e6f97b391f60e8c]*/
|
2018-02-25 17:32:14 +01:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
self->type = TYPE_TRANSMIT_FILE;
|
2020-07-10 19:43:37 +02:00
|
|
|
self->handle = Socket;
|
2018-02-25 17:32:14 +01:00
|
|
|
self->overlapped.Offset = offset;
|
|
|
|
self->overlapped.OffsetHigh = offset_high;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2020-07-10 19:43:37 +02:00
|
|
|
ret = Py_TransmitFile((SOCKET)Socket, File, count_to_write,
|
|
|
|
count_per_send, &self->overlapped, NULL, flags);
|
2018-02-25 17:32:14 +01:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : WSAGetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2018-02-25 17:32:14 +01:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.ConnectNamedPipe
|
|
|
|
|
|
|
|
handle as Pipe: HANDLE
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped wait for a client to connect.
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_ConnectNamedPipe_impl(OverlappedObject *self,
|
|
|
|
HANDLE Pipe)
|
|
|
|
/*[clinic end generated code: output=3e69adfe55818abe input=8b0d4cef8a72f7bc]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
|
|
|
BOOL ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
self->type = TYPE_CONNECT_NAMED_PIPE;
|
|
|
|
self->handle = Pipe;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = ConnectNamedPipe(Pipe, &self->overlapped);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = ret ? ERROR_SUCCESS : GetLastError();
|
|
|
|
switch (err) {
|
|
|
|
case ERROR_PIPE_CONNECTED:
|
|
|
|
mark_as_completed(&self->overlapped);
|
2015-01-22 23:50:03 +01:00
|
|
|
Py_RETURN_TRUE;
|
2013-10-17 22:40:50 +02:00
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
2015-01-22 23:50:03 +01:00
|
|
|
Py_RETURN_FALSE;
|
2013-10-17 22:40:50 +02:00
|
|
|
default:
|
2019-01-11 14:35:14 +01:00
|
|
|
Overlapped_clear(self);
|
2013-10-17 22:40:50 +02:00
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.ConnectPipe
|
|
|
|
|
|
|
|
addr as Address: Py_UNICODE
|
|
|
|
/
|
|
|
|
|
|
|
|
Connect to the pipe for asynchronous I/O (overlapped).
|
|
|
|
[clinic start generated code]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_ConnectPipe_impl(OverlappedObject *self,
|
|
|
|
const Py_UNICODE *Address)
|
|
|
|
/*[clinic end generated code: output=3cc9661667d459d4 input=167c06a274efcefc]*/
|
2013-10-17 22:40:50 +02:00
|
|
|
{
|
2015-01-22 22:55:08 +01:00
|
|
|
HANDLE PipeHandle;
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2015-01-26 22:43:39 +01:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2015-01-22 22:55:08 +01:00
|
|
|
PipeHandle = CreateFileW(Address,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
0, NULL, OPEN_EXISTING,
|
|
|
|
FILE_FLAG_OVERLAPPED, NULL);
|
2015-01-26 22:43:39 +01:00
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
2015-01-22 22:55:08 +01:00
|
|
|
if (PipeHandle == INVALID_HANDLE_VALUE)
|
|
|
|
return SetFromWindowsErr(0);
|
|
|
|
return Py_BuildValue(F_HANDLE, PipeHandle);
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-01-11 14:35:14 +01:00
|
|
|
static int
|
|
|
|
Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
switch (self->type) {
|
|
|
|
case TYPE_READ:
|
|
|
|
case TYPE_ACCEPT:
|
|
|
|
Py_VISIT(self->allocated_buffer);
|
|
|
|
break;
|
|
|
|
case TYPE_WRITE:
|
2019-05-28 11:52:15 +02:00
|
|
|
case TYPE_WRITE_TO:
|
2019-01-11 14:35:14 +01:00
|
|
|
case TYPE_READINTO:
|
|
|
|
if (self->user_buffer.obj) {
|
|
|
|
Py_VISIT(&self->user_buffer.obj);
|
|
|
|
}
|
|
|
|
break;
|
2019-05-28 11:52:15 +02:00
|
|
|
case TYPE_READ_FROM:
|
2020-06-07 14:05:36 +02:00
|
|
|
Py_VISIT(self->read_from.result);
|
|
|
|
Py_VISIT(self->read_from.allocated_buffer);
|
2022-03-13 17:42:29 +01:00
|
|
|
break;
|
|
|
|
case TYPE_READ_FROM_INTO:
|
|
|
|
Py_VISIT(self->read_from_into.result);
|
2022-03-13 22:28:45 +01:00
|
|
|
if (self->read_from_into.user_buffer.obj) {
|
|
|
|
Py_VISIT(&self->read_from_into.user_buffer.obj);
|
2022-03-13 17:42:29 +01:00
|
|
|
}
|
|
|
|
break;
|
2019-01-11 14:35:14 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-28 11:52:15 +02:00
|
|
|
// UDP functions
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: WSAConnect does not support Overlapped I/O so this function should
|
|
|
|
* _only_ be used for connectionless sockets (UDP).
|
|
|
|
*/
|
2020-07-10 19:43:37 +02:00
|
|
|
|
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.WSAConnect
|
|
|
|
|
|
|
|
client_handle as ConnectSocket: HANDLE
|
2022-10-30 05:34:46 +01:00
|
|
|
address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
|
2020-07-10 19:43:37 +02:00
|
|
|
/
|
|
|
|
|
|
|
|
Bind a remote address to a connectionless (UDP) socket.
|
|
|
|
[clinic start generated code]*/
|
|
|
|
|
2019-05-28 11:52:15 +02:00
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_WSAConnect_impl(PyObject *module, HANDLE ConnectSocket,
|
|
|
|
PyObject *AddressObj)
|
2022-10-30 05:34:46 +01:00
|
|
|
/*[clinic end generated code: output=ea0b4391e94dad63 input=7cf65313d49c015a]*/
|
2019-05-28 11:52:15 +02:00
|
|
|
{
|
|
|
|
char AddressBuf[sizeof(struct sockaddr_in6)];
|
|
|
|
SOCKADDR *Address = (SOCKADDR*)AddressBuf;
|
|
|
|
int Length;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
Length = sizeof(AddressBuf);
|
|
|
|
Length = parse_address(AddressObj, Address, Length);
|
|
|
|
if (Length < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
// WSAConnect does not support overlapped I/O so this call will
|
|
|
|
// successfully complete immediately.
|
2020-07-10 19:43:37 +02:00
|
|
|
err = WSAConnect((SOCKET)ConnectSocket, Address, Length,
|
2019-05-28 11:52:15 +02:00
|
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (err == 0) {
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return SetFromWindowsErr(WSAGetLastError());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSASendTo
|
|
|
|
|
|
|
|
handle: HANDLE
|
2022-03-13 22:28:45 +01:00
|
|
|
buf as bufobj: Py_buffer
|
2020-07-10 19:43:37 +02:00
|
|
|
flags: DWORD
|
2022-10-30 05:34:46 +01:00
|
|
|
address_as_bytes as AddressObj: object(subclass_of='&PyTuple_Type')
|
2020-07-10 19:43:37 +02:00
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped sendto over a connectionless (UDP) socket.
|
|
|
|
[clinic start generated code]*/
|
2019-05-28 11:52:15 +02:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_WSASendTo_impl(OverlappedObject *self, HANDLE handle,
|
2022-03-13 22:28:45 +01:00
|
|
|
Py_buffer *bufobj, DWORD flags,
|
2020-07-10 19:43:37 +02:00
|
|
|
PyObject *AddressObj)
|
2022-10-30 05:34:46 +01:00
|
|
|
/*[clinic end generated code: output=3cdedc4cfaeb70cd input=31f44cd4ab92fc33]*/
|
2019-05-28 11:52:15 +02:00
|
|
|
{
|
|
|
|
char AddressBuf[sizeof(struct sockaddr_in6)];
|
|
|
|
SOCKADDR *Address = (SOCKADDR*)AddressBuf;
|
|
|
|
int AddressLength;
|
|
|
|
DWORD written;
|
|
|
|
WSABUF wsabuf;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
// Parse the "to" address
|
|
|
|
AddressLength = sizeof(AddressBuf);
|
|
|
|
AddressLength = parse_address(AddressObj, Address, AddressLength);
|
|
|
|
if (AddressLength < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
2022-03-13 22:28:45 +01:00
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
2019-05-28 11:52:15 +02:00
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->user_buffer, bufobj);
|
2019-05-28 11:52:15 +02:00
|
|
|
|
|
|
|
self->type = TYPE_WRITE_TO;
|
|
|
|
self->handle = handle;
|
|
|
|
wsabuf.len = (DWORD)self->user_buffer.len;
|
|
|
|
wsabuf.buf = self->user_buffer.buf;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = WSASendTo((SOCKET)handle, &wsabuf, 1, &written, flags,
|
|
|
|
Address, AddressLength, &self->overlapped, NULL);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = (ret == SOCKET_ERROR ? WSAGetLastError() :
|
|
|
|
ERROR_SUCCESS);
|
|
|
|
|
|
|
|
switch(err) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
|
|
|
self->type = TYPE_NOT_STARTED;
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PyDoc_STRVAR(
|
|
|
|
Overlapped_WSARecvFrom_doc,
|
|
|
|
"RecvFile(handle, size, flags) -> Overlapped[(message, (host, port))]\n\n"
|
|
|
|
"Start overlapped receive");
|
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSARecvFrom
|
|
|
|
|
|
|
|
handle: HANDLE
|
|
|
|
size: DWORD
|
|
|
|
flags: DWORD = 0
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped receive.
|
|
|
|
[clinic start generated code]*/
|
|
|
|
|
2019-05-28 11:52:15 +02:00
|
|
|
static PyObject *
|
2020-07-10 19:43:37 +02:00
|
|
|
_overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
|
|
|
|
HANDLE handle, DWORD size,
|
|
|
|
DWORD flags)
|
|
|
|
/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
|
2019-05-28 11:52:15 +02:00
|
|
|
{
|
|
|
|
PyObject *buf;
|
2022-03-13 17:42:29 +01:00
|
|
|
DWORD nread;
|
2019-05-28 11:52:15 +02:00
|
|
|
WSABUF wsabuf;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsabuf.buf = PyBytes_AS_STRING(buf);
|
2022-03-13 17:42:29 +01:00
|
|
|
wsabuf.len = size;
|
2019-05-28 11:52:15 +02:00
|
|
|
|
|
|
|
self->type = TYPE_READ_FROM;
|
|
|
|
self->handle = handle;
|
|
|
|
self->read_from.allocated_buffer = buf;
|
|
|
|
memset(&self->read_from.address, 0, sizeof(self->read_from.address));
|
|
|
|
self->read_from.address_length = sizeof(self->read_from.address);
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
|
|
|
|
(SOCKADDR*)&self->read_from.address,
|
|
|
|
&self->read_from.address_length,
|
|
|
|
&self->overlapped, NULL);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
|
2022-03-13 17:42:29 +01:00
|
|
|
switch (err) {
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
mark_as_completed(&self->overlapped);
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
|
|
|
self->type = TYPE_NOT_STARTED;
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 11:52:15 +02:00
|
|
|
|
2022-03-13 17:42:29 +01:00
|
|
|
|
|
|
|
/*[clinic input]
|
|
|
|
_overlapped.Overlapped.WSARecvFromInto
|
|
|
|
|
|
|
|
handle: HANDLE
|
|
|
|
buf as bufobj: Py_buffer
|
|
|
|
size: DWORD
|
|
|
|
flags: DWORD = 0
|
|
|
|
/
|
|
|
|
|
|
|
|
Start overlapped receive.
|
|
|
|
[clinic start generated code]*/
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
_overlapped_Overlapped_WSARecvFromInto_impl(OverlappedObject *self,
|
|
|
|
HANDLE handle, Py_buffer *bufobj,
|
|
|
|
DWORD size, DWORD flags)
|
|
|
|
/*[clinic end generated code: output=30c7ea171a691757 input=4be4b08d03531e76]*/
|
|
|
|
{
|
|
|
|
DWORD nread;
|
|
|
|
WSABUF wsabuf;
|
|
|
|
int ret;
|
|
|
|
DWORD err;
|
|
|
|
|
|
|
|
if (self->type != TYPE_NONE) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "operation already attempted");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SIZEOF_SIZE_T > SIZEOF_LONG
|
|
|
|
if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "buffer too large");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
wsabuf.buf = bufobj->buf;
|
|
|
|
wsabuf.len = size;
|
|
|
|
|
|
|
|
self->type = TYPE_READ_FROM_INTO;
|
|
|
|
self->handle = handle;
|
2022-03-13 22:28:45 +01:00
|
|
|
steal_buffer(&self->read_from_into.user_buffer, bufobj);
|
2022-03-13 17:42:29 +01:00
|
|
|
memset(&self->read_from_into.address, 0, sizeof(self->read_from_into.address));
|
|
|
|
self->read_from_into.address_length = sizeof(self->read_from_into.address);
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
|
|
|
|
(SOCKADDR*)&self->read_from_into.address,
|
|
|
|
&self->read_from_into.address_length,
|
|
|
|
&self->overlapped, NULL);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
|
|
|
|
switch (err) {
|
2019-05-28 11:52:15 +02:00
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
mark_as_completed(&self->overlapped);
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
case ERROR_MORE_DATA:
|
|
|
|
case ERROR_IO_PENDING:
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
default:
|
|
|
|
self->type = TYPE_NOT_STARTED;
|
|
|
|
return SetFromWindowsErr(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-13 17:42:29 +01:00
|
|
|
|
2020-07-10 19:43:37 +02:00
|
|
|
#include "clinic/overlapped.c.h"
|
2019-01-11 14:35:14 +01:00
|
|
|
|
2013-10-17 22:40:50 +02:00
|
|
|
static PyMethodDef Overlapped_methods[] = {
|
2020-07-10 19:43:37 +02:00
|
|
|
_OVERLAPPED_OVERLAPPED_GETRESULT_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_CANCEL_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_READFILE_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
|
2022-03-13 17:42:29 +01:00
|
|
|
_OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSARECVFROMINTO_METHODDEF
|
2020-07-10 19:43:37 +02:00
|
|
|
_OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_CONNECTEX_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_DISCONNECTEX_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_TRANSMITFILE_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_CONNECTNAMEDPIPE_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_WSASENDTO_METHODDEF
|
2013-10-17 22:40:50 +02:00
|
|
|
{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},
|
|
|
|
};
|
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
static PyType_Slot overlapped_type_slots[] = {
|
|
|
|
{Py_tp_dealloc, Overlapped_dealloc},
|
|
|
|
{Py_tp_doc, (char *)_overlapped_Overlapped__doc__},
|
|
|
|
{Py_tp_traverse, Overlapped_traverse},
|
|
|
|
{Py_tp_methods, Overlapped_methods},
|
|
|
|
{Py_tp_members, Overlapped_members},
|
|
|
|
{Py_tp_getset, Overlapped_getsets},
|
|
|
|
{Py_tp_new, _overlapped_Overlapped},
|
|
|
|
{0,0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static PyType_Spec overlapped_type_spec = {
|
|
|
|
.name = "_overlapped.Overlapped",
|
|
|
|
.basicsize = sizeof(OverlappedObject),
|
2021-06-17 12:06:09 +02:00
|
|
|
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
|
2020-09-07 15:12:40 +02:00
|
|
|
.slots = overlapped_type_slots
|
2013-10-17 22:40:50 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static PyMethodDef overlapped_functions[] = {
|
2020-07-10 19:43:37 +02:00
|
|
|
_OVERLAPPED_CREATEIOCOMPLETIONPORT_METHODDEF
|
|
|
|
_OVERLAPPED_GETQUEUEDCOMPLETIONSTATUS_METHODDEF
|
|
|
|
_OVERLAPPED_POSTQUEUEDCOMPLETIONSTATUS_METHODDEF
|
|
|
|
_OVERLAPPED_FORMATMESSAGE_METHODDEF
|
|
|
|
_OVERLAPPED_BINDLOCAL_METHODDEF
|
|
|
|
_OVERLAPPED_REGISTERWAITWITHQUEUE_METHODDEF
|
|
|
|
_OVERLAPPED_UNREGISTERWAIT_METHODDEF
|
|
|
|
_OVERLAPPED_UNREGISTERWAITEX_METHODDEF
|
|
|
|
_OVERLAPPED_CREATEEVENT_METHODDEF
|
|
|
|
_OVERLAPPED_SETEVENT_METHODDEF
|
|
|
|
_OVERLAPPED_RESETEVENT_METHODDEF
|
|
|
|
_OVERLAPPED_OVERLAPPED_CONNECTPIPE_METHODDEF
|
|
|
|
_OVERLAPPED_WSACONNECT_METHODDEF
|
2013-10-17 22:40:50 +02:00
|
|
|
{NULL}
|
|
|
|
};
|
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
#define WINAPI_CONSTANT(fmt, con) \
|
|
|
|
do { \
|
|
|
|
PyObject *value = Py_BuildValue(fmt, con); \
|
|
|
|
if (value == NULL) { \
|
|
|
|
return -1; \
|
|
|
|
} \
|
|
|
|
if (PyModule_AddObject(module, #con, value) < 0 ) { \
|
|
|
|
Py_DECREF(value); \
|
|
|
|
return -1; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static int
|
|
|
|
overlapped_exec(PyObject *module)
|
|
|
|
{
|
2013-10-17 22:40:50 +02:00
|
|
|
/* Ensure WSAStartup() called before initializing function pointers */
|
2020-09-07 15:12:40 +02:00
|
|
|
PyObject *socket_module = PyImport_ImportModule("_socket");
|
|
|
|
if (!socket_module) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
Py_DECREF(socket_module);
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
if (initialize_function_pointers() < 0) {
|
|
|
|
return -1;
|
bpo-40024: Update C extension modules to use PyModule_AddType() (GH-19119)
Update _asyncio, _bz2, _csv, _curses, _datetime,
_io, _operator, _pickle, _queue, blake2,
multibytecodec and overlapped C extension modules
to use PyModule_AddType().
2020-03-24 23:08:51 +01:00
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
|
2022-06-29 12:24:51 +02:00
|
|
|
PyTypeObject *overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(
|
2020-09-07 15:12:40 +02:00
|
|
|
module, &overlapped_type_spec, NULL);
|
2022-06-29 12:24:51 +02:00
|
|
|
if (overlapped_type == NULL) {
|
2020-09-07 15:12:40 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-06-29 12:24:51 +02:00
|
|
|
int rc = PyModule_AddType(module, overlapped_type);
|
|
|
|
Py_DECREF(overlapped_type);
|
|
|
|
if (rc < 0) {
|
2020-09-07 15:12:40 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2013-10-17 22:40:50 +02:00
|
|
|
|
|
|
|
WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
|
|
|
|
WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
|
2018-01-27 20:22:47 +01:00
|
|
|
WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
|
2013-10-17 22:40:50 +02:00
|
|
|
WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
|
2015-01-22 22:55:08 +01:00
|
|
|
WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
|
2013-10-17 22:40:50 +02:00
|
|
|
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);
|
|
|
|
|
2020-09-07 15:12:40 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyModuleDef_Slot overlapped_slots[] = {
|
|
|
|
{Py_mod_exec, overlapped_exec},
|
2023-05-05 23:11:27 +02:00
|
|
|
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
2020-09-07 15:12:40 +02:00
|
|
|
{0, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct PyModuleDef overlapped_module = {
|
2022-06-29 12:24:51 +02:00
|
|
|
.m_base = PyModuleDef_HEAD_INIT,
|
2020-09-07 15:12:40 +02:00
|
|
|
.m_name = "_overlapped",
|
|
|
|
.m_methods = overlapped_functions,
|
|
|
|
.m_slots = overlapped_slots,
|
|
|
|
};
|
|
|
|
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
PyInit__overlapped(void)
|
|
|
|
{
|
|
|
|
return PyModuleDef_Init(&overlapped_module);
|
2013-10-17 22:40:50 +02:00
|
|
|
}
|